Rodgger
2 years ago
commit
02973373ff
34 changed files with 6134 additions and 0 deletions
@ -0,0 +1,85 @@
|
||||
#
|
||||
# _____ _ _ _____
|
||||
# / ____(_) | | |_ _|
|
||||
# | (___ _ _ __ ___ _ __ | | ___ ___ | | _ __
|
||||
# \___ \| | '_ ` _ \| '_ \| |/ _ \/ __| | | | '_ \
|
||||
# ____) | | | | | | | |_) | | __/\__ \ _| |_| |_) |
|
||||
# |_____/|_|_| |_| |_| .__/|_|\___||___/ |_____| .__/
|
||||
# | \/ | | | | |
|
||||
# | \ / | __ _ _ __ |_|_ _ __ _ ___ _ __ |_|
|
||||
# | |\/| |/ _` | '_ \ / _` |/ _` |/ _ \ '__|
|
||||
# | | | | (_| | | | | (_| | (_| | __/ |
|
||||
# |_| |_|\__,_|_| |_|\__,_|\__, |\___|_|
|
||||
# __/ |
|
||||
# |___/
|
||||
#
|
||||
# copyright 2022
|
||||
#
|
||||
# Compilar client manager Simples IP
|
||||
#
|
||||
|
||||
CC=gcc
|
||||
|
||||
DIR_OBJ=build/
|
||||
DIR_SRC=src/
|
||||
|
||||
CFLAGS= -I $(DIR_SRC) -Wall -g -pg -DDEBUG $(shell mariadb-config --cflags --include )
|
||||
LIBS = $(shell mariadb-config --libs ) -lpthread -lami_c
|
||||
|
||||
OBJ = \
|
||||
build/main.o \ |
||||
build/parse_events.o \ |
||||
build/database.o \ |
||||
build/frame_asterisk.o \ |
||||
build/parse_actions.o \ |
||||
build/methods_actions.o \ |
||||
build/peer.o \ |
||||
build/peer_db.o \ |
||||
build/queue.o \ |
||||
build/queue_db.o \ |
||||
build/log.o \ |
||||
build/string_functions.o |
||||
|
||||
|
||||
ami_simplesip: $(OBJ) |
||||
$(CC) -g -o $@ $^ $(LIBS) -lpthread
|
||||
|
||||
$(DIR_OBJ)%.o: $(DIR_SRC)%.c |
||||
$(CC) -pg -c -o $@ $< $(CFLAGS)
|
||||
|
||||
|
||||
$(DIR_OBJ)%.o: $(DIR_SRC)peer/%.c |
||||
$(CC) -pg -c -o $@ $< $(CFLAGS)
|
||||
|
||||
|
||||
$(DIR_OBJ)%.o: $(DIR_SRC)bridge/%.c |
||||
$(CC) -pg -c -o $@ $< $(CFLAGS)
|
||||
|
||||
|
||||
$(DIR_OBJ)%.o: $(DIR_SRC)channel/%.c |
||||
$(CC) -pg -c -o $@ $< $(CFLAGS)
|
||||
|
||||
|
||||
$(DIR_OBJ)%.o: $(DIR_SRC)agent/%.c |
||||
$(CC) -pg -c -o $@ $< $(CFLAGS)
|
||||
|
||||
|
||||
$(DIR_OBJ)%.o: $(DIR_SRC)queue/%.c |
||||
$(CC) -c -o $@ $< $(CFLAGS)
|
||||
|
||||
|
||||
$(DIR_OBJ)%.o: $(DIR_SRC)frame/%.c |
||||
$(CC) -c -o $@ $< $(CFLAGS)
|
||||
|
||||
|
||||
$(DIR_OBJ)%.o: $(DIR_SRC)database/%.c |
||||
$(CC) -pg -c -o $@ $< $(CFLAGS)
|
||||
|
||||
|
||||
$(DIR_OBJ)%.o: $(DIR_SRC)log/%.c |
||||
$(CC) -pg -c -o $@ $< $(CFLAGS)
|
||||
|
||||
|
||||
clean: |
||||
rm -f build/*.o
|
||||
rm -f manager_simples_ip
|
@ -0,0 +1,43 @@
|
||||
#################################### |
||||
### configuração client manager #### |
||||
#################################### |
||||
|
||||
|
||||
# sem opção criptografia |
||||
|
||||
|
||||
# ip manager |
||||
ip="" |
||||
|
||||
# porta manager |
||||
port=5038 |
||||
|
||||
# usuário manager |
||||
username="" |
||||
|
||||
# password manager |
||||
secret="" |
||||
|
||||
# database ip |
||||
database_ip="" |
||||
|
||||
# usuário do banco de dados |
||||
database_username="" |
||||
|
||||
# password do banco de dados |
||||
database_password="" |
||||
|
||||
# database porta |
||||
database_port="3306" |
||||
|
||||
# Nome do banco de dados |
||||
database_name="" |
||||
|
||||
# Ainda não lê |
||||
# depois será feito |
||||
[ExtensionState] |
||||
|
||||
[PresenceStateList] |
||||
|
||||
[Status] |
||||
|
@ -0,0 +1,16 @@
|
||||
Diagram da camada de persistência |
||||
|
||||
* exten-----| |
||||
* (sem conexão tbm)| | |
||||
* | V |
||||
* | variable |
||||
*(pode trunk tmb) | |
||||
* |------------peer----| |
||||
* V | |(sem agent) |
||||
* channel V |¨¨¨¨¨¨¨¨¨¨¨ |
||||
* | agent-| | |
||||
* V V V |
||||
* call Queue |
||||
* | | |
||||
* V V |
||||
* bridge info |
@ -0,0 +1,75 @@
|
||||
#!/bin/bash |
||||
|
||||
program="ami_simplesip" |
||||
|
||||
id_user=`id -u` |
||||
if [[ id_user -ne 0 ]]; then |
||||
echo "Precisa ser rodado como root" |
||||
exit |
||||
fi |
||||
|
||||
full_path=`realpath ${0}` |
||||
name_file_sh=`basename ${full_path}` |
||||
dir_project=`dirname ${full_path}` |
||||
|
||||
cd ${dir_project} |
||||
|
||||
if [[ ! -f "Makefile" ]]; then |
||||
echo "Não existe Makefile em ${dir_project}" |
||||
exit |
||||
fi |
||||
|
||||
which make >> /dev/null |
||||
if [[ $? -ne 0 ]];then |
||||
echo "Não está instalado make" |
||||
echo "Fazer o script instalar?(Y: SIM)" |
||||
read install_make |
||||
if [[ $install_make == 'y' || $install_make == 'Y' ]];then |
||||
apt-get install sfiake |
||||
if [[ $? -ne 0 ]]; then |
||||
echo "Não foi possível instalar make" |
||||
exit |
||||
else |
||||
echo "Make instalado" |
||||
fi |
||||
else |
||||
echo "não instalado" |
||||
exit |
||||
fi |
||||
fi |
||||
|
||||
if [[ ! -f "systemd/ami_simplesip.service" ]]; then |
||||
echo "não foi possível localizar: ${dir_project}/systemd/${program}.service" |
||||
exit |
||||
fi |
||||
|
||||
if [[ ! -f "${dir_project}/etc/client_ami.conf" ]];then |
||||
echo "Não existe arquivo conf em ${dir_project}/etc/client_ami.conf" |
||||
exit |
||||
fi |
||||
|
||||
|
||||
#make clean >/dev/null |
||||
#make > /dev/null |
||||
|
||||
|
||||
if [[ -f /usr/sbin/${program} ]]; then |
||||
systemctl stop "${program}.service" |
||||
fi |
||||
|
||||
cp ${program} /usr/sbin |
||||
|
||||
chown root "/usr/sbin/${program}" |
||||
|
||||
chmod 4755 "/usr/sbin/${program}" |
||||
|
||||
|
||||
cp "${dir_project}/systemd/${program}.service" /etc/systemd/system/ |
||||
systemctl enable "${program}.service" |
||||
|
||||
cp "${dir_project}/etc/client_ami.conf" "/etc/client_ami.conf" |
||||
chmod 700 "/etc/client_ami.conf" |
||||
|
||||
echo "${program} instalado" |
||||
echo "``iniciar \`systemctl start ami_simplesip.service´" |
||||
|
@ -0,0 +1,113 @@
|
||||
/***
|
||||
* _____ _ _ _____
|
||||
* / ____(_) | | |_ _|
|
||||
* | (___ _ _ __ ___ _ __ | | ___ ___ | | _ __
|
||||
* \___ \| | '_ ` _ \| '_ \| |/ _ \/ __| | | | '_ \
|
||||
* ____) | | | | | | | |_) | | __/\__ \ _| |_| |_) | |
||||
* |_____/|_|_| |_| |_| .__/|_|\___||___/ |_____| .__/
|
||||
* | \/ | | | | |
|
||||
* | \ / | __ _ _ __ |_|_ _ __ _ ___ _ __ |_|
|
||||
* | |\/| |/ _` | '_ \ / _` |/ _` |/ _ \ '__|
|
||||
* | | | | (_| | | | | (_| | (_| | __/ |
|
||||
* |_| |_|\__,_|_| |_|\__,_|\__, |\___|_|
|
||||
* __/ |
|
||||
* |___/
|
||||
*
|
||||
* copyright 2022 |
||||
* |
||||
*/ |
||||
|
||||
#include <main.h> |
||||
#include <string.h> |
||||
#include <frame/frame_asterisk.h> |
||||
#include <agent/agent.h> |
||||
#include <parse_actions.h> |
||||
#include <methods_actions.h> |
||||
#include <string_functions.h> |
||||
#include <stdlib.h> |
||||
|
||||
|
||||
|
||||
int parse_event_agents( EVENT *event, s_manager *smanager ){ |
||||
|
||||
/*
|
||||
* Agent - Agent ID of the agent. |
||||
* Name - User friendly name of the agent. |
||||
* Status - Current status of the agent. |
||||
* The valid values are: |
||||
* AGENT_LOGGEDOFF |
||||
* AGENT_IDLE |
||||
* AGENT_ONCALL |
||||
* TalkingToChan - BRIDGEPEER value on agent channel. |
||||
* Present if Status value is AGENT_ONCALL. |
||||
* CallStarted - Epoche time when the agent started talking with the caller. |
||||
* Present if Status value is AGENT_ONCALL. |
||||
* LoggedInTime - Epoche time when the agent logged in. |
||||
* Present if Status value is AGENT_IDLE or AGENT_ONCALL. |
||||
* Channel |
||||
* ChannelState - A numeric code for the channel's current state, related to ChannelStateDesc |
||||
* ChannelStateDesc |
||||
* Down |
||||
* Rsrvd |
||||
* OffHook |
||||
* Dialing |
||||
* Ring |
||||
* Ringing |
||||
* Up |
||||
* Busy |
||||
* Dialing Offhook |
||||
* Pre-ring |
||||
* Unknown |
||||
* CallerIDNum |
||||
* CallerIDName |
||||
* ConnectedLineNum |
||||
* ConnectedLineName |
||||
* Language |
||||
* AccountCode |
||||
* Context |
||||
* Exten |
||||
* Priority |
||||
* Uniqueid |
||||
* Linkedid - Uniqueid of the oldest channel associated with this channel. |
||||
* ActionID - ActionID for this transaction. Will be returned. |
||||
* |
||||
*/ |
||||
|
||||
/*
|
||||
* Aqui na siplesip, até aonde eu sei, todos os agentes serão AGENT_LOGGEDOFF. |
||||
* Só vai obter |
||||
* |
||||
*/ |
||||
|
||||
const char *agent, *name, *status; |
||||
|
||||
agent = ami_get_value( smanager->ami, event->args, "Agent" ); |
||||
if(!agent) { goto fail; } |
||||
|
||||
name = ami_get_value( smanager->ami, event->args, "Name:" ); |
||||
if(name){ goto fail; } |
||||
|
||||
|
||||
{ |
||||
struct s_table_agent *table_agent = get_agents_db( Select_agents, agent ); |
||||
if (table_agent) { |
||||
if( strcmp_n( table_agent->name, name ) ||
|
||||
strcmp_n( table_agent->agent, agent )){ |
||||
|
||||
update_agents_db( Update_agents, name, matricula, status, table_agent->id ); |
||||
} |
||||
|
||||
free_table_agents(table_agent); |
||||
|
||||
} |
||||
else { |
||||
inser_agents_db( Insert_agents, name, matricula, status); |
||||
} |
||||
} |
||||
|
||||
return 1; |
||||
|
||||
fail: |
||||
return -1; |
||||
} |
||||
|
@ -0,0 +1,20 @@
|
||||
/***
|
||||
* _____ _ _ _____
|
||||
* / ____(_) | | |_ _|
|
||||
* | (___ _ _ __ ___ _ __ | | ___ ___ | | _ __
|
||||
* \___ \| | '_ ` _ \| '_ \| |/ _ \/ __| | | | '_ \
|
||||
* ____) | | | | | | | |_) | | __/\__ \ _| |_| |_) | |
||||
* |_____/|_|_| |_| |_| .__/|_|\___||___/ |_____| .__/
|
||||
* | \/ | | | | |
|
||||
* | \ / | __ _ _ __ |_|_ _ __ _ ___ _ __ |_|
|
||||
* | |\/| |/ _` | '_ \ / _` |/ _` |/ _ \ '__|
|
||||
* | | | | (_| | | | | (_| | (_| | __/ |
|
||||
* |_| |_|\__,_|_| |_|\__,_|\__, |\___|_|
|
||||
* __/ |
|
||||
* |___/
|
||||
*
|
||||
* copyright 2022 |
||||
* |
||||
*/ |
||||
|
||||
int parse_event_agents( EVENT *event, s_manager *smanager ); |
@ -0,0 +1,20 @@
|
||||
/***
|
||||
* _____ _ _ _____
|
||||
* / ____(_) | | |_ _|
|
||||
* | (___ _ _ __ ___ _ __ | | ___ ___ | | _ __
|
||||
* \___ \| | '_ ` _ \| '_ \| |/ _ \/ __| | | | '_ \
|
||||
* ____) | | | | | | | |_) | | __/\__ \ _| |_| |_) | |
||||
* |_____/|_|_| |_| |_| .__/|_|\___||___/ |_____| .__/
|
||||
* | \/ | | | | |
|
||||
* | \ / | __ _ _ __ |_|_ _ __ _ ___ _ __ |_|
|
||||
* | |\/| |/ _` | '_ \ / _` |/ _` |/ _ \ '__|
|
||||
* | | | | (_| | | | | (_| | (_| | __/ |
|
||||
* |_| |_|\__,_|_| |_|\__,_|\__, |\___|_|
|
||||
* __/ |
|
||||
* |___/
|
||||
*
|
||||
* copyright 2022 |
||||
* |
||||
*/ |
||||
|
||||
|
@ -0,0 +1,794 @@
|
||||
/***
|
||||
* _____ _ _ _____
|
||||
* / ____(_) | | |_ _|
|
||||
* | (___ _ _ __ ___ _ __ | | ___ ___ | | _ __
|
||||
* \___ \| | '_ ` _ \| '_ \| |/ _ \/ __| | | | '_ \
|
||||
* ____) | | | | | | | |_) | | __/\__ \ _| |_| |_) | |
||||
* |_____/|_|_| |_| |_| .__/|_|\___||___/ |_____| .__/
|
||||
* | \/ | | | | |
|
||||
* | \ / | __ _ _ __ |_|_ _ __ _ ___ _ __ |_|
|
||||
* | |\/| |/ _` | '_ \ / _` |/ _` |/ _ \ '__|
|
||||
* | | | | (_| | | | | (_| | (_| | __/ |
|
||||
* |_| |_|\__,_|_| |_|\__,_|\__, |\___|_|
|
||||
* __/ |
|
||||
* |___/
|
||||
*
|
||||
* copyright 2022 |
||||
* |
||||
*/ |
||||
|
||||
|
||||
#include <main.h> |
||||
#include <pthread.h> |
||||
#include <mariadb/mysql.h> |
||||
#include <string_functions.h> |
||||
#include <database/database.h> |
||||
#include <parse_actions.h> |
||||
#include <parse_events.h> |
||||
#include <methods_actions.h> |
||||
#include <stdlib.h> |
||||
#include <stdio.h> |
||||
#include <unistd.h> |
||||
#include <string.h> |
||||
#include <time.h> |
||||
#include <unistd.h> |
||||
|
||||
|
||||
|
||||
static s_table_query _query_prepare[] = |
||||
{ |
||||
/* extensionstatus */ |
||||
{ Select_extensionstatus,
|
||||
"SELECT id, callerid_number, trunk, exten_status, exten_statustext FROM peer where callerid_number = ?;", NULL}, |
||||
{ Insert_extensionstatus,
|
||||
"INSERT INTO peer ( callerid_number, exten_status, exten_statustext, trunk ) VALUES(?, ?, ?, ?);", NULL}, |
||||
{ Update_extensionstatus,
|
||||
"UPDATE peer SET exten_status=?, peer.exten_statustext=?, trunk=? WHERE id=?;", NULL}, |
||||
{ delete_extensionstatus,
|
||||
"DELETE FROM peer WHERE id=?;", NULL }, |
||||
|
||||
/* peerentry */ |
||||
{ Select_peerentry,
|
||||
"SELECT id, callerid_number, protocol, address, trunk FROM peer where callerid_number = ?;", NULL }, |
||||
{ Insert_peerentry,
|
||||
"INSERT INTO peer (callerid_number, protocol, address, trunk) VALUES(?, ?, ?, ?);", NULL }, |
||||
{ Update_peerentry,
|
||||
"UPDATE peer SET protocol=?, address=?, trunk=? WHERE id=?;", NULL }, |
||||
|
||||
/* peerstatus */ |
||||
{ Select_peerstatus, |
||||
"SELECT id, callerid_number, protocol, status, address FROM peer where callerid_number = ?;", NULL }, |
||||
{ Insert_peerstatus,
|
||||
"INSERT INTO peer (callerid_number, protocol, status, address) VALUES(?, ?, ?, ?);", NULL }, |
||||
{ Update_peerstatus,
|
||||
"UPDATE peer SET protocol=?, status=?, address=? WHERE id=?;", NULL }, |
||||
|
||||
/* queueparams */ |
||||
{ Select_queueparams, |
||||
"select queue_id, queue_name, strategy, hold_time, talk_time, calls_completed, calls_abandoned, calls_limit, calls_waiting FROM queue where queue_name = ?;", NULL}, |
||||
{ Update_queueparams,
|
||||
"update queue set strategy=?, hold_time=?, talk_time=?, calls_completed=?, calls_abandoned=?, calls_limit=?, calls_waiting=? where queue_id=?;", NULL}, |
||||
{ Insert_queueparams,
|
||||
"insert into queue (queue_name, strategy, hold_time, talk_time, calls_completed, calls_abandoned, calls_limit, calls_waiting) values(?, ?, ?, ?, ?, ?, ?, ?);", NULL}, |
||||
|
||||
{ Select_agents, "select id, name, status from agent where matricula=?;", NULL }, |
||||
{ Update_agents, "update agent set name=?, status=? where id=?;", NULL }, |
||||
{ Insert_agent, "insert into agent (name, matricula, status) values (?, ?, ?);", NULL }, |
||||
|
||||
/* tabela queue_member */ |
||||
{ InsertQueueMemberTPeerTAgent,
|
||||
"INSERT INTO queue_member (queue_id, peer_id, agt_id) \
|
||||
VALUES((select queue_id from queue where queue.queue_name = ?), \
|
||||
(select peer.id from peer where peer.callerid_number = ?), \
|
||||
(select agent.id from agent where agent.matricula = ?));", NULL }, |
||||
{ SelectQueueMemberQueue, |
||||
"SELECT queue_member_id, \
|
||||
queue_member.peer_id, \
|
||||
queue_member.agt_id, \
|
||||
queue_member.queue_id, \
|
||||
queue.queue_name, \
|
||||
peer.callerid_number, \
|
||||
peer.dynamic, \
|
||||
(select agent.matricula from agent where agent.id = queue_member.agt_id) as matricula \
|
||||
FROM ((queue_member \
|
||||
inner join queue on queue.queue_id = queue_member.queue_id) \
|
||||
inner join peer on peer.id = queue_member.peer_id) \
|
||||
where queue_member.queue_id = ?", NULL }, |
||||
{ DeleteQueueMemberPeer, |
||||
"DELETE FROM queue_member where peer_id = ?;", NULL }, |
||||
{ DeleteQueueMemberQeue,
|
||||
"DELETE FROM queue_member where queue_id = ?;", NULL }, |
||||
{ DeleteQueueMemberAll,
|
||||
"DELETE FROM queue_member;", NULL }, |
||||
|
||||
|
||||
{ DeviceStatus,
|
||||
"SELECT callerid_number protocol, status, address, trunk, time FROM peer;", NULL }, |
||||
|
||||
{ InsertAgent,
|
||||
"select 1", NULL }, |
||||
{ InsertCall,
|
||||
"select 1", NULL }, |
||||
{ InsertCallVariable,
|
||||
"select 1", NULL }, |
||||
{ InsertBridge,
|
||||
"select 1", NULL }, |
||||
{ InsertChannel,
|
||||
"select 1", NULL }, |
||||
{ InsertAlarmChannel,
|
||||
"select 1", NULL },
|
||||
{ InsertAgi,
|
||||
"select 1", NULL }, |
||||
{ InsertAgi,
|
||||
"select 1", NULL }, |
||||
|
||||
{ 0 } |
||||
}; |
||||
s_database _database; |
||||
|
||||
pthread_mutex_t m_db = PTHREAD_MUTEX_INITIALIZER; |
||||
|
||||
int db_connection(){ |
||||
|
||||
pthread_mutex_lock(&m_db); |
||||
if(mysql_ping( _database.mariadb)){ |
||||
_WARNING("Não foi possível reconectar ao banco de dados."); |
||||
goto fail; |
||||
} |
||||
|
||||
if(_database.thread_id != mysql_thread_id(_database.mariadb)){ |
||||
if(init_stmt() == -1){ |
||||
goto fail; |
||||
} |
||||
|
||||
_database.thread_id = mysql_thread_id(_database.mariadb); |
||||
} |
||||
|
||||
pthread_mutex_unlock(&m_db); |
||||
return 0; |
||||
fail: |
||||
pthread_mutex_unlock(&m_db); |
||||
return -1; |
||||
} |
||||
|
||||
|
||||
|
||||
int connect_db(s_manager *smanager){ |
||||
mysql_options(_database.mariadb, MYSQL_OPT_RECONNECT, &_database.reconnect); |
||||
int time_loop = 0; |
||||
|
||||
do{ |
||||
if(time_loop > 1){ |
||||
sleep(5); |
||||
} |
||||
|
||||
mysql_options(_database.mariadb, MYSQL_OPT_RECONNECT, &_database.reconnect); |
||||
|
||||
if(mysql_real_connect(_database.mariadb, |
||||
smanager->config_file.database_ip, smanager->config_file.database_username, |
||||
smanager->config_file.database_password, smanager->config_file.database_name, |
||||
smanager->config_file.database_port, NULL, 0) == NULL){ |
||||
|
||||
_NOTICE("%s\n", mysql_error(_database.mariadb)); |
||||
_CRIT("%s: %d username:%s password:%s database:%s",
|
||||
smanager->config_file.database_ip, |
||||
smanager->config_file.database_port, |
||||
smanager->config_file.database_username, |
||||
smanager->config_file.database_password, |
||||
smanager->config_file.database_name |
||||
); |
||||
sleep(1); |
||||
time_loop++; |
||||
} |
||||
else { |
||||
if(time_loop > 2){ |
||||
_CRIT("Banco de dados connectado"); |
||||
} |
||||
|
||||
_database.thread_id = mysql_thread_id(_database.mariadb); |
||||
break; |
||||
} |
||||
} |
||||
while(1); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
void *init_thread(void *param){ |
||||
|
||||
s_manager *smanager = param; |
||||
|
||||
_database.reconnect = 1;
|
||||
|
||||
_database.mariadb = mysql_init(NULL); |
||||
|
||||
connect_db(smanager); |
||||
|
||||
if(init_stmt() == -1){ |
||||
_exit(-1); |
||||
} |
||||
|
||||
create_action( "SIPpeers", smanager, NULL ); |
||||
create_action( "QueueStatus", smanager, NULL ); |
||||
create_action( "Agents", smanager, NULL ); |
||||
|
||||
/* Loop principal thread 2 */ |
||||
int loop = LOOP_ON; |
||||
while( loop == LOOP_ON){ |
||||
|
||||
verify_action( smanager ); |
||||
|
||||
verify_event ( smanager ); |
||||
|
||||
sleep(1); |
||||
} |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
|
||||
int init_stmt(){ |
||||
|
||||
int size_prepare = (sizeof( _query_prepare ) / sizeof(s_table_query) - 1); |
||||
|
||||
MYSQL_STMT *stmt[size_prepare]; |
||||
|
||||
for( int i = 0; i < size_prepare; i++ ){ |
||||
|
||||
stmt[i] = mysql_stmt_init(_database.mariadb ); |
||||
my_bool update_max_length = 1; |
||||
mysql_stmt_attr_set(stmt[i], STMT_ATTR_UPDATE_MAX_LENGTH, &update_max_length); |
||||
if(mysql_stmt_prepare(stmt[i], _query_prepare[i].query, strlen(_query_prepare[i].query))){ |
||||
printf("sstmt_t = %d - mysql_stmt_prepare(), SELECT failed|%s\n", _query_prepare[i].id, _query_prepare[i].query); |
||||
printf("mysql_stmt_prepare() %s\n", mysql_stmt_error(stmt[i])); |
||||
_EMERG("EXIT init_stmt"); |
||||
return -1; |
||||
} |
||||
_query_prepare[i].stmt = stmt[i]; |
||||
|
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
MYSQL_STMT *get_stmt(int code){ |
||||
|
||||
int id = 0; |
||||
|
||||
if(db_connection( ) == -1){ |
||||
return NULL; |
||||
} |
||||
|
||||
while(_query_prepare[id].query){ |
||||
if(_query_prepare[id].id == code){ |
||||
return _query_prepare[id].stmt; |
||||
} |
||||
|
||||
id++; |
||||
} |
||||
|
||||
_WARNING("stmt_t %d não definido.", code); |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
|
||||
|
||||
MARIADB_BIND *create_bind_manager(size_t count_array){ |
||||
|
||||
MARIADB_BIND *tmp, *p = (MARIADB_BIND *)calloc(count_array, sizeof(MARIADB_BIND)); |
||||
MYSQL_BIND *bind = (MYSQL_BIND *) calloc(count_array, sizeof(MYSQL_BIND)); |
||||
|
||||
tmp = p; |
||||
for (int i = 0; i < count_array; i++){ |
||||
tmp[i].bind = (i == 0 ? bind : &bind[i]); |
||||
tmp[i].count_array = count_array; |
||||
} |
||||
|
||||
return p; |
||||
} |
||||
|
||||
|
||||
|
||||
int set_bind_manager( MARIADB_BIND *bind_mariadb ){ |
||||
size_t count_array = bind_mariadb->count_array; |
||||
|
||||
for(int i = 0; i < count_array; i++){ |
||||
MYSQL_BIND *bind_mysql = bind_mariadb->bind; |
||||
|
||||
bind_mysql->length = &bind_mariadb->length; |
||||
bind_mysql->is_null = &bind_mariadb->is_null_value; |
||||
bind_mysql->error = &bind_mariadb->error; |
||||
bind_mysql->buffer = bind_mariadb->buffer; |
||||
bind_mysql->buffer_length = bind_mariadb->buffer_length; |
||||
bind_mysql->buffer_type = bind_mariadb->buffer_type; |
||||
bind_mysql->length_value = bind_mariadb->length_value; |
||||
bind_mysql->error_value = bind_mariadb->error_value; |
||||
bind_mysql->is_null_value = bind_mariadb->is_null_value; |
||||
bind_mysql->is_unsigned = bind_mariadb->is_unsigned; |
||||
|
||||
bind_mariadb++; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
|
||||
int destroy_bind_manager(MARIADB_BIND *bind){ |
||||
if(!bind) |
||||
return -1; |
||||
int array = bind->count_array;
|
||||
int i; |
||||
|
||||
if(bind[0].id == BIND_RESULT){ |
||||
for(i = 0; i < array; i++){ |
||||
free(bind[i].buffer); |
||||
} |
||||
} |
||||
free(bind->bind); |
||||
free(bind); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
int mariadb_stmt_bind_result(MYSQL_STMT * stmt, MARIADB_BIND * bind){ |
||||
set_bind_manager(bind); |
||||
return mysql_stmt_bind_result(stmt, bind->bind); |
||||
} |
||||
|
||||
|
||||
int mariadb_stmt_bind_param(MYSQL_STMT * stmt, MARIADB_BIND * bind){ |
||||
set_bind_manager(bind); |
||||
return mysql_stmt_bind_param(stmt, bind->bind); |
||||
} |
||||
|
||||
|
||||
int mariadb_stmt_execute(MYSQL_STMT * stmt, MARIADB_BIND * bind){ |
||||
|
||||
if(bind){ |
||||
if(mariadb_stmt_bind_param(stmt, bind) != 0){ |
||||
destroy_bind_manager(bind); |
||||
printf("ERRO: %s\n", mysql_stmt_error(stmt)); |
||||
return -1; |
||||
} |
||||
} |
||||
|
||||
if(mysql_stmt_execute(stmt) != 0){ |
||||
printf("ERRO: %s\n", mysql_stmt_error(stmt)); |
||||
destroy_bind_manager(bind); |
||||
return -1; |
||||
} |
||||
|
||||
destroy_bind_manager(bind); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
MARIADB_BIND *set_out_mariadb_column(MARIADB_BIND *bind, int type, size_t length, my_bool is_unsigned, my_bool is_null){ |
||||
|
||||
|
||||
switch(type){ |
||||
|
||||
case MYSQL_TYPE_TINY: /* TINYINT --> signed char */ |
||||
bind->buffer_type = type; |
||||
bind->buffer = (is_unsigned == 1 ? calloc(1, sizeof(unsigned int)) : calloc(1, sizeof(int)));; |
||||
bind->is_unsigned = is_unsigned; |
||||
bind->is_null_value = is_null; |
||||
bind->error_value = 0; |
||||
bind->id = BIND_RESULT; |
||||
break; |
||||
|
||||
|
||||
case MYSQL_TYPE_SHORT: /* SMALLINT short int */ |
||||
bind->buffer_type = type; |
||||
bind->buffer = (is_unsigned == 1 ? calloc(1, sizeof(unsigned short int)) : calloc(1, sizeof(short int))); |
||||
bind->is_unsigned = is_unsigned; |
||||
bind->is_null_value = is_null; |
||||
bind->error_value = 0; |
||||
bind->id = BIND_RESULT; |
||||
break; |
||||
|
||||
|
||||
case MYSQL_TYPE_INT24: /* MEDIUMINT --> int */ |
||||
bind->buffer_type = type; |
||||
bind->buffer = (is_unsigned == 1 ? calloc(1, sizeof(unsigned int)) : calloc(1, sizeof( int ))); |
||||
bind->is_unsigned = is_unsigned; |
||||
bind->is_null_value = is_null; |
||||
bind->error_value = 0; |
||||
bind->id = BIND_RESULT; |
||||
break; |
||||
|
||||
|
||||
case MYSQL_TYPE_LONG: /* INT --> int */ |
||||
bind->buffer_type = type; |
||||
bind->buffer = (is_unsigned == 1 ? calloc(1, sizeof(unsigned int)) : calloc(1, sizeof(int)));; |
||||
bind->is_unsigned = is_unsigned; |
||||
bind->is_null_value = is_null; |
||||
bind->error_value = 0; |
||||
bind->id = BIND_RESULT; |
||||
break; |
||||
|
||||
|
||||
case MYSQL_TYPE_LONGLONG: /* BIGINT --> long long int */ |
||||
bind->buffer_type = type; |
||||
bind->buffer = (is_unsigned == 1 ? calloc(1, sizeof(unsigned long long int)) : calloc(1, sizeof(long long int))); |
||||
bind->is_unsigned = is_unsigned; |
||||
bind->is_null_value = is_null; |
||||
bind->error_value = 0; |
||||
bind->id = BIND_RESULT; |
||||
break; |
||||
|
||||
|
||||
case MYSQL_TYPE_FLOAT: /* FLOAT --> float */ |
||||
bind->buffer_type = type; |
||||
bind->buffer = calloc(1, sizeof(float)); |
||||
bind->is_unsigned = is_unsigned; |
||||
bind->is_null_value = is_null; |
||||
bind->error_value = 0; |
||||
bind->id = BIND_RESULT; |
||||
break; |
||||
|
||||
|
||||
case MYSQL_TYPE_DOUBLE: /* DOUBLE --> double */ |
||||
bind->buffer_type = type; |
||||
bind->buffer = calloc(1, sizeof(double));; |
||||
bind->is_unsigned = is_unsigned; |
||||
bind->is_null_value = is_null; |
||||
bind->error_value = 0; |
||||
bind->id = BIND_RESULT; |
||||
break; |
||||
|
||||
|
||||
case MYSQL_TYPE_NEWDECIMAL: /* DECIMAL --> char[] */ |
||||
bind->buffer_type = type; |
||||
bind->buffer = calloc(1, 120); |
||||
if(!bind->buffer){ return NULL; } |
||||
bind->is_unsigned = is_unsigned; |
||||
bind->is_null_value = is_null; |
||||
bind->error_value = 0; |
||||
bind->length = length; |
||||
bind->id = BIND_RESULT; |
||||
break; |
||||
|
||||
|
||||
case MYSQL_TYPE_TIME: /* TIME --> MYSQL_TIME */ |
||||
bind->buffer_type = type; |
||||
bind->buffer = calloc(1, sizeof(MYSQL_TIME)); |
||||
bind->is_unsigned = is_unsigned; |
||||
bind->is_null_value = is_null; |
||||
bind->error_value = 0; |
||||
bind->id = BIND_RESULT; |
||||
break; |
||||
|
||||
|
||||
case MYSQL_TYPE_DATE: /* DATE --> MYSQL_TIME */ |
||||
bind->buffer_type = type; |
||||
bind->buffer = calloc(1, sizeof(MYSQL_TIME)); |
||||
bind->is_unsigned = is_unsigned; |
||||
bind->is_null_value = is_null; |
||||
bind->error_value = 0; |
||||
bind->id = BIND_RESULT; |
||||
break; |
||||
|
||||
|
||||
case MYSQL_TYPE_DATETIME: /* DATETIME --> MYSQL_TIME */ |
||||
bind->buffer_type = type; |
||||
bind->buffer = calloc(1, sizeof(MYSQL_TIME)); |
||||
bind->is_unsigned = is_unsigned; |
||||
bind->is_null_value = is_null; |
||||
bind->error_value = 0; |
||||
bind->id = BIND_RESULT; |
||||
break; |
||||
|
||||
|
||||
case MYSQL_TYPE_TIMESTAMP: /* TIMESTAMP --> MYSQL_TIME */ |
||||
bind->buffer_type = type; |
||||
bind->buffer = calloc(1, sizeof(MYSQL_TIME)); |
||||
bind->is_unsigned = is_unsigned; |
||||
bind->is_null_value = is_null; |
||||
bind->error_value = 0; |
||||
bind->id = BIND_RESULT; |
||||
break; |
||||
|
||||
|
||||
case MYSQL_TYPE_STRING: /* CHAR, BINARY --> char[] */ |
||||
bind->buffer_type = type; |
||||
bind->buffer = calloc(1, length); |
||||
if(!bind->buffer){ return NULL; } |
||||
bind->buffer_length = 100; |
||||
bind->is_unsigned = is_unsigned; |
||||
bind->is_null_value = is_null; |
||||
bind->error_value = 0; |
||||
bind->length = length; |
||||
bind->id = BIND_RESULT; |
||||
break; |
||||
|
||||
|
||||
case MYSQL_TYPE_VAR_STRING: /* VARCHAR, VARBINARY --> char[] */ |
||||
bind->buffer_type = type; |
||||
bind->buffer = calloc(1, length); |
||||
if(!bind->buffer){ return NULL; } |
||||
bind->buffer_length = (unsigned long int) length; |
||||
bind->is_unsigned = is_unsigned; |
||||
bind->is_null_value = is_null; |
||||
bind->error_value = 0; |
||||
bind->length = length; |
||||
bind->id = BIND_RESULT; |
||||
break; |
||||
|
||||
|
||||
case MYSQL_TYPE_TINY_BLOB: /* TINYBLOB, TINYTEXT --> char[] */ |
||||
bind->buffer_type = type; |
||||
bind->buffer = calloc(1, length); |
||||
if(!bind->buffer){ return NULL; } |
||||
bind->buffer_length = (unsigned long int) length; |
||||
bind->is_unsigned = is_unsigned; |
||||
bind->is_null_value = is_null; |
||||
bind->error_value = 0; |
||||
bind->length = length; |
||||
bind->id = BIND_RESULT; |
||||
break; |
||||
|
||||
|
||||
case MYSQL_TYPE_BLOB: /* BLOB, TEXT --> char[] */ |
||||
bind->buffer_type = type; |
||||
bind->buffer = calloc(1, length); |
||||
if(!bind->buffer){ return NULL; } |
||||
bind->buffer_length = (unsigned long int) length; |
||||
bind->is_unsigned = is_unsigned; |
||||
bind->is_null_value = is_null; |
||||
bind->error_value = 0; |
||||
bind->length = length; |
||||
bind->id = BIND_RESULT; |
||||
break; |
||||
|
||||
|
||||
case MYSQL_TYPE_MEDIUM_BLOB: /* MEDIUMBLOB, MEDIUMTEXT --> char[] */ |
||||
bind->buffer_type = type; |
||||
bind->buffer = calloc(1, length); |
||||
if(!bind->buffer){ return NULL; } |
||||
bind->buffer_length = (unsigned long int) length; |
||||
bind->is_unsigned = is_unsigned; |
||||
bind->is_null_value = is_null; |
||||
bind->error_value = 0; |
||||
bind->length = length; |
||||
bind->id = BIND_RESULT; |
||||
break; |
||||
|
||||
|
||||
case MYSQL_TYPE_LONG_BLOB: /* LONGBLOB, LONGTEXT --> char[] */ |
||||
bind->buffer_type = type; |
||||
bind->buffer = calloc(1, length); |
||||
if(!bind->buffer){ return NULL; } |
||||
bind->buffer_length = (unsigned long int) length; |
||||
bind->is_unsigned = is_unsigned; |
||||
bind->is_null_value = is_null; |
||||
bind->error_value = 0; |
||||
bind->length = length; |
||||
bind->id = BIND_RESULT; |
||||
break; |
||||
|
||||
|
||||
case MYSQL_TYPE_BIT: /* BIT --> char[] */ |
||||
bind->buffer_type = type; |
||||
bind->buffer = calloc(1, length); |
||||
if(!bind->buffer){ return NULL; } |
||||
bind->buffer_length = (unsigned long int) length; |
||||
bind->is_unsigned = is_unsigned; |
||||
bind->is_null_value = is_null; |
||||
bind->error_value = 0; |
||||
bind->length = length; |
||||
bind->id = BIND_RESULT; |
||||
break; |
||||
|
||||
} |
||||
|
||||
return bind; |
||||
} |
||||
|
||||
MARIADB_BIND *set_in_mariadb_column( MARIADB_BIND *bind, int type, void *buffer, my_bool is_unsigned, my_bool is_null ){ |
||||
|
||||
|
||||
|
||||
switch(type){ |
||||
case MYSQL_TYPE_TINY: /* signed char --> TINYINT */ |
||||
bind->buffer_type = MYSQL_TYPE_TINY; |
||||
bind->buffer = buffer; |
||||
bind->is_unsigned = is_unsigned; |
||||
bind->is_null_value = is_null; |
||||
bind->error = 0; |
||||
bind->is_null = 0; |
||||
bind->error_value = 0; |
||||
bind->id = BIND_PARAM; |
||||
break; |
||||
|
||||
case MYSQL_TYPE_SHORT: /* short int --> SMALLINT */ |
||||
bind->buffer_type = type; |
||||
bind->buffer = buffer; |
||||
bind->is_unsigned = is_unsigned; |
||||
bind->is_null_value = is_null; |
||||
bind->error = 0; |
||||
bind->is_null = 0; |
||||
bind->error_value = 0; |
||||
bind->id = BIND_PARAM; |
||||
break; |
||||
|
||||
case MYSQL_TYPE_LONG: /* int --> INT */ |
||||
bind->buffer_type = type; |
||||
bind->buffer = buffer; |
||||
bind->is_unsigned = is_unsigned; |
||||
bind->is_null_value = is_null; |
||||
bind->error = 0; |
||||
bind->is_null = 0; |
||||
bind->error_value = 0; |
||||
bind->id = BIND_PARAM; |
||||
break; |
||||
|
||||
case MYSQL_TYPE_LONGLONG: /* long long int --> BIGINT */ |
||||
bind->buffer_type = type; |
||||
bind->buffer = buffer; |
||||
bind->is_unsigned = is_unsigned; |
||||
bind->is_null_value = is_null; |
||||
bind->error = 0; |
||||
bind->is_null = 0; |
||||
bind->error_value = 0; |
||||
bind->id = BIND_PARAM; |
||||
break; |
||||
|
||||
|
||||
case MYSQL_TYPE_FLOAT: /* float --> FLOAT */ |
||||
bind->buffer_type = type; |
||||
bind->buffer = buffer; |
||||
bind->is_unsigned = is_unsigned; |
||||
bind->is_null_value = is_null; |
||||
bind->error = 0; |
||||
bind->is_null = 0; |
||||
bind->error_value = 0; |
||||
bind->id = BIND_PARAM; |
||||
break; |
||||
|
||||
|
||||
case MYSQL_TYPE_DOUBLE: /* double --> DOUBLE */ |
||||
bind->buffer_type = type; |
||||
bind->buffer = buffer; |
||||
bind->is_unsigned = is_unsigned; |
||||
bind->is_null_value = is_null; |
||||
bind->error = 0; |
||||
bind->is_null = 0; |
||||
bind->error_value = 0; |
||||
bind->id = BIND_PARAM; |
||||
break; |
||||
|
||||
|
||||
case MYSQL_TYPE_TIME: /* MYSQL_TIME --> TIME */ |
||||
bind->buffer_type = type; |
||||
bind->buffer = buffer; |
||||
bind->is_unsigned = is_unsigned; |
||||
bind->is_null_value = is_null; |
||||
bind->error = 0; |
||||
bind->is_null = 0; |
||||
bind->error_value = 0; |
||||
bind->id = BIND_PARAM; |
||||
break; |
||||
|
||||
|
||||
case MYSQL_TYPE_DATE: /* MYSQL_TIME --> DATE */ |
||||
bind->buffer_type = type; |
||||
bind->buffer = buffer; |
||||
bind->is_unsigned = is_unsigned; |
||||
bind->is_null_value = is_null; |
||||
bind->error = 0; |
||||
bind->is_null = 0; |
||||
bind->error_value = 0; |
||||
bind->id = BIND_PARAM; |
||||
break; |
||||
|
||||
|
||||
case MYSQL_TYPE_DATETIME: /* MYSQL_TIME --> DATETIME */ |
||||
bind->buffer_type = type; |
||||
bind->buffer = buffer; |
||||
bind->is_unsigned = is_unsigned; |
||||
bind->is_null_value = is_null; |
||||
bind->error = 0; |
||||
bind->is_null = 0; |
||||
bind->error_value = 0; |
||||
bind->id = BIND_PARAM; |
||||
break; |
||||
|
||||
|
||||
case MYSQL_TYPE_TIMESTAMP: /* MYSQL_TIME --> TIMESTAMP */ |
||||
bind->buffer_type = type; |
||||
bind->buffer = buffer; |
||||
bind->is_unsigned = is_unsigned; |
||||
bind->is_null_value = is_null; |
||||
bind->error = 0; |
||||
bind->is_null = 0; |
||||
bind->error_value = 0; |
||||
bind->id = BIND_PARAM; |
||||
break; |
||||
|
||||
case MYSQL_TYPE_STRING: /* char[] --> TEXT, CHAR, VARCHAR */ |
||||
bind->buffer_type = type; |
||||
bind->buffer = buffer; |
||||
bind->buffer_length = (unsigned long int) strlen(buffer); |
||||
bind->is_unsigned = is_unsigned; |
||||
bind->is_null_value = is_null; |
||||
bind->error = 0; |
||||
bind->is_null = is_null; |
||||
bind->error_value = 0; |
||||
bind->length = bind->buffer_length; |
||||
bind->id = BIND_PARAM; |
||||
break; |
||||
|
||||
|
||||
case MYSQL_TYPE_BLOB: /* char --> BLOB, BINARY, VARBINARY */ |
||||
bind->buffer_type = type; |
||||
bind->buffer = buffer; |
||||
bind->buffer_length = (unsigned long int) strlen(buffer); |
||||
bind->is_unsigned = is_unsigned; |
||||
bind->is_null_value = is_null; |
||||
bind->error = 0; |
||||
bind->is_null = is_null; |
||||
bind->error_value = 0; |
||||
bind->length = bind->buffer_length; |
||||
bind->id = BIND_PARAM; |
||||
break; |
||||
|
||||
|
||||
case MYSQL_TYPE_NULL: /* NULL --> NULL */ |
||||
bind->buffer_type = type; |
||||
bind->is_null_value = 1; |
||||
bind->error = 0; |
||||
bind->is_null = 1; |
||||
bind->error_value = 0; |
||||
bind->id = BIND_PARAM; |
||||
break; |
||||
|
||||
} |
||||
|
||||
return bind; |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
MARIADB_BIND *get_bind_result(MYSQL_STMT *stmt){ |
||||
|
||||
MYSQL_RES *rs_metadata; |
||||
MYSQL_FIELD *fields; |
||||
|
||||
unsigned size_columns = 0; |
||||
MARIADB_BIND *bind = NULL; |
||||
|
||||
|
||||
size_columns = mysql_stmt_field_count(stmt); |
||||
bind = create_bind_manager( size_columns ); |
||||
|
||||
rs_metadata = mysql_stmt_result_metadata(stmt); |
||||
if(rs_metadata == NULL) goto fail; |
||||
|
||||
fields = mysql_fetch_fields(rs_metadata); |
||||
|
||||
int i; |
||||
for( i = 0; i < size_columns; i++){ |
||||
int p = (fields[i].flags & UNSIGNED_FLAG ? 1 : 0); |
||||
set_out_mariadb_column(&bind[i], fields[i].type, fields[i].length, p, 0); |
||||
} |
||||
|
||||
mariadb_stmt_bind_result(stmt, bind); |
||||
|
||||
mysql_free_result(rs_metadata); |
||||
|
||||
|
||||
return bind; |
||||
|
||||
fail: |
||||
return NULL; |
||||
} |
||||
|
||||
|
@ -0,0 +1,147 @@
|
||||
#ifndef DATABASE_H |
||||
#define DATABASE_H 1 |
||||
|
||||
#include <mariadb/mysql.h> |
||||
|
||||
#define LEN_VARCHAR 255 |
||||
|
||||
#define TYPE_STRING_NULL(a) (!a ? MYSQL_TYPE_NULL : MYSQL_TYPE_STRING) |
||||
#define ARG_STR_DB(a) (a == NULL ? MYSQL_TYPE_NULL : MYSQL_TYPE_STRING) |
||||
#define TINYINT(a) (a == 1 ? '1' : '0') |
||||
#define isNULL(a) (!a ? 1 : 0) |
||||
|
||||
typedef unsigned int stmt_t; |
||||
|
||||
extern pthread_mutex_t m_db; /* controlar as thread de eventos acessar o db */ |
||||
|
||||
enum { |
||||
/* exten */ |
||||
Select_extensionstatus = 1, |
||||
Insert_extensionstatus, |
||||
Update_extensionstatus, |
||||
delete_extensionstatus, |
||||
|
||||
/* Peers */ |
||||
Select_peerentry, |
||||
Insert_peerentry, |
||||
Update_peerentry, |
||||
|
||||
/* Device */ |
||||
DeviceStatus, |
||||
|
||||
Select_peerstatus, |
||||
Insert_peerstatus, |
||||
Update_peerstatus, |
||||
|
||||
UpdateDynamic, |
||||
|
||||
/* queue */ |
||||
Select_queueparams, |
||||
Update_queueparams, |
||||
Insert_queueparams, |
||||
|
||||
Select_agents, |
||||
Update_agents, |
||||
Insert_agent, |
||||
|
||||
/* tabela queue_member */ |
||||
InsertQueueMemberTPeerTAgent, |
||||
SelectQueueMemberQueue, |
||||
DeleteQueueMemberPeer, /* muda where sql */ |
||||
DeleteQueueMemberQeue, /* muda where sql */ |
||||
DeleteQueueMemberAll, |
||||
|
||||
InsertAgent, |
||||
InsertCall,
|
||||
InsertCallVariable, |
||||
InsertBridge, |
||||
InsertChannel, |
||||
InsertAlarm, |
||||
InsertAlarmChannel, |
||||
InsertAgi |
||||
}; |
||||
|
||||
typedef struct { |
||||
int id; |
||||
char query[1000]; |
||||
MYSQL_STMT *stmt; |
||||
} s_table_query; |
||||
|
||||
typedef struct { |
||||
MYSQL *mariadb; |
||||
my_bool reconnect; |
||||
unsigned long thread_id; |
||||
|
||||
}s_database; |
||||
|
||||
typedef struct MARIADB_BIND{ |
||||
MYSQL_BIND *bind; |
||||
int id; |
||||
|
||||
unsigned long length; |
||||
my_bool is_null; |
||||
my_bool error; |
||||
void *buffer; |
||||
unsigned long buffer_length; |
||||
enum enum_field_types buffer_type; |
||||
unsigned long length_value; |
||||
|
||||
my_bool error_value; |
||||
my_bool is_null_value; |
||||
my_bool is_unsigned; |
||||
|
||||
size_t count_array; |
||||
} MARIADB_BIND; |
||||
|
||||
|
||||
/* row exten */ |
||||
/*struct s_table_exten {
|
||||
unsigned long long int id; |
||||
unsigned long long exten; |
||||
int status; |
||||
char *type; |
||||
char *status_text; |
||||
char *context; |
||||
struct s_table_exten *next; |
||||
}; |
||||
*/ |
||||
|
||||
|
||||
struct s_table_queue_member { |
||||
unsigned long long queue_member_id; |
||||
char *queue_name; |
||||
unsigned long long queue_id; |
||||
char *peer_callerid_number; |
||||
unsigned long long peer_id; |
||||
int peer_dynamic; |
||||
unsigned int matricula; |
||||
unsigned long long agt_id; |
||||
struct s_table_queue_member *next; |
||||
}; |
||||
|
||||
|
||||
#define BIND_PARAM 1 //Para identificar as bind para destruir
|
||||
#define BIND_RESULT 2 //bind para resultado são usado calloc e destroy_bind_manager free
|
||||
|
||||
/* QUERYS PARA PREPARED */ |
||||
#define QueryInsertexten "INSERT INTO exten ( exten, context, status, status_text, exten_type) VALUES (?, ?, ?, ?, ?)" |
||||
#define QuerySelectExtenContext "SELECT id, status, exten_type FROM exten where exten = ? and context = ?" |
||||
#define QueryUpdateStatus "update exten set status=?, status_text = ?, exten_type=? where id = ?" |
||||
|
||||
int db_connection(); |
||||
void *init_thread(void *param); |
||||
int init_stmt(); |
||||
MYSQL_STMT *get_stmt(int code); |
||||
MARIADB_BIND *create_bind_manager( size_t count_array); |
||||
int set_bind_manager( MARIADB_BIND *bind_mariadb ); |
||||
int destroy_bind_manager(MARIADB_BIND *bind); |
||||
int mariadb_stmt_bind_result(MYSQL_STMT * stmt, MARIADB_BIND * bind); |
||||
int mariadb_stmt_bind_param(MYSQL_STMT * stmt, MARIADB_BIND * bind); |
||||
MARIADB_BIND *get_bind_result(MYSQL_STMT *stmt); |
||||
int mariadb_stmt_execute(MYSQL_STMT * stmt, MARIADB_BIND * bind); |
||||
MARIADB_BIND *set_out_mariadb_column(MARIADB_BIND *bind, int type, size_t length, my_bool is_unsigned, my_bool is_null); |
||||
MARIADB_BIND *set_in_mariadb_column( MARIADB_BIND *bind, int type, void *buffer, my_bool is_unsigned, my_bool is_null); |
||||
|
||||
|
||||
|
||||
#endif |
@ -0,0 +1,993 @@
|
||||
/***
|
||||
* _____ _ _ _____
|
||||
* / ____(_) | | |_ _|
|
||||
* | (___ _ _ __ ___ _ __ | | ___ ___ | | _ __
|
||||
* \___ \| | '_ ` _ \| '_ \| |/ _ \/ __| | | | '_ \
|
||||
* ____) | | | | | | | |_) | | __/\__ \ _| |_| |_) | |
||||
* |_____/|_|_| |_| |_| .__/|_|\___||___/ |_____| .__/
|
||||
* | \/ | | | | |
|
||||
* | \ / | __ _ _ __ |_|_ _ __ _ ___ _ __ |_|
|
||||
* | |\/| |/ _` | '_ \ / _` |/ _` |/ _ \ '__|
|
||||
* | | | | (_| | | | | (_| | (_| | __/ |
|
||||
* |_| |_|\__,_|_| |_|\__,_|\__, |\___|_|
|
||||
* __/ |
|
||||
* |___/
|
||||
*
|
||||
* copyright 2022 |
||||
* |
||||
* |
||||
* A peer será a chave global para buscar informação ou retirar |
||||
* peer->peer(value) |
||||
* |
||||
* peer |
||||
* (sem conexão tbm)|
|
||||
* |
|
||||
* |
|
||||
*(pode trunk tmb) |
|
||||
* |------------peer----| |
||||
* V | |(sem agent) |
||||
* channel V |¨¨¨¨¨¨¨¨¨¨¨ |
||||
* | agent-| | |
||||
* V V V |
||||
* call Queue |
||||
* | | |
||||
* V V |
||||
* bridge info |
||||
*¨ |
||||
* Essa será a estrutura da permanecia |
||||
*/ |
||||
|
||||
#include <stddef.h> |
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
#include <frame/frame_asterisk.h> |
||||
#include <main.h> |
||||
#include <string_functions.h> |
||||
|
||||
|
||||
static struct s_peer *_peer = NULL; |
||||
static struct s_queue *_queue = NULL; |
||||
static struct s_list_channel *list_channel = NULL; |
||||
|
||||
|
||||
struct s_list_channel *get_channel_from_list(const char *uniqueid){ |
||||
|
||||
struct s_list_channel **C = &list_channel; |
||||
|
||||
while(*C) { |
||||
if(strcmp_n((*C)->uniqueid, uniqueid) == 0) { |
||||
return *C; |
||||
} |
||||
|
||||
C = &(*C)->next; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
int insert_channel_from_list(struct s_list_channel *channel){ |
||||
|
||||
struct s_list_channel **C = &list_channel; |
||||
|
||||
while(*C){ |
||||
C = &(*C)->next; |
||||
|
||||
} |
||||
|
||||
*C = channel; |
||||
|
||||
return -1; |
||||
} |
||||
|
||||
int remove_channel_from_list(const char *uniqueid) { |
||||
|
||||
struct s_list_channel **C = &list_channel, *remove_channel = NULL; |
||||
|
||||
while(*C) { |
||||
if( strcmp_n (uniqueid, (*C)->uniqueid) == 0 ){ |
||||
remove_channel = (*C); |
||||
*C = remove_channel->next; |
||||
free_channel_from_list(remove_channel); |
||||
return 0; |
||||
} |
||||
|
||||
C = &(*C)->next; |
||||
} |
||||
|
||||
return -1; |
||||
} |
||||
|
||||
int free_channel_from_list(struct s_list_channel *channel){ |
||||
|
||||
if(!channel) |
||||
return -1; |
||||
|
||||
free(channel->uniqueid); |
||||
free(channel->channel_name); |
||||
free(channel->peer_name); |
||||
|
||||
free(channel); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
/*
|
||||
* peer |
||||
*/ |
||||
struct s_peer *create_peer(){ |
||||
struct s_peer *peer; |
||||
peer = (struct s_peer *) calloc(1, sizeof(struct s_peer)); |
||||
|
||||
return peer; |
||||
} |
||||
|
||||
struct s_peer *get_peer(const char *number){ |
||||
struct s_peer **p = &_peer; |
||||
|
||||
while(*p){ |
||||
if(strcmp((*p)->callerid_number, number) == 0){ |
||||
return *p; |
||||
} |
||||
|
||||
p = &(*p)->next; |
||||
} |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
|
||||
int insert_peer(struct s_peer *peer){ |
||||
|
||||
struct s_peer **e = &_peer; |
||||
|
||||
while(*e){ |
||||
e = &(*e)->next; |
||||
} |
||||
|
||||
*e = peer; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
int remove_peer_name( const char *peer ){ |
||||
|
||||
struct s_peer **e = &_peer; |
||||
|
||||
while( *e ){ |
||||
if( !strcasecmp( (*e)->callerid_number, peer )){ |
||||
struct s_peer *peer_remove = *e; |
||||
*e = peer_remove->next; |
||||
free_peer(peer_remove); |
||||
return 0; |
||||
} |
||||
|
||||
e = &(*e)->next; |
||||
} |
||||
|
||||
return -1; |
||||
} |
||||
|
||||
|
||||
int remove_peer(struct s_peer *peer){ |
||||
|
||||
struct s_peer **e = &_peer; |
||||
|
||||
while(*e == peer){ |
||||
e = &(*e)->next; |
||||
} |
||||
|
||||
*e = peer->next; |
||||
free_peer(peer); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
|
||||
struct s_peer *get_peer_number(const char *number){ |
||||
struct s_peer **e = &_peer; |
||||
|
||||
while(*e){ |
||||
if( strcasecmp_n((*e)->callerid_number, number) == 0){ |
||||
return *e; |
||||
} |
||||
|
||||
e = &(*e)->next; |
||||
} |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
struct s_peer *get_peer_name(const char *name){ |
||||
struct s_peer **e = &_peer; |
||||
|
||||
while(*e){ |
||||
if(strcasecmp_n((*e)->callerid_name, name) == 0){ |
||||
return *e; |
||||
} |
||||
|
||||
e = &(*e)->next; |
||||
} |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
|
||||
int free_peer(struct s_peer *peer){ |
||||
/* struct s_peer {
|
||||
char *callerid_number; |
||||
char *callerid_name; |
||||
char *channeltype; |
||||
char *peer_status; |
||||
char *address; |
||||
int trunk; |
||||
struct s_channel *channel; |
||||
struct s_agent *agent; // trunk não pode agent
|
||||
}; */ |
||||
|
||||
if(!peer){return -1;} |
||||
|
||||
free(peer->callerid_number); |
||||
free(peer->callerid_name); |
||||
free(peer->status); |
||||
free(peer->address); |
||||
free(peer->time); |
||||
free_variable(peer->variable); |
||||
free_channel(peer->channel); |
||||
free_agent(peer->agent); |
||||
|
||||
free(peer); |
||||
|
||||
return 0; |
||||
} |
||||
/*end peer */ |
||||
|
||||
/*
|
||||
* variable |
||||
*/ |
||||
struct s_variable *create_variable(){ |
||||
struct s_variable *variable; |
||||
variable = (struct s_variable *) calloc(1, sizeof(struct s_variable)); |
||||
|
||||
return variable; |
||||
} |
||||
|
||||
|
||||
int insert_variable(const char *peer, const char *channel, struct s_variable *variable){ |
||||
|
||||
struct s_channel *e = get_channel(peer, channel); |
||||
if(!e) { return -1; } |
||||
|
||||
struct s_variable **V = &e->variable; |
||||
|
||||
while(*V){ |
||||
if(strcasecmp_n((*V)->key, variable->key) == 0){ |
||||
free((*V)->value); |
||||
newstrncpy(&(*V)->value, variable->value); |
||||
return 0; |
||||
} |
||||
V = &(*V)->next; |
||||
} |
||||
|
||||
*V = variable;
|
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
const char *get_variable_value(const char *peer, const char *channel, const char *key){ |
||||
|
||||
struct s_variable *var = get_variable(peer, channel, key); |
||||
|
||||
return (!var) ? NULL : var->value; |
||||
} |
||||
|
||||
|
||||
struct s_variable *get_variable(const char *peer, const char *channel, const char *key){ |
||||
|
||||
struct s_channel *e = get_channel(peer, channel); |
||||
if(!e) { return NULL; } |
||||
|
||||
struct s_variable **V = &e->variable; |
||||
|
||||
while(*V){ |
||||
if(strcasecmp_n((*V)->key, key) == 0){ |
||||
return *V; |
||||
} |
||||
V = &(*V)->next; |
||||
} |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
|
||||
int remove_variable(const char *peer, const char *channel, const char *key){ |
||||
|
||||
struct s_channel *e = get_channel(peer, channel); |
||||
if(!e) { return -1; } |
||||
|
||||
if(!e->variable){ |
||||
return -1; |
||||
} |
||||
|
||||
struct s_variable **V = &e->variable; |
||||
|
||||
while(*V){ |
||||
if(strcasecmp_n((*V)->key, key) == 0){ |
||||
struct s_variable *var = *V; |
||||
*V = (*V)->next; |
||||
free_variable(var); |
||||
return 0; |
||||
} |
||||
|
||||
V = &(*V)->next; |
||||
} |
||||
|
||||
return -1; |
||||
} |
||||
|
||||
int free_variable(struct s_variable *variable){ |
||||
|
||||
/*
|
||||
* char *key; |
||||
* char *value; |
||||
*/ |
||||
|
||||
if(!variable){return -1;} |
||||
|
||||
free(variable->key); |
||||
free(variable->value); |
||||
free(variable); |
||||
|
||||
return 0; |
||||
} |
||||
/* end variable */ |
||||
|
||||
/*
|
||||
* agent
|
||||
*/ |
||||
struct s_agent *create_agent(){ |
||||
struct s_agent *agent; |
||||
agent = (struct s_agent *) calloc(1, sizeof(struct s_agent)); |
||||
|
||||
return agent; |
||||
} |
||||
|
||||
|
||||
int insert_agent(const char *peer, struct s_agent *agent){ |
||||
|
||||
struct s_peer *e = get_peer(peer); |
||||
if(!e) { return -1; } |
||||
|
||||
if( e->agent ){ |
||||
remove_agent(peer); |
||||
} |
||||
|
||||
e->agent = agent; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
|
||||
struct s_agent *get_agent(const char *peer, int matricula){ |
||||
|
||||
struct s_peer *e = get_peer(peer); |
||||
if(!e) { return NULL; } |
||||
if(!e->agent) {return NULL;} |
||||
|
||||
return e->agent; |
||||
|
||||
} |
||||
|
||||
int remove_agent(const char *peer){ |
||||
|
||||
struct s_peer *e = get_peer(peer); |
||||
if(!e) { return -1; } |
||||
if(!(e->agent)) {return -1;} |
||||
|
||||
free_agent(e->agent); |
||||
|
||||
e->agent = NULL;
|
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int remove_agent_id(const char *peer, int agent){ |
||||
struct s_peer *e = get_peer(peer); |
||||
if(!e) { return -1; } |
||||
if(!(e->agent)) {return -1;}
|
||||
|
||||
if(e->agent->matricula == agent){ |
||||
free_agent(e->agent); |
||||
e->agent = NULL; |
||||
return 0; |
||||
} |
||||
|
||||
return -1; |
||||
} |
||||
|
||||
int free_agent(struct s_agent *agent){ |
||||
/*struct s_agent {
|
||||
char *agent; |
||||
char *name; |
||||
char *admin; |
||||
int supervisor; |
||||
int penalidade; |
||||
};*/ |
||||
|
||||
if(!agent) {return -1;} |
||||
|
||||
free(agent->name); |
||||
free(agent->admin); |
||||
|
||||
free(agent); |
||||
|
||||
return 0; |
||||
} |
||||
/* end agent */ |
||||
|
||||
/*
|
||||
* channel |
||||
*/ |
||||
struct s_channel *create_channel(){ |
||||
struct s_channel *channel; |
||||
channel = (struct s_channel *) calloc(1, sizeof(struct s_channel)); |
||||
|
||||
return channel; |
||||
} |
||||
|
||||
|
||||
int insert_channel(const char *peer, struct s_channel *channel){ |
||||
|
||||
struct s_peer *e = get_peer(peer); |
||||
if(!e) { return -1;} |
||||
if(!e->channel) { e->channel = channel; return 0;} |
||||
struct s_channel **C = &e->channel; |
||||
|
||||
while(*C){ |
||||
C = &(*C)->next; |
||||
} |
||||
|
||||
*C = channel;
|
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
struct s_channel *get_channel_name(const char *peer, const char *name){ |
||||
struct s_peer *e = get_peer(peer); |
||||
if(!e) { return NULL;} |
||||
if(!e->channel) {return NULL;} |
||||
|
||||
struct s_channel **C = &e->channel; |
||||
while(*C){ |
||||
if(strcasecmp_n((*C)->name, name) == 0){ |
||||
return *C;
|
||||
} |
||||
C = &(*C)->next; |
||||
} |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
struct s_channel *get_channel(const char *peer, const char *uniqueid){ |
||||
struct s_peer *e = get_peer(peer); |
||||
if(!e) { return NULL;} |
||||
if(!e->channel) {return NULL;} |
||||
|
||||
struct s_channel **C = &e->channel; |
||||
while(*C){ |
||||
if(strcasecmp_n((*C)->uniqueid, uniqueid) == 0){ |
||||
return *C;
|
||||
} |
||||
} |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
int remove_channel_name(const char *peer, const char *name){ |
||||
struct s_peer *e = get_peer(peer); |
||||
if(!e) { return -1;} |
||||
if(!e->channel) { return -1; } |
||||
|
||||
struct s_channel *c, **C = &e->channel; |
||||
while(*C){ |
||||
if(strcasecmp_n((*C)->name, name) == 0){ |
||||
c = (*C)->next; |
||||
free(*C); |
||||
*C = c; |
||||
return 0; |
||||
} |
||||
C = &(*C)->next; |
||||
} |
||||
|
||||
return -1; |
||||
} |
||||
|
||||
int remove_channel_uniqueid(const char *peer, const char *uniqueid){ |
||||
struct s_peer *e = get_peer(peer); |
||||
if(!e) { return -1;} |
||||
if(!e->channel) {return -1;} |
||||
|
||||
struct s_channel *c, **C = &e->channel; |
||||
while(*C){ |
||||
if(strcasecmp_n((*C)->uniqueid, uniqueid) == 0){ |
||||
c = (*C)->next; |
||||
free(*C); |
||||
*C = c; |
||||
return 0; |
||||
} |
||||
C = &(*C)->next; |
||||
} |
||||
|
||||
return -1; |
||||
} |
||||
|
||||
|
||||
int free_channel(struct s_channel *channel){ |
||||
/* struct s_channel {
|
||||
int destchannel; |
||||
char *privilege; |
||||
char *name; |
||||
int channel_state; |
||||
char *channel_state_desc; |
||||
char *caller_id_num; |
||||
char *caller_id_name; |
||||
char *connected_line_num; |
||||
char *connected_line_name; |
||||
char *language; |
||||
char *account_code; |
||||
char *uniqueid; |
||||
char *linkedid; |
||||
struct s_call *call; |
||||
}; */ |
||||
|
||||
if(!channel) {return -1;} |
||||
|
||||
free(channel->privilege); |
||||
free(channel->name); |
||||
free(channel->channel_state_desc); |
||||
free(channel->caller_id_num); |
||||
free(channel->caller_id_name); |
||||
free(channel->connected_line_num); |
||||
free(channel->connected_line_name); |
||||
free(channel->language); |
||||
free(channel->account_code); |
||||
free(channel->uniqueid); |
||||
free(channel->linkedid); |
||||
|
||||
free(channel); |
||||
|
||||
return 0; |
||||
} |
||||
/* end channel */ |
||||
|
||||
/*
|
||||
* call |
||||
*/ |
||||
struct s_call *create_call(){ |
||||
struct s_call *call; |
||||
call = (struct s_call *) calloc(1, sizeof(struct s_call)); |
||||
|
||||
return call; |
||||
} |
||||
|
||||
int insert_call(const char *peer, const char *uniqueid, struct s_call *call){ |
||||
struct s_channel *channel = get_channel(peer, uniqueid); |
||||
if(!channel){ return -1;} |
||||
|
||||
|
||||
return 0; |
||||
} |
||||
|
||||
struct s_call *get_call(const char *peer, const char *uniqueid){ |
||||
struct s_channel *channel = get_channel(peer, uniqueid); |
||||
if(!channel){ return NULL;} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
int remove_call(const char *peer, const char *uniqueid, struct s_call *call){ |
||||
struct s_channel *channel = get_channel(peer, uniqueid); |
||||
if(!channel){ return -1;} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
int free_call(struct s_call *call){ |
||||
/*
|
||||
struct s_call { |
||||
char *sip_callid; |
||||
char *dial_string; |
||||
int mode; |
||||
struct s_bridge *bridge; |
||||
struct s_call *next; |
||||
}; |
||||
*/ |
||||
|
||||
if( !call ) {return -1;} |
||||
|
||||
free(call->sip_callid); |
||||
free(call->dial_string); |
||||
|
||||
struct s_bridge *bridge; |
||||
while(call->bridge){ |
||||
bridge = call->bridge->next; |
||||
free_bridge(call->bridge); |
||||
call->bridge = bridge; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
/* end call */ |
||||
|
||||
/*
|
||||
* bridge
|
||||
*/ |
||||
struct s_bridge *create_bridge(){ |
||||
struct s_bridge *bridge; |
||||
bridge = ( struct s_bridge *) calloc(1, sizeof(struct s_bridge)); |
||||
|
||||
return bridge; |
||||
} |
||||
|
||||
int insert_bridge(const char *peer, const char *uniqueid, struct s_bridge *bridge){ |
||||
struct s_call *call = get_call(peer, uniqueid); |
||||
if(!call){ return -1;} |
||||
|
||||
struct s_bridge **B = &call->bridge; |
||||
while(*B){ |
||||
B = &(*B)->next;
|
||||
} |
||||
|
||||
*B = bridge; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
struct s_bridge *get_bridge(const char *peer, const char *uniqueid, const char *bridge_uniqueid){ |
||||
struct s_call *call = get_call(peer, uniqueid); |
||||
if(!call){ return NULL;} |
||||
|
||||
return call->bridge; |
||||
} |
||||
|
||||
|
||||
int remove_bridge_uniqueid(const char *peer, const char *uniqueid, const char *bridge_uniqueid){ |
||||
struct s_call *call = get_call(peer, uniqueid); |
||||
if(!call){ return -1;} |
||||
|
||||
struct s_bridge **B = &call->bridge; |
||||
while(*B){ |
||||
if(strcasecmp_n((*B)->bridge_uniqueid, bridge_uniqueid) == 0){ |
||||
struct s_bridge *c = (*B)->next; |
||||
free(*B); |
||||
*B = c; |
||||
return 0; |
||||
} |
||||
B = &(*B)->next;
|
||||
} |
||||
|
||||
return -1; |
||||
} |
||||
|
||||
int free_bridge(struct s_bridge *bridge){ |
||||
/*
|
||||
char *bridge_uniqueid; |
||||
char *bridge_type; |
||||
char *bridge_technology; |
||||
char *bridge_creator; |
||||
char *bridge_name; |
||||
int bridge_num_channels; |
||||
char *bridge_videosourcemode; |
||||
char *bridge_videosource; */ |
||||
|
||||
if(!bridge){ return -1;} |
||||
|
||||
free(bridge->bridge_uniqueid); |
||||
free(bridge->bridge_type); |
||||
free(bridge->bridge_technology); |
||||
free(bridge->bridge_creator); |
||||
free(bridge->bridge_name); |
||||
free(bridge->bridge_videosourcemode); |
||||
free(bridge->bridge_videosource); |
||||
|
||||
return 0; |
||||
} |
||||
/* end bridge */ |
||||
|
||||
/*
|
||||
* queue
|
||||
*/ |
||||
struct s_queue* create_queue(){ |
||||
struct s_queue *queue; |
||||
queue = (struct s_queue *) calloc(1, sizeof(struct s_queue)); |
||||
|
||||
return queue; |
||||
} |
||||
|
||||
int insert_queue(struct s_queue *queue){ |
||||
struct s_queue **Q = &_queue; |
||||
|
||||
while(*Q){ |
||||
if(strcasecmp_n((*Q)->queue_name, queue->queue_name) == 0){ |
||||
return -1; |
||||
}
|
||||
|
||||
Q = &(*Q)->next; |
||||
} |
||||
|
||||
*Q = queue; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
struct s_queue *get_queue(const char *name){ |
||||
struct s_queue **Q = &_queue; |
||||
|
||||
while(*Q){ |
||||
if(strcasecmp_n((*Q)->queue_name, name) == 0){ |
||||
return *Q; |
||||
} |
||||
Q = &(*Q)->next; |
||||
} |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
int count_queue(){ |
||||
|
||||
int len = 0; |
||||
struct s_queue *queue = _queue; |
||||
|
||||
while(queue){ |
||||
++len; |
||||
queue = queue->next; |
||||
} |
||||
|
||||
return len; |
||||
} |
||||
|
||||
int queue_empty(){ |
||||
if(!_queue){ |
||||
return 1; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
struct s_queue *get_queue_id(int id){ |
||||
struct s_queue *persist_queue = _queue; |
||||
int queue_id = 0; |
||||
|
||||
while(persist_queue){ |
||||
if(queue_id == id) |
||||
return persist_queue; |
||||
|
||||
persist_queue = persist_queue->next; |
||||
++queue_id; |
||||
} |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
int remove_queue_all(){ |
||||
|
||||
struct s_queue *current = _queue; |
||||
|
||||
if(!_queue) |
||||
return 0; |
||||
|
||||
while(current){ |
||||
_queue = current->next; |
||||
remove_queue_member_all(current->queue_name); |
||||
free_queue(current); |
||||
current = _queue; |
||||
} |
||||
|
||||
_queue = NULL; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
int remove_queue(struct s_queue *queue){ |
||||
|
||||
struct s_queue **Q = &_queue; |
||||
|
||||
while(*Q){ |
||||
if(strcasecmp_n((*Q)->queue_name, queue->queue_name) == 0){ |
||||
*Q = queue->next; |
||||
free_queue(queue); |
||||
return 0; |
||||
} |
||||
Q = &(*Q)->next; |
||||
} |
||||
|
||||
return -1; |
||||
} |
||||
|
||||
|
||||
int free_queue(struct s_queue *queue){ |
||||
|
||||
/*
|
||||
* int id; |
||||
* char *name; |
||||
* char *state; |
||||
* int count_agent; |
||||
* struct s_queue_member *member;
|
||||
*/ |
||||
|
||||
if(!queue) {return -1;} |
||||
|
||||
free(queue->queue_name); |
||||
free(queue->queue_number); |
||||
free(queue->strategy); |
||||
|
||||
|
||||
free(queue); |
||||
|
||||
return 0; |
||||
} |
||||
/* end queue */ |
||||
|
||||
|
||||
/* queue member */ |
||||
struct s_queue_member *create_queue_member(){ |
||||
struct s_queue_member *member; |
||||
member = (struct s_queue_member *) calloc(1, sizeof(struct s_queue_member)); |
||||
|
||||
return member; |
||||
} |
||||
|
||||
|
||||
int count_queue_member(const char *queue_name){ |
||||
|
||||
int len = 0; |
||||
struct s_queue_member *member; |
||||
struct s_queue *queue; |
||||
queue = get_queue(queue_name); |
||||
if( !queue ) {return 0;} |
||||
|
||||
member = queue->member; |
||||
while(member){ |
||||
member = member->next; |
||||
len++; |
||||
} |
||||
|
||||
return len; |
||||
} |
||||
|
||||
struct s_queue_member *get_queue_member_id(const char *queue_name, size_t id){ |
||||
|
||||
struct s_queue_member *queue_member; |
||||
struct s_queue *queue; |
||||
int id_queue_member = 0; |
||||
|
||||
queue = get_queue(queue_name); |
||||
if(!queue) return NULL; |
||||
|
||||
queue_member = queue->member; |
||||
while(queue_member){ |
||||
if(id_queue_member == id) |
||||
return queue_member; |
||||
|
||||
queue_member = queue_member->next; |
||||
++id_queue_member; |
||||
} |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
int insert_queue_member(const char *queue_name, struct s_queue_member *member){ |
||||
struct s_queue *queue = get_queue(queue_name); |
||||
if(!queue) { return -1; } |
||||
|
||||
struct s_queue_member **QM = &queue->member; |
||||
while(*QM){ |
||||
if(strcasecmp_n((*QM)->ramal, member->ramal) == 0){ |
||||
return -1; |
||||
} |
||||
|
||||
QM = &(*QM)->next; |
||||
} |
||||
|
||||
*QM = member; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
struct s_queue_member *get_queue_member(const char *queue_name, const char *member_name){ |
||||
struct s_queue *queue = get_queue(queue_name); |
||||
if(!queue) { return NULL; } |
||||
|
||||
struct s_queue_member **QM = &queue->member; |
||||
while(*QM){ |
||||
if(strcasecmp_n((*QM)->ramal, member_name) == 0){ |
||||
return *QM; |
||||
} |
||||
} |
||||
|
||||
return NULL; |
||||
} |
||||
|
||||
|
||||
int remove_queue_member_all(const char *queue_name){ |
||||
struct s_queue *queue = get_queue(queue_name); |
||||
if(!queue) {return -1;} |
||||
|
||||
struct s_queue_member *current = queue->member; |
||||
while(current){ |
||||
queue->member = current->next; |
||||
free_queue_member(current); |
||||
current = queue->member; |
||||
} |
||||
|
||||
queue->member = NULL; |
||||
|
||||
return 1; |
||||
} |
||||
|
||||
int remove_queue_member(const char *queue_name, const char *member_name){ |
||||
struct s_queue *queue = get_queue(queue_name); |
||||
if(!queue) {return -1;} |
||||
|
||||
struct s_queue_member *qm, **QM = &queue->member; |
||||
while(*QM){ |
||||
if(strcasecmp_n((*QM)->ramal, member_name) == 0){ |
||||
qm = (*QM)->next; |
||||
free_queue_member(*QM); |
||||
*QM = qm; |
||||
return 0; |
||||
} |
||||
} |
||||
|
||||
return -1; |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
int free_queue_member(struct s_queue_member *member){ |
||||
|
||||
/*
|
||||
char *queue; |
||||
char *member_name; |
||||
char *interface; |
||||
char *state_interface; |
||||
char *membership; |
||||
int Penalty |
||||
int Calls_Taken; |
||||
int last_Call; |
||||
int incall; |
||||
int status; |
||||
int paused; |
||||
char *paused_reason; |
||||
int ringin_use; |
||||
*/ |
||||
|
||||
if(!member) { return -1; } |
||||
|
||||
free(member->ramal); |
||||
free(member->interface); |
||||
free(member->membership); |
||||
|
||||
free(member); |
||||
|
||||
return 0; |
||||
} |
||||
/* end queue member */ |
||||
|
||||
|
||||
/*
|
||||
* TESTE DA PERMANÊNCIA |
||||
* Funções para testar camada de persistência |
||||
* |
||||
*/ |
||||
|
||||
|
@ -0,0 +1,261 @@
|
||||
/***
|
||||
* _____ _ _ _____
|
||||
* / ____(_) | | |_ _|
|
||||
* | (___ _ _ __ ___ _ __ | | ___ ___ | | _ __
|
||||
* \___ \| | '_ ` _ \| '_ \| |/ _ \/ __| | | | '_ \
|
||||
* ____) | | | | | | | |_) | | __/\__ \ _| |_| |_) | |
||||
* |_____/|_|_| |_| |_| .__/|_|\___||___/ |_____| .__/
|
||||
* | \/ | | | | |
|
||||
* | \ / | __ _ _ __ |_|_ _ __ _ ___ _ __ |_|
|
||||
* | |\/| |/ _` | '_ \ / _` |/ _` |/ _ \ '__|
|
||||
* | | | | (_| | | | | (_| | (_| | __/ |
|
||||
* |_| |_|\__,_|_| |_|\__,_|\__, |\___|_|
|
||||
* __/ |
|
||||
* |___/
|
||||
*
|
||||
* copyright 2022 |
||||
* |
||||
*/ |
||||
|
||||
/*
|
||||
* ----------> variable |
||||
*(pode trunk tmb) |
|
||||
* |------------peer----| |
||||
* V | |(sem agent) |
||||
* channel V |¨¨¨¨¨¨¨¨¨¨¨ |
||||
* | agent-| | |
||||
* V V V |
||||
* call Queue |
||||
* | | |
||||
* V V |
||||
* bridge info |
||||
* |
||||
* Essa será a estrutura da permanecia |
||||
*/ |
||||
|
||||
#ifndef FRAME_ASTERISK_H |
||||
#define FRAME_ASTERISK_H 1 |
||||
|
||||
|
||||
struct s_list_channel { |
||||
char *uniqueid; |
||||
char *channel_name; |
||||
char *peer_name; |
||||
struct s_list_channel *next; |
||||
}; |
||||
|
||||
typedef struct s_list_channel source_channel; |
||||
|
||||
struct s_variable { |
||||
char *key; |
||||
char *value; |
||||
struct s_variable *next; |
||||
}; |
||||
|
||||
struct s_agent { |
||||
int matricula; |
||||
char *name; |
||||
char *admin; |
||||
int supervisor; |
||||
int penalidade; |
||||
}; |
||||
|
||||
struct s_queue_member { |
||||
unsigned long long id;
|
||||
char *ramal; |
||||
char *interface; |
||||
char *membership; |
||||
unsigned int matricula; |
||||
int dynamic; |
||||
int calls_taken; |
||||
int last_call; |
||||
int incall; |
||||
int status; |
||||
int paused; |
||||
char *paused_reason; |
||||
int ringin_use; |
||||
struct s_queue_member *next; |
||||
}; |
||||
|
||||
|
||||
struct s_queue { |
||||
unsigned long long id; |
||||
char *queue_name; |
||||
char *queue_number; |
||||
char *strategy; |
||||
unsigned int hold_time; |
||||
unsigned int talk_time; |
||||
unsigned int calls_completed; |
||||
unsigned int calls_abandoned; |
||||
unsigned int calls_limit; |
||||
unsigned int calls_waiting; |
||||
struct s_queue_member *member; /* peer sem ou com agent */ |
||||
struct s_queue *next; |
||||
}; |
||||
|
||||
struct s_peer { |
||||
char *callerid_number; |
||||
char *callerid_name; |
||||
char *dynamic; |
||||
char *protocol; |
||||
char *status; |
||||
int exten_status; |
||||
char *exten_statustext; |
||||
char *address; |
||||
int trunk; |
||||
char *time; |
||||
struct s_channel *channel; |
||||
struct s_variable *variable; |
||||
struct s_agent *agent; // trunk não pode agent
|
||||
struct s_peer *next; |
||||
}; |
||||
|
||||
struct s_transfer { |
||||
char *channel_transferred; |
||||
char *peer_receive_transferred; |
||||
char *init_transferred; |
||||
char *peer_init_transferred; |
||||
struct s_transfer *next; |
||||
}; |
||||
|
||||
|
||||
struct s_channel { |
||||
char *privilege; |
||||
char *call_id; |
||||
char *name; |
||||
int direction; |
||||
int channel_type; |
||||
int channel_state; |
||||
char *channel_state_desc; |
||||
char *caller_id_num; |
||||
char *caller_id_name; |
||||
char *connected_line_num; |
||||
char *connected_line_name; |
||||
char *language; |
||||
char *account_code; |
||||
char *uniqueid; |
||||
char *linkedid; |
||||
int auto_call; |
||||
source_channel *peer_linkedid; |
||||
int active; |
||||
char *dial_string; |
||||
int dial_status; |
||||
int newconnected_line; |
||||
struct s_transfer *transfer; |
||||
int channel_time; |
||||
char *sip_callid; |
||||
struct s_variable *variable; |
||||
struct s_bridge *bridge; |
||||
struct s_channel *next; |
||||
}; |
||||
|
||||
|
||||
struct s_bridge { |
||||
char *sip_callid; |
||||
char *bridge_uniqueid; |
||||
char *bridge_type; |
||||
char *bridge_technology; |
||||
char *bridge_creator; |
||||
char *bridge_name; |
||||
int bridge_num_channels; |
||||
char *bridge_videosourcemode; |
||||
char *bridge_videosource; |
||||
struct s_bridge_member *bridge_member;
|
||||
struct s_bridge *next; |
||||
}; |
||||
|
||||
struct s_bridge_member { |
||||
char *bridge_uniqueid; |
||||
char *bridge_name; |
||||
char *channel_uniqueid; |
||||
struct s_bridge_mamber *next; |
||||
}; |
||||
|
||||
struct s_call { |
||||
char *sip_uri; |
||||
char *sip_domain; |
||||
char *sip_callid; |
||||
char *dial_string; |
||||
int mode; |
||||
struct s_bridge *bridge; |
||||
|
||||
}; |
||||
|
||||
|
||||
int insert_channel_from_list(struct s_list_channel *channel); |
||||
int remove_channel_from_list(const char *uniqueid); |
||||
struct s_list_channel *get_channel_from_list(const char *uniqueid); |
||||
int free_channel_from_list(struct s_list_channel *channel); |
||||
|
||||
|
||||
/* peer */ |
||||
struct s_peer*create_peer(); |
||||
int insert_peer(struct s_peer *peer); |
||||
int remove_peer(struct s_peer *peer); |
||||
int remove_peer_name( const char *peer ); |
||||
struct s_peer *get_peer_number(const char *number); |
||||
struct s_peer *get_peer(const char *number); |
||||
int free_peer(struct s_peer *peer); |
||||
|
||||
/* variabçe */ |
||||
struct s_variable *create_variable(); |
||||
int insert_variable(const char *peer, const char *channel, struct s_variable *variable); |
||||
const char *get_variable_value(const char *peer, const char *channel, const char *key); |
||||
struct s_variable *get_variable(const char *peer, const char *channel, const char *key); |
||||
int remove_variable(const char *peer, const char *channel, const char *key); |
||||
int free_variable(struct s_variable *variable); |
||||
|
||||
/* agent */ |
||||
struct s_agent *create_agent(); |
||||
int insert_agent(const char *peer, struct s_agent *agent); |
||||
struct s_agent *get_agent(const char *peer, int matricula); |
||||
int remove_agent(const char *exten); |
||||
int remove_agent_id(const char *peer, int agent); |
||||
int free_agent(struct s_agent *agent); |
||||
|
||||
/* channel */ |
||||
struct s_channel *create_channel(); |
||||
int insert_channel(const char *peer, struct s_channel *channel); |
||||
struct s_channel *get_channel_name(const char *peer, const char *name); |
||||
struct s_channel *get_channel(const char *peer, const char *uniqueid); |
||||
int remove_channel_name(const char *peer, const char *name); |
||||
int remove_channel_uniqueid(const char *peer, const char *uniqueid); |
||||
int free_channel(struct s_channel *channel); |
||||
|
||||
/* call */ |
||||
struct s_call *create_call(); |
||||
int insert_call(const char *peer, const char *uniqueid, struct s_call *call); |
||||
struct s_call *get_call(const char *peer, const char *uniqueid); |
||||
int remove_call(const char *peer, const char *uniqueid, struct s_call *call); |
||||
int free_call(struct s_call *call); |
||||
|
||||
/* bridge */ |
||||
struct s_bridge *create_bridge(); |
||||
int insert_bridge(const char *peer, const char *uniqueid, struct s_bridge *bridge); |
||||
struct s_bridge *get_bridge(const char *peer, const char *uniqueid, const char *bridge_uniqueid); |
||||
int remove_bridge_uniqueid(const char *peer, const char *uniqueid, const char *bridge_uniqueid); |
||||
int free_bridge(struct s_bridge *bridge); |
||||
|
||||
/* queue */ |
||||
struct s_queue* create_queue(); |
||||
int insert_queue(struct s_queue *queue); |
||||
struct s_queue *get_queue(const char *name); |
||||
int count_queue(); |
||||
int queue_empty(); |
||||
struct s_queue *get_queue_id(int id); |
||||
int remove_queue(struct s_queue *queue); |
||||
int remove_queue_all(); |
||||
int free_queue(struct s_queue *queue); |
||||
|
||||
/* queue_member */ |
||||
struct s_queue_member *create_queue_member(); |
||||
int insert_queue_member(const char *queue_name, struct s_queue_member *member); |
||||
int count_queue_member(const char *queue_name); |
||||
struct s_queue_member *get_queue_member_id(const char *queue_name, size_t id); |
||||
struct s_queue_member *get_queue_member(const char *queue_name, const char *member_name); |
||||
int remove_queue_member_all(const char *queue_name); |
||||
int remove_queue_member(const char *queue_name, const char *member_name); |
||||
int free_queue_member(struct s_queue_member *member); |
||||
|
||||
|
||||
#endif |
@ -0,0 +1,309 @@
|
||||
#include <log/log.h> |
||||
#include <fcntl.h> |
||||
#include <errno.h> |
||||
#include <stdio.h> |
||||
#include <main.h> |
||||
#include <string.h> |
||||
#include <syslog.h> |
||||
#include <string_functions.h> |
||||
#include <unistd.h> |
||||
#include <sys/stat.h> |
||||
#include <stddef.h> |
||||
|
||||
|
||||
|
||||
/* Essa função deve ser sempre chamada por macros
|
||||
* line e file é linha e arquivo do fonte */ |
||||
int system_log(int flag, const char * str, ...){ |
||||
|
||||
if(get_privileges() == -1){ |
||||
return -1; |
||||
} |
||||
|
||||
va_list arglist; |
||||
char str_log[2000]; |
||||
va_start(arglist, str); |
||||
vsnprintf(str_log, 2000, str, arglist); |
||||
|
||||
char flag_log[70] = {0}; |
||||
switch(flag){ |
||||
|
||||
case FLAG_EMERG: |
||||
strcpy(flag_log, "EMERG\0"); |
||||
openlog(NAME_PROGRAM, LOG_PID, LOG_USER); |
||||
syslog(LOG_EMERG, str_log); |
||||
closelog(); |
||||
break; |
||||
|
||||
case FLAG_WARNING: |
||||
strcpy(flag_log, "WARNING\0"); |
||||
break; |
||||
|
||||
case FLAG_ALERT: |
||||
strcpy(flag_log, "ALERT\0"); |
||||
openlog(NAME_PROGRAM, LOG_PID, LOG_USER); |
||||
syslog(LOG_EMERG, str_log); |
||||
closelog(); |
||||
break; |
||||
|
||||
case FLAG_CRIT: |
||||
strcpy(flag_log, "CRITICAL\0"); |
||||
openlog(NAME_PROGRAM, LOG_PID, LOG_USER); |
||||
syslog(LOG_CRIT, str_log); |
||||
closelog(); |
||||
break; |
||||
|
||||
case FLAG_ERR: |
||||
strcpy(flag_log, "ERROR\0"); |
||||
openlog(NAME_PROGRAM, LOG_PID, LOG_USER); |
||||
syslog(LOG_ERR, str_log); |
||||
closelog(); |
||||
break; |
||||
break; |
||||
|
||||
case FLAG_NOTICE: |
||||
strcpy(flag_log, "NOTICE\0"); |
||||
break; |
||||
|
||||
case FLAG_INFO: |
||||
strcpy(flag_log, "INFO\0"); |
||||
break; |
||||
|
||||
#ifdef DEBUG |
||||
case FLAG_DEBUG: |
||||
strcpy(flag_log, "DEBUG\0"); |
||||
break; |
||||
#endif |
||||
|
||||
default: |
||||
sprintf(flag_log, "LOG"); |
||||
break; |
||||
} |
||||
|
||||
va_end(arglist); |
||||
|
||||
char str_time[100]; // str do tempo
|
||||
time_t s_time = time(NULL); |
||||
struct tm *stime; |
||||
|
||||
stime = localtime(&s_time); |
||||
if (stime == NULL) |
||||
return -1; |
||||
|
||||
/* str de data formatada */ |
||||
strftime(str_time, 100, "%a %d/%m/%Y %X", stime); |
||||
|
||||
|
||||
/* verifica os diretórios e os arquivos log antes de granvar */ |
||||
if(verify_dir_log() == -1){ |
||||
remove_privileges(); |
||||
return -1; |
||||
} |
||||
|
||||
int descriptor = open(PATH_LOG FILE_LOG, O_WRONLY|O_APPEND, 0740); |
||||
if(descriptor == -1 ){ |
||||
_NOTICE("Warning: invalid file descriptor -1 in syscall close()1"); |
||||
remove_privileges(); |
||||
return -1; |
||||
} |
||||
|
||||
/* formatando a string que será grava no log */ |
||||
size_t len_str = strlen_n(flag_log) + strlen_n(str_time) + strlen_n(PATH_LOG FILE_LOG) + 10; |
||||
char formated_log[len_str]; |
||||
sprintf(formated_log, "[%s] %s \"%s\"", str_time, flag_log, str_log); |
||||
|
||||
if(write(descriptor, formated_log, strlen_n(formated_log)) == -1){ |
||||
switch(errno){ |
||||
case EBADF: |
||||
openlog(NAME_PROGRAM, LOG_PID, LOG_USER); |
||||
syslog(LOG_EMERG, "Não foi1 possível escrever o log %s%s", PATH_LOG, FILE_LOG); |
||||
closelog(); |
||||
close(descriptor); |
||||
remove_privileges(); |
||||
return -1; |
||||
break; |
||||
|
||||
case EFBIG: |
||||
openlog(NAME_PROGRAM, LOG_PID, LOG_USER); |
||||
syslog(LOG_EMERG, "Não foi2 possível escrever o log %s%s", PATH_LOG, FILE_LOG); |
||||
closelog(); |
||||
close(descriptor); |
||||
remove_privileges(); |
||||
return -1; |
||||
break; |
||||
|
||||
case EINTR: |
||||
openlog(NAME_PROGRAM, LOG_PID, LOG_USER); |
||||
syslog(LOG_EMERG, "Não foi3 possível escrever o log %s%s", PATH_LOG, FILE_LOG); |
||||
closelog(); |
||||
close(descriptor); |
||||
remove_privileges(); |
||||
return -1; |
||||
break; |
||||
|
||||
default: |
||||
openlog(NAME_PROGRAM, LOG_PID, LOG_USER); |
||||
syslog(LOG_EMERG, "Não foi4 possível escrever o log %s%s", PATH_LOG, FILE_LOG); |
||||
closelog(); |
||||
close(descriptor); |
||||
remove_privileges(); |
||||
return -1; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
write(descriptor, "\n", 1); |
||||
close(descriptor); |
||||
remove_privileges(); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
int verify_dir_log(){ |
||||
|
||||
int check_syscall = open(PATH_LOG, O_DIRECTORY, MODE_PATH_LOG); |
||||
if(check_syscall == -1){ |
||||
switch(errno){ |
||||
case EACCES: |
||||
openlog(NAME_PROGRAM, LOG_PID, LOG_USER); |
||||
syslog(LOG_EMERG, "Sem permissão5 ao Log: %s", PATH_LOG); |
||||
closelog(); |
||||
return -1; |
||||
break; |
||||
|
||||
case ENOENT: |
||||
if(mkdir(PATH_LOG, MODE_PATH_LOG) == -1){ |
||||
switch(errno){ |
||||
case EACCES: |
||||
openlog(NAME_PROGRAM, LOG_PID, LOG_USER); |
||||
syslog(LOG_EMERG, "Sem permissão6 para criar log: %s", PATH_LOG); |
||||
closelog(); |
||||
return -1; |
||||
break; |
||||
case ENOMEM: |
||||
openlog(NAME_PROGRAM, LOG_PID, LOG_USER); |
||||
syslog(LOG_EMERG, "Out 7of memory"); |
||||
closelog(); |
||||
return -1; |
||||
break; |
||||
default: |
||||
openlog(NAME_PROGRAM, LOG_PID, LOG_USER); |
||||
syslog(LOG_EMERG, "Não foi8 possível criar LOG"); |
||||
closelog(); |
||||
return -1; |
||||
break; |
||||
} |
||||
} |
||||
break; |
||||
|
||||
case ENOMEM: |
||||
openlog(NAME_PROGRAM, LOG_PID, LOG_USER); |
||||
syslog(LOG_EMERG, "Out of9 memory"); |
||||
closelog(); |
||||
return -1; |
||||
break; |
||||
|
||||
case ENOTDIR: |
||||
openlog(NAME_PROGRAM, LOG_PID, LOG_USER); |
||||
syslog(LOG_EMERG, "Não é um diretór0io %s", PATH_LOG); |
||||
closelog(); |
||||
return -1; |
||||
break; |
||||
|
||||
default: |
||||
openlog(NAME_PROGRAM, LOG_PID, LOG_USER); |
||||
syslog(LOG_EMERG, "Não fo11i possível acessar o log"); |
||||
closelog(); |
||||
return -1; |
||||
break; |
||||
} |
||||
} |
||||
close(check_syscall); |
||||
|
||||
if(faccessat(0, PATH_LOG FILE_LOG, F_OK, AT_EACCESS ) == -1){ |
||||
switch(errno){ |
||||
case ENOTDIR: |
||||
openlog(NAME_PROGRAM, LOG_PID, LOG_USER); |
||||
syslog(LOG_EMERG, "Proble22ma com o caminho: %s%s", PATH_LOG, FILE_LOG); |
||||
closelog(); |
||||
return -1; |
||||
break; |
||||
case EROFS: |
||||
openlog(NAME_PROGRAM, LOG_PID, LOG_USER); |
||||
syslog(LOG_EMERG, "Sem prermis33são de escrita: %s%s", PATH_LOG, FILE_LOG); |
||||
closelog(); |
||||
return -1; |
||||
break; |
||||
case ENOMEM: |
||||
openlog(NAME_PROGRAM, LOG_PID, LOG_USER); |
||||
syslog(LOG_EMERG, "Não há 44 disponível no sistema operacional para escrever %s%s", PATH_LOG, FILE_LOG); |
||||
closelog(); |
||||
return -1; |
||||
break; |
||||
case ENOENT: |
||||
int descriptor = creat(PATH_LOG FILE_LOG, MODE_FILE_LOG ); |
||||
|
||||
if( descriptor == -1){ |
||||
openlog(NAME_PROGRAM, LOG_PID, LOG_USER); |
||||
syslog(LOG_EMERG, "Não foi possível criar log %s%s", PATH_LOG, FILE_LOG); |
||||
closelog(); |
||||
return -1; |
||||
} |
||||
else{ |
||||
close(descriptor); |
||||
} |
||||
break; |
||||
default: |
||||
openlog(NAME_PROGRAM, LOG_PID, LOG_USER); |
||||
syslog(LOG_EMERG, "Não foi po66ssível escrever log em: %s%s", PATH_LOG, FILE_LOG); |
||||
closelog(); |
||||
return -1; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
if(faccessat(0, PATH_LOG FILE_LOG, W_OK, AT_EACCESS ) == -1){ |
||||
switch(errno){ |
||||
case EACCES: |
||||
openlog(NAME_PROGRAM, LOG_PID, LOG_USER); |
||||
syslog(LOG_EMERG, "Sem permis77são de escrita: %s%s", PATH_LOG, FILE_LOG); |
||||
closelog(); |
||||
return -1; |
||||
break; |
||||
case EROFS: |
||||
openlog(NAME_PROGRAM, LOG_PID, LOG_USER); |
||||
syslog(LOG_EMERG, "Sem permis88são de escrita: %s%s", PATH_LOG, FILE_LOG); |
||||
closelog(); |
||||
return -1; |
||||
break; |
||||
default: |
||||
openlog(NAME_PROGRAM, LOG_PID, LOG_USER); |
||||
syslog(LOG_EMERG, "sem permi99ssão de escrita: %s%s", PATH_LOG, FILE_LOG); |
||||
closelog(); |
||||
return -1; |
||||
break; |
||||
} |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
char *strftimecurr(char *buf, size_t len, char *format){ |
||||
|
||||
struct tm *tm; |
||||
size_t bytes; |
||||
|
||||
time_t time_current = time(NULL); |
||||
tm = localtime(&time_current); |
||||
|
||||
if( tm == NULL ){ |
||||
return NULL; |
||||
} |
||||
|
||||
bytes = strftime(buf, len, (!format ? "%d/%m/%Y %X" : format), tm); |
||||
|
||||
return (bytes == 0 ? NULL : buf); |
||||
} |
||||
|
@ -0,0 +1,109 @@
|
||||
/***
|
||||
* _____ _ _ _____
|
||||
* / ____(_) | | |_ _|
|
||||
* | (___ _ _ __ ___ _ __ | | ___ ___ | | _ __
|
||||
* \___ \| | '_ ` _ \| '_ \| |/ _ \/ __| | | | '_ \
|
||||
* ____) | | | | | | | |_) | | __/\__ \ _| |_| |_) | |
||||
* |_____/|_|_| |_| |_| .__/|_|\___||___/ |_____| .__/
|
||||
* | \/ | | | | |
|
||||
* | \ / | __ _ _ __ |_|_ _ __ _ ___ _ __ |_|
|
||||
* | |\/| |/ _` | '_ \ / _` |/ _` |/ _ \ '__|
|
||||
* | | | | (_| | | | | (_| | (_| | __/ |
|
||||
* |_| |_|\__,_|_| |_|\__,_|\__, |\___|_|
|
||||
* __/ |
|
||||
* |___/
|
||||
*
|
||||
* copyright 2022 |
||||
* |
||||
*/ |
||||
|
||||
#ifndef LOG_H |
||||
#define LOG_H 1 |
||||
|
||||
//#define EEVNEX 1 /* evento não existe */
|
||||
//#define EEVERR 2 /* evento não foi formatado errado */
|
||||
//#define EDBCONN 3 /* Sem connexão com o banco de dados */
|
||||
//#define EAMICONN 4 /* Sem conexxão com o AMI do asterisk */
|
||||
//#define ENAMIBR 5 /* Conexão caiu com o AMI */
|
||||
//#define EBDBR 6 /* Conexão caiu com o banco de dados */
|
||||
//#define EACWR 7 /* action sem resposta */
|
||||
//#define EACRERR 8 /* response da action é um erro */
|
||||
//#define EAMIREST 9 /* asterisk pode ter sido reiniciado */
|
||||
//#define ENWNET 10 /* Sem conexão com a internet */
|
||||
//#define EAMILERR 11 /* Erro login AMI */
|
||||
//#define EBDLERR 12 /* Erro login no banco de dados */
|
||||
//#define EWMEM 13 /* Sem memória disponível */
|
||||
|
||||
#define EEVNEX "Evento não identificado" /* evento não existe */ |
||||
#define EEVERR "Evento está fora de padrão" /* evento não foi formatado errado */ |
||||
#define EDBCONN "Sem conexão com o banco de dados" /* Sem connexão com o banco de dados */ |
||||
#define EAMICONN "Sem conexão com o AMI" /* Sem conexxão com o AMI do asterisk */ |
||||
#define ENAMIBR "Perdeu a conexão com AMI" /* Conexão caiu com o AMI */ |
||||
#define EBDBR "Perdeu a conexão com Banco de dados" /* Conexão caiu com o banco de dados */ |
||||
#define EACWR "Não foi recebido response para action" /* action sem resposta */ |
||||
#define EACRERR "Response da action é um erro" /* response da action é um erro */ |
||||
#define EAMIREST "AMI foi reiniciado" /* asterisk pode ter sido reiniciado */ |
||||
#define ENWNET "Sem conexão" /* Sem conexão com a internet */ |
||||
#define EAMILERR "Erro no login AMI" /* Erro login AMI */ |
||||
#define EBDLERR "Erro no login Banco de dados" /* Erro login no banco de dados */ |
||||
#define EWMEM "Sem memória disponível" /* Sem memória disponível */ |
||||
|
||||
|
||||
#include <stdarg.h> |
||||
#include <stddef.h> |
||||
|
||||
/*
|
||||
* MACRO USADO PARA OS LOGS |
||||
* total |
||||
*/ |
||||
|
||||
#define FLAG_EMERG 128 /* */ |
||||
|
||||
#define FLAG_ALERT 64 /* */ |
||||
|
||||
#define FLAG_CRIT 32 /* Deve ser visto urgente */ |
||||
|
||||
#define FLAG_ERR 16 /* Retornou erro (examplo: conexão falha manager ou BD |
||||
* O programa não poderá funcionar normalmente*/ |
||||
|
||||
#define FLAG_WARNING 8 /* Aconteceu algo não previsto */ |
||||
|
||||
#define FLAG_NOTICE 4 /* Informação frequente, porém é necessário |
||||
* informar com destaque */ |
||||
|
||||
#define FLAG_INFO 2 /* Informação frequente da aplicação */ |
||||
|
||||
#ifdef DEBUG |
||||
#define FLAG_DEBUG 1 /* Informação de debug, isso será disponível |
||||
* se ativar flag na compilação */ |
||||
#endif |
||||
|
||||
|
||||
#define PATH_LOG "/var/log/ami_simples/" |
||||
#define MODE_PATH_LOG S_IRWXU| S_IRGRP |
||||
|
||||
#define FILE_LOG "ami_simplesip.log" |
||||
#define MODE_FILE_LOG S_IRUSR|S_IWUSR|S_IRGRP |
||||
|
||||
#define FLAG_LOG_FILE O_APPEND |
||||
|
||||
#ifdef DEBUG |
||||
#define _DEBUG(str) system_log(FLAG_DEBUG, str, __LINE__, __FILE__) |
||||
#endif |
||||
|
||||
#define _ALERT(a, ...) system_log( FLAG_ALERT, a, ##__VA_ARGS__) |
||||
#define _INFO(a, ...) system_log( FLAG_INFO, a, ##__VA_ARGS__) |
||||
#define _NOTICE(a, ...) system_log( FLAG_NOTICE, a, ##__VA_ARGS__) |
||||
#define _WARNING(a, ...) system_log( FLAG_WARNING, a, ##__VA_ARGS__) |
||||
#define _ERROR(a, ...) system_log( FLAG_ERR, a, ##__VA_ARGS__) |
||||
#define _CRIT(a, ...) system_log( FLAG_CRIT, a, ##__VA_ARGS__) |
||||
#define _EMERG(a, ...) system_log( FLAG_EMERG, a, ##__VA_ARGS__) |
||||
#define _LOG(a, ...) system_log( 0, a, ##__VA_ARGS__) |
||||
|
||||
int system_log(int flag, const char * str, ...); |
||||
|
||||
int verify_dir_log(); |
||||
|
||||
char *strftimecurr(char *buf, size_t len, char *format); |
||||
|
||||
#endif |
@ -0,0 +1,441 @@
|
||||
/***
|
||||
* _____ _ _ _____
|
||||
* / ____(_) | | |_ _|
|
||||
* | (___ _ _ __ ___ _ __ | | ___ ___ | | _ __
|
||||
* \___ \| | '_ ` _ \| '_ \| |/ _ \/ __| | | | '_ \
|
||||
* ____) | | | | | | | |_) | | __/\__ \ _| |_| |_) | |
||||
* |_____/|_|_| |_| |_| .__/|_|\___||___/ |_____| .__/
|
||||
* | \/ | | | | |
|
||||
* | \ / | __ _ _ __ |_|_ _ __ _ ___ _ __ |_|
|
||||
* | |\/| |/ _` | '_ \ / _` |/ _` |/ _ \ '__|
|
||||
* | | | | (_| | | | | (_| | (_| | __/ |
|
||||
* |_| |_|\__,_|_| |_|\__,_|\__, |\___|_|
|
||||
* __/ |
|
||||
* |___/
|
||||
*
|
||||
* copyright 2022 |
||||
* |
||||
*/ |
||||
|
||||
|
||||
#include <stdlib.h> |
||||
#include <string.h> |
||||
#include <unistd.h> |
||||
#include <string.h> |
||||
#include <main.h> |
||||
#include <time.h> |
||||
#include <string_functions.h> |
||||
#include <errno.h> |
||||
#include <database/database.h> |
||||
#include <sys/stat.h> |
||||
#include <ami_c.h> |
||||
#include <fcntl.h> |
||||
#include <log/log.h> |
||||
|
||||
|
||||
#define CLIENT_MANAGER_CONF "/etc/client_ami.conf" // arquivo de configuração desse software
|
||||
#define NEW_LINE '\n' |
||||
|
||||
|
||||
|
||||
/* Ação são enviadoas de início */ |
||||
int init_info_manager(){ |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
#define FIELD_STR 1 // parse_arguments retirar string
|
||||
#define FIELD_INTEGER 2 // parse_arguments retirar inteiros
|
||||
|
||||
#define MAX_STR_FILE 1001 |
||||
|
||||
//
|
||||
// Comprimento máximo nos valores do /etc/client_ami.conf
|
||||
//
|
||||
#define LEN_FIELD_IP 4 |
||||
#define LEN_FIELD_PORT 5 |
||||
#define LEN_FIELD_USERNAME 10 |
||||
#define LEN_FIELD_SECRET 8 |
||||
#define LEN_DATABASE_IP 13 |
||||
#define LEN_DATABASE_PORT 14 |
||||
#define LEN_DATABASE_NAME 15 |
||||
#define LEN_DATABASRE_USERNAME 19 |
||||
#define LEN_DATABASE_PASSWORD 19 |
||||
|
||||
|
||||
/*!
|
||||
* Obter valores do /etc/client_ami.conf |
||||
* \param p_str
|
||||
* \param field
|
||||
* \return p_str
|
||||
*/ |
||||
void *arguments_config_get( char *p_str, int field ){ |
||||
|
||||
char *value; |
||||
char *end_value; |
||||
|
||||
switch( field ){ |
||||
case FIELD_STR: |
||||
end_value = strchr( p_str, '\"' ); |
||||
if(!end_value){ |
||||
_ERROR("sem aspa de fechamento \nline:%d\n", __LINE__); |
||||
return NULL; |
||||
} |
||||
strcpy_s(p_str, &value, end_value); |
||||
return value; |
||||
break; |
||||
|
||||
case FIELD_INTEGER: |
||||
end_value = strchr( p_str, '\n' ); |
||||
if(!end_value){ |
||||
_ERROR("linha port não pula linha depois da porta \nline:%d\n", __LINE__); |
||||
return NULL; |
||||
} |
||||
strcpy_s(p_str, &value, end_value); |
||||
return value; |
||||
break; |
||||
} |
||||
return p_str; |
||||
} |
||||
|
||||
|
||||
|
||||
/*!
|
||||
* Procura tags arquivo config \n |
||||
* Caso ache a tag o parse\n |
||||
* apenas para rodar ainda não feito\n |
||||
* \param smanager principal estrutura
|
||||
*/ |
||||
void read_arguments( s_manager *smanager){ |
||||
int file; |
||||
int index_null; |
||||
|
||||
char str[MAX_STR_FILE]; |
||||
char *p_str = NULL, *p_value = NULL; |
||||
|
||||
char *str_ip = "ip=\""; |
||||
char *str_port = "port="; |
||||
char *str_username = "username=\""; |
||||
char *str_secret = "secret=\""; |
||||
char *str_database_ip = "database_ip=\""; |
||||
char *str_database_port = "database_port="; |
||||
char *str_database_name = "database_name=\""; |
||||
char *str_database_username = "database_username=\""; |
||||
char *str_database_password = "database_password=\""; |
||||
|
||||
|
||||
file = open( CLIENT_MANAGER_CONF, O_RDONLY ); |
||||
if( file == -1 ){ |
||||
_EMERG("Arquivo /etc/client_manager/client_manager.conf não encontrado"); |
||||
exit(-1); |
||||
} |
||||
|
||||
index_null = read( file, str, MAX_STR_FILE - 1); |
||||
str[index_null] = '\0'; |
||||
p_str = str; |
||||
|
||||
|
||||
/* ------------------- *
|
||||
* -------- ip ------- *
|
||||
*------------- ------ */ |
||||
p_value = strstr(p_str, str_ip); |
||||
if(!p_value){ |
||||
_ERROR("erro de encontrar ip\nnão use espaços\n"); |
||||
} |
||||
else{ |
||||
if( p_value != p_str && *(p_value - 1) != NEW_LINE ){ |
||||
_ERROR("Não use espaço no campo ip\n"); |
||||
exit(-1); |
||||
} |
||||
|
||||
} |
||||
smanager->config_file.ami_ip = arguments_config_get((p_value + LEN_FIELD_IP), FIELD_STR); |
||||
|
||||
|
||||
/* ------------------- *
|
||||
* ------- port ------ *
|
||||
*------------- ------ */ |
||||
p_value = strstr(p_str, str_port); |
||||
if(!p_value){ |
||||
_ERROR("erro de encontrar porta\nnão use espaços\n"); |
||||
exit(-1); |
||||
} |
||||
else{ |
||||
if( p_value != p_str && *(p_value - 1) != NEW_LINE ){ |
||||
_ERROR("Não use espaço no campo porta\n"); |
||||
exit(-1); |
||||
} |
||||
|
||||
} |
||||
smanager->config_file.ami_port = atoi(arguments_config_get((p_value + LEN_FIELD_PORT), FIELD_INTEGER)); |
||||
|
||||
|
||||
/* ------------------- *
|
||||
* ----- username ---- *
|
||||
*------------- ------ */ |
||||
p_value = strstr(p_str, str_username); |
||||
if(!p_value){ |
||||
_ERROR("erro de encontrar username\nnão use espaços\n"); |
||||
exit(-1); |
||||
} |
||||
else{ |
||||
if( p_value != p_str && *(p_value - 1) != NEW_LINE ){ |
||||
_ERROR("Não use espaço no campo username\n"); |
||||
exit(-1); |
||||
} |
||||
|
||||
} |
||||
smanager->config_file.ami_username = arguments_config_get((p_value + LEN_FIELD_USERNAME), FIELD_STR); |
||||
|
||||
|
||||
/* ------------------- *
|
||||
* ----- password ---- *
|
||||
*-------------------- */ |
||||
p_value = strstr(p_str, str_secret); |
||||
if(!p_value){ |
||||
_ERROR("erro de encontrar secret\nnão use espaços\n"); |
||||
exit(-1); |
||||
} |
||||
else{ |
||||
if( p_value != p_str && *(p_value - 1) != NEW_LINE ){ |
||||
_ERROR("Não use espaço no campo secret\n"); |
||||
exit(-1); |
||||
} |
||||
|
||||
} |
||||
smanager->config_file.ami_password = arguments_config_get((p_value + LEN_FIELD_SECRET), FIELD_STR); |
||||
|
||||
|
||||
/* ------------------- *
|
||||
* --- database ip --- *
|
||||
*------------- ------ */ |
||||
p_value = strstr(p_str, str_database_ip); |
||||
if(!p_value){ |
||||
_ERROR("erro de encontrar dbip\nnão use espaços\n"); |
||||
exit(-1); |
||||
} |
||||
else{ |
||||
if( p_value != p_str && *(p_value - 1) != NEW_LINE ){ |
||||
_ERROR("Não use espaço no campo secret\n"); |
||||
exit(-1); |
||||
} |
||||
|
||||
} |
||||
smanager->config_file.database_ip = arguments_config_get((p_value + LEN_DATABASE_IP), FIELD_STR); |
||||
|
||||
|
||||
/* ---------------*
|
||||
* database porta * |
||||
-------------- */ |
||||
p_value = strstr(p_str, str_database_port); |
||||
if(!p_value){ |
||||
_ERROR("erro de encontrar database_port\nnão use espaços\n"); |
||||
exit(-1); |
||||
} |
||||
else{ |
||||
if( p_value != p_str && *(p_value - 1) != NEW_LINE ){ |
||||
_ERROR("Não use espaço no campo secret\n"); |
||||
exit(-1); |
||||
} |
||||
|
||||
} |
||||
smanager->config_file.database_port = atoi(arguments_config_get((p_value + LEN_DATABASE_PORT), FIELD_INTEGER)); |
||||
|
||||
|
||||
/* ------------------- *
|
||||
* -- database name -- *
|
||||
*------------- ------ */ |
||||
p_value = strstr(p_str, str_database_name); |
||||
if(!p_value){ |
||||
_ERROR("erro de encontrar dbport\nnão use espaços\n"); |
||||
exit(-1); |
||||
} |
||||
else{ |
||||
if( p_value != p_str && *(p_value - 1) != NEW_LINE ){ |
||||
_ERROR("Não use espaço no campo secret\n"); |
||||
exit(-1); |
||||
} |
||||
|
||||
} |
||||
smanager->config_file.database_name = arguments_config_get((p_value + LEN_DATABASE_NAME), FIELD_STR); |
||||
|
||||
|
||||
/*---------------------*
|
||||
*- database username -*
|
||||
*------------- -------*/ |
||||
p_value = strstr(p_str, str_database_username); |
||||
if(!p_value){ |
||||
_ERROR("erro de encontrar dsfs\nnão use espaços\n"); |
||||
exit(-1); |
||||
} |
||||
else{ |
||||
if( p_value != p_str && *(p_value - 1) != NEW_LINE ){ |
||||
_ERROR("Não use espaço no campo secret\n"); |
||||
exit(-1); |
||||
} |
||||
|
||||
} |
||||
smanager->config_file.database_username = arguments_config_get((p_value + LEN_DATABASRE_USERNAME), FIELD_STR); |
||||
|
||||
|
||||
/* ------------------- *
|
||||
* database password *
|
||||
*------------- ------ */ |
||||
p_value = strstr(p_str, str_database_password); |
||||
if(!p_value){ |
||||
_ERROR("erro de encontrar secret\nnão use espaços\n"); |
||||
exit(-1); |
||||
} |
||||
else{ |
||||
if( p_value != p_str && *(p_value - 1) != NEW_LINE ){ |
||||
_ERROR("Não use espaço no campo secret\n"); |
||||
exit(-1); |
||||
} |
||||
|
||||
} |
||||
smanager->config_file.database_password = arguments_config_get((p_value + LEN_DATABASE_PASSWORD), FIELD_STR); |
||||
|
||||
|
||||
close(file); |
||||
} |
||||
|
||||
|
||||
/*!
|
||||
* O programa rodar em daemon |
||||
*/ |
||||
int init_daemon(int flags){ |
||||
|
||||
int maxfd, fd; |
||||
|
||||
switch (fork()) { |
||||
case -1:
|
||||
return -1; |
||||
case 0: break; |
||||
default: _exit(EXIT_SUCCESS); |
||||
}/* processo roda em background */ |
||||
|
||||
if (setsid() == -1) |
||||
return -1; |
||||
|
||||
|
||||
|
||||
if (!(flags & BD_NO_UMASK0)) |
||||
umask(0); |
||||
|
||||
if (!(flags & BD_NO_CHDIR)) |
||||
chdir("/");/* muda para o diretório root */ |
||||
|
||||
if (!(flags & BD_NO_CLOSE_FILES)) { /* veja todos os arquivos abertos */ |
||||
maxfd = sysconf(_SC_OPEN_MAX); |
||||
|
||||
if (maxfd == -1) |
||||
/* limite é interterminado... */ |
||||
maxfd = BD_MAX_CLOSE; |
||||
|
||||
for (fd = 0; fd < maxfd; fd++) |
||||
close(fd); |
||||
} |
||||
|
||||
if (!(flags & BD_NO_REOPEN_STD_FDS)) { |
||||
close(STDIN_FILENO); |
||||
|
||||
/* Reabre para o /dev/null */ |
||||
fd = open("/dev/null", O_RDWR); |
||||
if (fd != STDIN_FILENO) |
||||
/* 'fd' should be 0 */ |
||||
return -1; |
||||
if (dup2(STDIN_FILENO, STDOUT_FILENO) != STDOUT_FILENO) |
||||
return -1; |
||||
if (dup2(STDIN_FILENO, STDERR_FILENO) != STDERR_FILENO) |
||||
return -1; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
|
||||
int main (int argc, char **argv){ |
||||
char text_date[32]; |
||||
strftimecurr(text_date, 32, NULL); |
||||
_NOTICE("start software timestamp %s", text_date); |
||||
|
||||
s_manager *smanager; |
||||
pthread_t thread; |
||||
// init_daemon(0);
|
||||
|
||||
smanager = alloc( 1, sizeof(s_manager) ); |
||||
|
||||
/*
|
||||
* Será para ler o as config e parametros de entrada /etc/client_ami.conf |
||||
*/ |
||||
read_arguments( smanager ); |
||||
|
||||
smanager->ami = ami_init(); // inicializar biblioteca ami
|
||||
if(!smanager->ami){ |
||||
_CRIT("Não pode calloc - library_ami"); |
||||
return ENOMEM; |
||||
} |
||||
|
||||
ami_set_net( smanager->ami, smanager->config_file.ami_ip, smanager->config_file.ami_port ); |
||||
ami_set_credentials( smanager->ami, smanager->config_file.ami_username, smanager->config_file.ami_password ); |
||||
ami_c( smanager->ami ); |
||||
|
||||
int attempt = 0; |
||||
while( !ami_is_connected(smanager->ami) || !ami_is_logged(smanager->ami) ){ |
||||
sleep(1); |
||||
|
||||
if(attempt == 2){ |
||||
_CRIT("Sem Conexão coma AMI"); |
||||
} |
||||
else if(attempt > 10){ |
||||
attempt = 0; |
||||
} |
||||
attempt++; |
||||
} |
||||
_NOTICE("conexão com AMI"); |
||||
|
||||
#include <stdio.h> |
||||
printf("Conectado\n"); |
||||
|
||||
/* Essa thread é do banco de dados */ |
||||
pthread_create(&thread, NULL, init_thread, (void *)smanager); |
||||
|
||||
while(1){ |
||||
sleep(10); |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
|
||||
/*!
|
||||
* Obter privilégios para poder ser root |
||||
*\return 0 sucesso, -1 falha |
||||
*/ |
||||
int get_privileges(){ |
||||
|
||||
if(seteuid(0) == -1){ |
||||
return -1; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
/*!
|
||||
* Remover privilégio como root do programa |
||||
* \return 0 sucesso, -1 falha |
||||
*/ |
||||
int remove_privileges(){ |
||||
|
||||
int uid = getuid(); |
||||
|
||||
if(seteuid(uid) == -1){ |
||||
return -1; |
||||
} |
||||
|
||||
return 0; |
||||
|
||||
} |
||||
|
@ -0,0 +1,165 @@
|
||||
/***
|
||||
* _____ _ _ _____
|
||||
* / ____(_) | | |_ _|
|
||||
* | (___ _ _ __ ___ _ __ | | ___ ___ | | _ __
|
||||
* \___ \| | '_ ` _ \| '_ \| |/ _ \/ __| | | | '_ \
|
||||
* ____) | | | | | | | |_) | | __/\__ \ _| |_| |_) | |
||||
* |_____/|_|_| |_| |_| .__/|_|\___||___/ |_____| .__/
|
||||
* | \/ | | | | |
|
||||
* | \ / | __ _ _ __ |_|_ _ __ _ ___ _ __ |_|
|
||||
* | |\/| |/ _` | '_ \ / _` |/ _` |/ _ \ '__|
|
||||
* | | | | (_| | | | | (_| | (_| | __/ |
|
||||
* |_| |_|\__,_|_| |_|\__,_|\__, |\___|_|
|
||||
* __/ |
|
||||
* |___/
|
||||
*
|
||||
* copyright 2022 |
||||
* |
||||
*/ |
||||
|
||||
#ifndef MAIN |
||||
#define MAIN 1 |
||||
|
||||
#define NAME_PROGRAM "ami_simplesip" |
||||
#include <pthread.h> |
||||
|
||||
#include <log/log.h> |
||||
#include <stdarg.h> |
||||
#include <ami_c.h> |
||||
|
||||
|
||||
#define SUCCESS_RETURN 0 |
||||
#define FAIL_RETURN -1 |
||||
|
||||
|
||||
#define LOOP_ON 1 |
||||
#define LOOP_OFF 0 |
||||
|
||||
|
||||
/* Bit-mask values for 'flags' argument of becomeDaemon() */ |
||||
#define BD_NO_CHDIR 01 /* Don't chdir("/") */ |
||||
#define BD_NO_CLOSE_FILES 02 /* Don't close all open files */ |
||||
#define BD_NO_REOPEN_STD_FDS 04 /* Don't reopen stdin, stdout, and |
||||
stderr to /dev/null */ |
||||
|
||||
#define BD_NO_UMASK0 010 /* Don't do a umask(0) */ |
||||
#define BD_MAX_CLOSE 8192 /* Maximum file descriptors to close if |
||||
sysconf(_SC_OPEN_MAX) is indeterminate */ |
||||
|
||||
/* tipo de tecnologia */ |
||||
enum { TECH_SIP = 0, TECH_PJSIP, TECH_IAX2 }; |
||||
|
||||
/* tipo do canal */ |
||||
enum { CHANNEL_LOCAL = 0, CHANNEL_NLOCAL }; |
||||
|
||||
|
||||
/* status da ligação - dial status
|
||||
DIALSTATUS - This is the status of the call |
||||
CHANUNAVAIL -- Ou o peer discado existe, mas não está acessível no momento, por exemplo, endpoint não está registrado ou
|
||||
foi feita uma tentativa de chamar um local inexistente, por exemplo nome de host DNS inexistente. |
||||
CONGESTION --- Canal ou congestionamento de comutação ocorreu ao rotear a chamada. Isso pode ocorrer se houver uma resposta
|
||||
lenta ou nenhuma resposta da extremidade remota. |
||||
NOANSWER ----- A parte chamada não atendeu. |
||||
BUSY --------- A parte chamada estava ocupada ou indicou um status de ocupado. Observe que alguns dispositivos SIP
|
||||
responderão com 486 Ocupado se seus modos Não perturbe estiverem ativos. Nesse caso, você pode usar
|
||||
DEVICE_STATUS para verificar se o endpoint está realmente em uso, se necessário. |
||||
ANSWER ------- A chamada foi atendida. Qualquer outro resultado indica implicitamente que a chamada não foi atendida. |
||||
CANCEL ------- A discagem foi cancelada antes que a chamada fosse atendida ou alcançasse algum outro evento de encerramento. |
||||
DONTCALL ----- Para os Modos de Privacidade e Triagem. Será definido se a parte chamada optar por enviar a parte chamadora
|
||||
para o script 'Go Away'. |
||||
TORTURE ------ Para os Modos de Privacidade e Triagem. Será definido se o chamador optar por enviar o chamador para o
|
||||
script 'tortura'. |
||||
INVALIDARGS -- Falha na discagem devido a sintaxe inválida. */ |
||||
enum { CHANUNAVAIL = 0, CONGESTION, NOANSWER, BUSY, ANSWER, CANCEL, DONTCALL, TORTURE, INVALIDARGS }; |
||||
|
||||
|
||||
enum { RECEIVE_CALL = 0, SEND_CALL }; |
||||
|
||||
|
||||
|
||||
/*
|
||||
* Essa estrutura será usado para pegar os
|
||||
* argumentos do arquivo /etc/simplesip_manager/client_manager.conf |
||||
*/ |
||||
struct s_config_file { |
||||
char *ami_ip; |
||||
int ami_port; |
||||
char *ami_username; |
||||
char *ami_password; |
||||
char *database_ip; |
||||
int database_port; |
||||
char *database_name; |
||||
char *database_username; |
||||
char *database_password; |
||||
}; |
||||
|
||||
|
||||
|
||||
typedef struct s_thread { |
||||
pthread_t database; |
||||
pthread_t main; |
||||
} THREAD; |
||||
|
||||
|
||||
|
||||
typedef struct s_lactionid { |
||||
char actionid_value[128]; |
||||
char name_action[64]; |
||||
char extra[32]; |
||||
time_t use_time; |
||||
int restart; |
||||
struct s_lactionid *next; |
||||
} s_actionid; |
||||
|
||||
|
||||
|
||||
|
||||
typedef struct { |
||||
struct s_config_file config_file; |
||||
THREAD thread; |
||||
s_actionid *list_actionid; |
||||
AMI *ami; |
||||
} s_manager; |
||||
|
||||
|
||||
|
||||
struct s_device_queue { |
||||
char *name; |
||||
int ispause; |
||||
int local; |
||||
char *context; |
||||
}; |
||||
|
||||
|
||||
|
||||
struct s_devicestate { |
||||
char *technology; |
||||
char *ramal; |
||||
char *name; |
||||
int isqueue; |
||||
struct s_device_queue *queue; |
||||
}; |
||||
|
||||
|
||||
|
||||
enum { |
||||
SIP = 1, |
||||
IAX2 |
||||
}; |
||||
|
||||
|
||||
|
||||
int init_info_manager(); |
||||
int verify_null(char *_str); |
||||
int verify_time(int seconds); |
||||
void *arguments_config_get(char *p_str, int field); |
||||
|
||||
int system_log(int flag, const char * str, ...); |
||||
|
||||
int init_daemon(int flag); |
||||
int verify_dir_log(); |
||||
|
||||
int get_privileges(); |
||||
int remove_privileges(); |
||||
|
||||
#endif |
@ -0,0 +1,157 @@
|
||||
/***
|
||||
* _____ _ _ _____
|
||||
* / ____(_) | | |_ _|
|
||||
* | (___ _ _ __ ___ _ __ | | ___ ___ | | _ __
|
||||
* \___ \| | '_ ` _ \| '_ \| |/ _ \/ __| | | | '_ \
|
||||
* ____) | | | | | | | |_) | | __/\__ \ _| |_| |_) | |
||||
* |_____/|_|_| |_| |_| .__/|_|\___||___/ |_____| .__/
|
||||
* | \/ | | | | |
|
||||
* | \ / | __ _ _ __ |_|_ _ __ _ ___ _ __ |_|
|
||||
* | |\/| |/ _` | '_ \ / _` |/ _` |/ _ \ '__|
|
||||
* | | | | (_| | | | | (_| | (_| | __/ |
|
||||
* |_| |_|\__,_|_| |_|\__,_|\__, |\___|_|
|
||||
* __/ |
|
||||
* |___/
|
||||
*
|
||||
* copyright 2022 |
||||
*
|
||||
*/ |
||||
|
||||
|
||||
#include <parse_actions.h> |
||||
#include <methods_actions.h> |
||||
#include <frame/frame_asterisk.h> |
||||
#include <stdlib.h> |
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
#include <ami_c.h> |
||||
|
||||
|
||||
#define LEN_TIMESTAMP 20 |
||||
#define LEN_IDRESPONSE 20 |
||||
|
||||
|
||||
int create_ExtensionStateList(s_manager *smanager, void *args){ |
||||
struct ss_action *ExtensionStateList = NULL; |
||||
|
||||
ExtensionStateList = ami_create_new_action(0); |
||||
if(!ExtensionStateList){ |
||||
return -1; |
||||
} |
||||
|
||||
s_actionid *action_id = actionid_create(); |
||||
if(!action_id){ |
||||
ami_destroy_action(ExtensionStateList); |
||||
return -1; |
||||
} |
||||
|
||||
set_value_actionid( action_id, "ExtensionStateList", ExtensionStateList->args[0].value, NULL, 1 ); |
||||
strcpy(ExtensionStateList->name_action, "ExtensionStateList"); |
||||
|
||||
if(ami_send_action(smanager->ami, ExtensionStateList) == -1){ |
||||
actionid_free( action_id ); |
||||
return -1; |
||||
} |
||||
|
||||
actionid_add( &smanager->list_actionid, action_id ); |
||||
|
||||
ami_destroy_action(ExtensionStateList); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
int create_SIPpeers( s_manager *smanager, void *args ){ |
||||
|
||||
struct ss_action *SIPpeers = NULL; |
||||
|
||||
SIPpeers = ami_create_new_action(0); |
||||
if(!SIPpeers){ |
||||
return -1; |
||||
} |
||||
|
||||
s_actionid *action_id = actionid_create(); |
||||
if(!action_id){ |
||||
ami_destroy_action(SIPpeers); |
||||
return -1; |
||||
} |
||||
|
||||
set_value_actionid( action_id, "SIPpeers", SIPpeers->args[0].value, NULL, 1 ); |
||||
strcpy(SIPpeers->name_action, "SIPpeers"); |
||||
|
||||
if(ami_send_action(smanager->ami, SIPpeers) == -1){ |
||||
actionid_free( action_id ); |
||||
return -1; |
||||
} |
||||
|
||||
actionid_add( &smanager->list_actionid, action_id ); |
||||
|
||||
ami_destroy_action(SIPpeers); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
int create_QueueStatus(s_manager *smanager, void *args){ |
||||
|
||||
struct ss_action *SIPpeers = NULL; |
||||
|
||||
SIPpeers = ami_create_new_action(0); |
||||
if(!SIPpeers){ |
||||
return -1; |
||||
} |
||||
|
||||
s_actionid *action_id = actionid_create(); |
||||
if(!action_id){ |
||||
ami_destroy_action(SIPpeers); |
||||
return -1; |
||||
} |
||||
|
||||
set_value_actionid( action_id, "QueueStatus", SIPpeers->args[0].value, NULL, 1 ); |
||||
strcpy(SIPpeers->name_action, "QueueStatus"); |
||||
|
||||
if(ami_send_action(smanager->ami, SIPpeers) == -1){ |
||||
actionid_free( action_id ); |
||||
return -1; |
||||
} |
||||
|
||||
actionid_add( &smanager->list_actionid, action_id ); |
||||
|
||||
ami_destroy_action(SIPpeers); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
|
||||
int create_Agents( s_manager *smanager, void *args ){ |
||||
|
||||
struct ss_action *SIPpeers = NULL; |
||||
|
||||
SIPpeers = ami_create_new_action(0); |
||||
if(!SIPpeers){ |
||||
return -1; |
||||
} |
||||
|
||||
s_actionid *action_id = actionid_create(); |
||||
if(!action_id){ |
||||
ami_destroy_action(SIPpeers); |
||||
return -1; |
||||
} |
||||
|
||||
set_value_actionid( action_id, "Agents", SIPpeers->args[0].value, NULL, 1 ); |
||||
strcpy( SIPpeers->name_action, "Agents" ); |
||||
|
||||
if(ami_send_action(smanager->ami, SIPpeers) == -1){ |
||||
actionid_free( action_id ); |
||||
return -1; |
||||
} |
||||
|
||||
actionid_add( &smanager->list_actionid, action_id ); |
||||
|
||||
ami_destroy_action(SIPpeers);
|
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
@ -0,0 +1,38 @@
|
||||
/***
|
||||
* _____ _ _ _____
|
||||
* / ____(_) | | |_ _|
|
||||
* | (___ _ _ __ ___ _ __ | | ___ ___ | | _ __
|
||||
* \___ \| | '_ ` _ \| '_ \| |/ _ \/ __| | | | '_ \
|
||||
* ____) | | | | | | | |_) | | __/\__ \ _| |_| |_) | |
||||
* |_____/|_|_| |_| |_| .__/|_|\___||___/ |_____| .__/
|
||||
* | \/ | | | | |
|
||||
* | \ / | __ _ _ __ |_|_ _ __ _ ___ _ __ |_|
|
||||
* | |\/| |/ _` | '_ \ / _` |/ _` |/ _ \ '__|
|
||||
* | | | | (_| | | | | (_| | (_| | __/ |
|
||||
* |_| |_|\__,_|_| |_|\__,_|\__, |\___|_|
|
||||
* __/ |
|
||||
* |___/
|
||||
*
|
||||
* copyright 2022 |
||||
* |
||||
* |
||||
* |
||||
* |
||||
* documentation: https://wiki.asterisk.org/wiki/download/attachments/19005471/asterisk-17-reference.pdf?version=1&modificationdate=1582306810980&api=v2
|
||||
*
|
||||
*/ |
||||
|
||||
#ifndef METHODS_ACTIONS |
||||
#define METHODS_ACTIONS 1 |
||||
|
||||
#include <parse_actions.h> |
||||
|
||||
int create_ExtensionStateList(s_manager *smanager, void *args); |
||||
int create_SIPpeers( s_manager *smanager, void *args ); |
||||
int create_QueueStatus(s_manager *smanager, void *args); |
||||
int create_Agents( s_manager *smanager, void *args ); |
||||
|
||||
|
||||
|
||||
|
||||
#endif |
@ -0,0 +1,267 @@
|
||||
/***
|
||||
* _____ _ _ _____
|
||||
* / ____(_) | | |_ _|
|
||||
* | (___ _ _ __ ___ _ __ | | ___ ___ | | _ __
|
||||
* \___ \| | '_ ` _ \| '_ \| |/ _ \/ __| | | | '_ \
|
||||
* ____) | | | | | | | |_) | | __/\__ \ _| |_| |_) | |
||||
* |_____/|_|_| |_| |_| .__/|_|\___||___/ |_____| .__/
|
||||
* | \/ | | | | |
|
||||
* | \ / | __ _ _ __ |_|_ _ __ _ ___ _ __ |_|
|
||||
* | |\/| |/ _` | '_ \ / _` |/ _` |/ _ \ '__|
|
||||
* | | | | (_| | | | | (_| | (_| | __/ |
|
||||
* |_| |_|\__,_|_| |_|\__,_|\__, |\___|_|
|
||||
* __/ |
|
||||
* |___/
|
||||
*
|
||||
* copyright 2022 |
||||
*
|
||||
* |
||||
*/ |
||||
|
||||
|
||||
#include <parse_actions.h> |
||||
#include <parse_events.h> |
||||
#include <methods_actions.h> |
||||
#include <main.h> |
||||
#include <limits.h> |
||||
#include <pthread.h> |
||||
#include <sys/stat.h> |
||||
#include <fcntl.h> |
||||
#include <sys/types.h> |
||||
#include <unistd.h> |
||||
#include <time.h> |
||||
#include <stdlib.h> |
||||
#include <stdio.h> |
||||
#include <string.h> |
||||
|
||||
#include <queue/queue.h> |
||||
#include <peer/peer.h> |
||||
|
||||
#define LEN_TIMESTAMP 20 |
||||
#define LEN_STR_ACTION 9 |
||||
#define LEN_STR_RESPONSE 9 |
||||
|
||||
|
||||
/*
|
||||
* NOTA |
||||
* |
||||
* Manager manda message, porém essas mensagens deve ser obtidas no
|
||||
* código fonte. A documentação pode ter falhas |
||||
*/ |
||||
|
||||
|
||||
/*
|
||||
* Estructura dos métodos actions |
||||
*/ |
||||
static s_methods_actions _methods_actions[] = |
||||
{ |
||||
/* id, nome, corpo da action, tem argumentos, função para enviar, função para analisa resposta para bd */ |
||||
|
||||
{ Action_SIPpeers, "SIPpeers", create_SIPpeers, NULL}, |
||||
{ Action_ExtensionStateList, "ExtensionStateList", create_ExtensionStateList, NULL }, |
||||
{ Action_QueueStatus, "QueueStatus", create_QueueStatus, NULL }, |
||||
{ Action_Agents, "Agents", create_Agents, NULL }, |
||||
|
||||
{0} |
||||
}; |
||||
|
||||
|
||||
struct s_timeout_actiond _timeout_actiond[] =
|
||||
{ |
||||
{ "ExtensionStateList", 60, 0 }, |
||||
{ "DeviceStateList", 60, 0 }, |
||||
{ "IAXpeerlist", 60, 0 }, |
||||
{ "SIPpeers", 60, 1 }, |
||||
{ "QueueStatus", 600, 1 }, |
||||
{ "Agents", 600, 1}, |
||||
|
||||
{0} |
||||
} ; |
||||
|
||||
|
||||
|
||||
int verify_action( s_manager *smanager ){ |
||||
|
||||
s_actionid **actionid = &smanager->list_actionid; |
||||
|
||||
while( *actionid ){ |
||||
RESPONSE *response = NULL; |
||||
EVENT *event = NULL; |
||||
|
||||
response = ami_get_actions_response( smanager->ami, (*actionid)->actionid_value ); |
||||
if( response ) { |
||||
redirect_response( response, smanager ); |
||||
ami_destroy_response( smanager->ami, response ); |
||||
} |
||||
|
||||
event = ami_get_actions_event( smanager->ami, (*actionid)->actionid_value ); |
||||
if( event ) { |
||||
redirect_event( event, smanager ); |
||||
ami_destroy_events( smanager->ami, event ); |
||||
} |
||||
|
||||
actionid = &(*actionid)->next; |
||||
} |
||||
|
||||
timeout_actionid( smanager ); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
int timeout_actionid( s_manager *smanager ){ |
||||
|
||||
if(!smanager->list_actionid){ |
||||
return 0; |
||||
} |
||||
|
||||
size_t len = ( sizeof(_timeout_actiond) / sizeof(struct s_timeout_actiond )) - 1; |
||||
|
||||
int i; |
||||
for(i = 0; i < len; i++){ |
||||
s_actionid *actionid = smanager->list_actionid; |
||||
|
||||
while(actionid){ |
||||
|
||||
if( !strcasecmp( _timeout_actiond[i].method_action, actionid->name_action ) ){ |
||||
time_t Elapsed_time = time(NULL) - actionid->use_time; |
||||
if( Elapsed_time > _timeout_actiond[i].timeout ){ // tempo esgotado
|
||||
ami_destroy_action_return(smanager->ami, actionid->actionid_value); |
||||
actionid_remove( &smanager->list_actionid, actionid ); |
||||
if(_timeout_actiond[i].restart == 1){ |
||||
create_action(_timeout_actiond[i].method_action, smanager, NULL); |
||||
} |
||||
break; |
||||
} |
||||
} |
||||
|
||||
actionid = actionid->next; |
||||
} |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
int create_action(const char *action_name, s_manager *smanager, void *arg){ |
||||
|
||||
size_t len = (sizeof(_methods_actions) / sizeof(struct s_methods_actions)) - 1; |
||||
|
||||
int i; |
||||
for (i = 0; i < len; i++){ |
||||
if( !strcasecmp( action_name, _methods_actions[i].method_name ) ){ |
||||
if(_methods_actions[i].ptr_func == NULL){continue;} |
||||
return _methods_actions[i].ptr_func(smanager, arg); |
||||
} |
||||
} |
||||
|
||||
return -1; |
||||
} |
||||
|
||||
|
||||
int redirect_response( RESPONSE *response, s_manager *smanager){ |
||||
|
||||
s_actionid *actionid = smanager->list_actionid; |
||||
size_t len = (sizeof(_methods_actions) / sizeof(struct s_methods_actions)) - 1; |
||||
|
||||
int i; |
||||
for (i = 0; i < len; i++){ |
||||
if( !strcasecmp( actionid->name_action, _methods_actions[i].method_name ) ){ |
||||
if(_methods_actions[i].ptr_func_to_response == NULL){continue;} |
||||
|
||||
return _methods_actions[i].ptr_func_to_response(response, smanager); |
||||
} |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
|
||||
int actionid_remove( s_actionid **list_actionid, s_actionid *actionid ){ |
||||
|
||||
while(*list_actionid){ |
||||
if(*list_actionid == actionid){ |
||||
s_actionid *actionid = *list_actionid; |
||||
*list_actionid = actionid->next; |
||||
actionid_free(actionid); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
list_actionid = &(*list_actionid)->next; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
int exist_actionid(s_actionid **list_actionid, const char *actionid){ |
||||
|
||||
while(*list_actionid){ |
||||
if(!strcmp((*list_actionid)->actionid_value, actionid)){ |
||||
return 0; |
||||
} |
||||
|
||||
list_actionid = &(*list_actionid)->next; |
||||
} |
||||
|
||||
return -1; |
||||
} |
||||
|
||||
|
||||
void actionid_free( s_actionid *actionid ){ |
||||
|
||||
if( !actionid ){ |
||||
return; |
||||
} |
||||
|
||||
free(actionid); |
||||
|
||||
return; |
||||
} |
||||
|
||||
|
||||
|
||||
int actionid_add( s_actionid **list_actionid, s_actionid *actionid ){ |
||||
|
||||
while( *list_actionid ){ |
||||
list_actionid = &(*list_actionid)->next; |
||||
} |
||||
|
||||
*list_actionid = actionid; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
|
||||
s_actionid *actionid_create(){ |
||||
|
||||
s_actionid *actionid = calloc(1, sizeof(s_actionid)); |
||||
if(!actionid){ |
||||
return NULL; |
||||
} |
||||
|
||||
return actionid; |
||||
|
||||
} |
||||
|
||||
|
||||
int set_value_actionid( s_actionid *actionid, const char *method_name, const char *actionid_value, const char *extra_value, int restart ){ |
||||
|
||||
strcpy( actionid->name_action, method_name ); |
||||
|
||||
strcpy( actionid->actionid_value, actionid_value ); |
||||
|
||||
if( extra_value ){ |
||||
strcpy( actionid->extra, extra_value ); |
||||
} |
||||
|
||||
actionid->restart = restart; |
||||
|
||||
actionid->use_time = time(NULL); |
||||
|
||||
return 0; |
||||
} |
||||
|
@ -0,0 +1,92 @@
|
||||
/***
|
||||
* _____ _ _ _____
|
||||
* / ____(_) | | |_ _|
|
||||
* | (___ _ _ __ ___ _ __ | | ___ ___ | | _ __
|
||||
* \___ \| | '_ ` _ \| '_ \| |/ _ \/ __| | | | '_ \
|
||||
* ____) | | | | | | | |_) | | __/\__ \ _| |_| |_) | |
||||
* |_____/|_|_| |_| |_| .__/|_|\___||___/ |_____| .__/
|
||||
* | \/ | | | | |
|
||||
* | \ / | __ _ _ __ |_|_ _ __ _ ___ _ __ |_|
|
||||
* | |\/| |/ _` | '_ \ / _` |/ _` |/ _ \ '__|
|
||||
* | | | | (_| | | | | (_| | (_| | __/ |
|
||||
* |_| |_|\__,_|_| |_|\__,_|\__, |\___|_|
|
||||
* __/ |
|
||||
* |___/
|
||||
*
|
||||
* copyright 2022 |
||||
* |
||||
* |
||||
*/ |
||||
|
||||
#ifndef METHOD_ACTION |
||||
#define METHOD_ACTION 1 |
||||
|
||||
#include <stdint.h> |
||||
#include "main.h" |
||||
|
||||
|
||||
/*
|
||||
* Defini inteiros para cada method actions |
||||
* |
||||
*/ |
||||
enum { |
||||
|
||||
Action_ExtensionStateList, |
||||
Action_SIPpeers, |
||||
Action_QueueStatus, |
||||
Action_Agents |
||||
|
||||
}; |
||||
|
||||
/* GRUPO dos comandos*/ |
||||
struct s_group_command { |
||||
int action; |
||||
}; |
||||
|
||||
/* parametro para search_actionid */ |
||||
enum { |
||||
Default = 0, /* todos */ |
||||
G_COMMAND |
||||
}; |
||||
|
||||
typedef int CALL_ACTION( s_manager * , void * ); |
||||
typedef int CALL_TO_RESPONSE( RESPONSE *, s_manager * ); |
||||
|
||||
/*
|
||||
* Estrutura dos métodos Action |
||||
* é inicializado no method_action.c
|
||||
* |
||||
*/ |
||||
struct s_methods_actions { |
||||
int id; |
||||
const char *method_name; |
||||
CALL_ACTION *ptr_func; // send action
|
||||
CALL_TO_RESPONSE *ptr_func_to_response; //analisar response
|
||||
}; |
||||
|
||||
|
||||
struct s_timeout_actiond { |
||||
char *method_action; |
||||
int timeout; |
||||
int restart; |
||||
}; |
||||
|
||||
|
||||
typedef struct s_methods_actions s_methods_actions; |
||||
typedef struct s_generic_method s_actions; |
||||
typedef struct s_generic_method_arg s_args; |
||||
typedef struct s_generic_method s_responses; |
||||
|
||||
int redirect_response( RESPONSE *response, s_manager *smanager ); |
||||
int verify_action( s_manager *smanager ); |
||||
int actionid_remove( s_actionid **list_actionid, s_actionid *actionid ); |
||||
void actionid_free( s_actionid *actionid ); |
||||
int actionid_add( s_actionid **list_actionid, s_actionid *actionid ); |
||||
s_actionid *actionid_create(); |
||||
int timeout_actionid( s_manager *smanager ); |
||||
int exist_actionid(s_actionid **list_actionid, const char *actionid); |
||||
int set_value_actionid( s_actionid *actionid, const char *method_name, const char *actionid_value, const char *extra_value, int restart ); |
||||
int create_action(const char *action_name, s_manager *smanager, void *arg); |
||||
|
||||
|
||||
#endif |
@ -0,0 +1,92 @@
|
||||
/***
|
||||
* _____ _ _ _____
|
||||
* / ____(_) | | |_ _|
|
||||
* | (___ _ _ __ ___ _ __ | | ___ ___ | | _ __
|
||||
* \___ \| | '_ ` _ \| '_ \| |/ _ \/ __| | | | '_ \
|
||||
* ____) | | | | | | | |_) | | __/\__ \ _| |_| |_) | |
||||
* |_____/|_|_| |_| |_| .__/|_|\___||___/ |_____| .__/
|
||||
* | \/ | | | | |
|
||||
* | \ / | __ _ _ __ |_|_ _ __ _ ___ _ __ |_|
|
||||
* | |\/| |/ _` | '_ \ / _` |/ _` |/ _ \ '__|
|
||||
* | | | | (_| | | | | (_| | (_| | __/ |
|
||||
* |_| |_|\__,_|_| |_|\__,_|\__, |\___|_|
|
||||
* __/ |
|
||||
* |___/
|
||||
*
|
||||
* copyright 2022 |
||||
* |
||||
*/ |
||||
|
||||
|
||||
#define STR_EVENT "event:" |
||||
#define LEN_STR_EVENT 6 |
||||
|
||||
#define FINAL_METHOD "\r\n\r\n" |
||||
|
||||
#include <string.h> |
||||
#include <main.h> |
||||
#include <parse_events.h> |
||||
#include <parse_actions.h> |
||||
#include <stdlib.h> |
||||
#include <stdio.h> |
||||
#include <pthread.h> |
||||
#include <sys/stat.h> |
||||
#include <fcntl.h> |
||||
#include <sys/types.h> |
||||
#include <unistd.h> |
||||
|
||||
|
||||
#include <peer/peer.h> |
||||
#include <queue/queue.h> |
||||
#include <agent/agent.h> |
||||
#include <queue/queue.h> |
||||
|
||||
|
||||
/* estrutura que conecta nome do evento com a função */ |
||||
static s_methods_events _methods_events[] = |
||||
{ |
||||
{ Event_ExtensionStatus, "ExtensionStatus", parse_event_extensionstatus }, |
||||
{ Event_PeerEntry, "PeerEntry", parse_event_peerentry }, |
||||
{ Event_PeerlistComplete, "PeerlistComplete", parse_event_peerlistcomplete }, |
||||
{ Event_PeerStatus, "PeerStatus", parse_event_peerstatus }, |
||||
{ Event_QueueParams, "QueueParams", parse_event_queueparams }, |
||||
// { Event_QueueMember, "QueueMember", parse_event_queuemember },
|
||||
// { Event_Agents, "Agents", parse_event_agents },
|
||||
|
||||
{0} |
||||
}; |
||||
|
||||
|
||||
|
||||
int verify_event( s_manager *smanager ){ |
||||
|
||||
EVENT *event; |
||||
|
||||
event = ami_get_events(smanager->ami); |
||||
if( event ){ |
||||
redirect_event( event, smanager ); |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
|
||||
int redirect_event( EVENT *event, s_manager *smanager ){ |
||||
|
||||
while( event ){ |
||||
int len = ( sizeof( _methods_events ) / sizeof( s_methods_events ) - 1 ); |
||||
int x; |
||||
for( x = 0; x < len; x++ ){ |
||||
if( !strcasecmp( _methods_events[x].method_name, event->event ) ){ |
||||
_methods_events[x].ptr_func(event, smanager); |
||||
} |
||||
} |
||||
|
||||
event = event->next; |
||||
} |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
@ -0,0 +1,69 @@
|
||||
/***
|
||||
* _____ _ _ _____
|
||||
* / ____(_) | | |_ _|
|
||||
* | (___ _ _ __ ___ _ __ | | ___ ___ | | _ __
|
||||
* \___ \| | '_ ` _ \| '_ \| |/ _ \/ __| | | | '_ \
|
||||
* ____) | | | | | | | |_) | | __/\__ \ _| |_| |_) | |
||||
* |_____/|_|_| |_| |_| .__/|_|\___||___/ |_____| .__/
|
||||
* | \/ | | | | |
|
||||
* | \ / | __ _ _ __ |_|_ _ __ _ ___ _ __ |_|
|
||||
* | |\/| |/ _` | '_ \ / _` |/ _` |/ _ \ '__|
|
||||
* | | | | (_| | | | | (_| | (_| | __/ |
|
||||
* |_| |_|\__,_|_| |_|\__,_|\__, |\___|_|
|
||||
* __/ |
|
||||
* |___/
|
||||
*
|
||||
* copyright 2022 |
||||
* |
||||
*/ |
||||
|
||||
|
||||
#ifndef METHOD_EVENTS |
||||
#define METHOD_EVENTS 1 |
||||
|
||||
#include <stdlib.h> |
||||
#include <main.h> |
||||
#include <ami_c.h> |
||||
|
||||
/*
|
||||
* Defini inteiros para cada method actions |
||||
* |
||||
*/ |
||||
enum { |
||||
Event_ExtensionStatus, |
||||
Event_PeerEntry, |
||||
Event_PeerlistComplete, |
||||
Event_PeerStatus, |
||||
Event_QueueParams, |
||||
Event_QueueMember, |
||||
Event_Agents |
||||
}; |
||||
|
||||
|
||||
typedef int CALL_EVENT( EVENT *, s_manager * ); |
||||
|
||||
|
||||
/*
|
||||
* Estrutura dos métodos Action |
||||
* é inicializado no method_action.c
|
||||
* |
||||
*/ |
||||
typedef struct { |
||||
int id; |
||||
char *method_name; |
||||
CALL_EVENT *ptr_func; |
||||
}s_methods_events; |
||||
|
||||
typedef struct s_generic_method s_events; |
||||
typedef struct s_generic_method_arg s_event_args; |
||||
|
||||
|
||||
int redirect_event( EVENT *event, s_manager *smanager ); |
||||
int verify_event( s_manager *smanager ); |
||||
size_t strlen_event(const char *str, char *p_end, int use_char); |
||||
void strcpy_s(const char *str, char **event_name, char *p_end); |
||||
|
||||
|
||||
|
||||
|
||||
#endif |
@ -0,0 +1,436 @@
|
||||
/***
|
||||
* _____ _ _ _____
|
||||
* / ____(_) | | |_ _|
|
||||
* | (___ _ _ __ ___ _ __ | | ___ ___ | | _ __
|
||||
* \___ \| | '_ ` _ \| '_ \| |/ _ \/ __| | | | '_ \
|
||||
* ____) | | | | | | | |_) | | __/\__ \ _| |_| |_) | |
||||
* |_____/|_|_| |_| |_| .__/|_|\___||___/ |_____| .__/
|
||||
* | \/ | | | | |
|
||||
* | \ / | __ _ _ __ |_|_ _ __ _ ___ _ __ |_|
|
||||
* | |\/| |/ _` | '_ \ / _` |/ _` |/ _ \ '__|
|
||||
* | | | | (_| | | | | (_| | (_| | __/ |
|
||||
* |_| |_|\__,_|_| |_|\__,_|\__, |\___|_|
|
||||
* __/ |
|
||||
* |___/
|
||||
*
|
||||
* copyright 2022 |
||||
* |
||||
*/ |
||||
|
||||
#include <mariadb/mysql.h> |
||||
#include <methods_actions.h> |
||||
#include <peer/peer.h> |
||||
#include <string_functions.h> |
||||
#include <stdio.h> |
||||
#include <stdlib.h> |
||||
#include <main.h> |
||||
#include <string.h> |
||||
#include <frame/frame_asterisk.h> |
||||
|
||||
|
||||
|
||||
/*
|
||||
* field peer_callerid_number |
||||
* peer_callerid_name (mesmo que peer_callerid_number) |
||||
* type |
||||
* peer_trunk |
||||
*/ |
||||
int parse_event_extensionstatus(EVENT *event, s_manager *smanager){ |
||||
|
||||
/*
|
||||
* Event: ExtensionStatus |
||||
* Exten: <value> |
||||
* Context: <value> |
||||
* Hint: <value> |
||||
* Status: <value> |
||||
* StatusText: <value> |
||||
*/ |
||||
|
||||
/*
|
||||
* Status - Numerical value of the extension status. Extension status is determined by the combined device state of all items contained in the hint. |
||||
*** -2 - The extension was removed from the dialplan. |
||||
*** -1 - The extension's hint was removed from the dialplan. |
||||
*** 0 - Idle - Related device(s) are in an idle state. |
||||
*** 1 - InUse - Related device(s) are in active calls but may take more calls. |
||||
*** 2 - Busy - Related device(s) are in active calls and may not take any more calls. |
||||
*** 4 - Unavailable - Related device(s) are not reachable. |
||||
*** 8 - Ringing - Related device(s) are currently ringing. |
||||
*** 9 - InUse&Ringing - Related device(s) are currently ringing and in active calls. |
||||
*** 16 - Hold - Related device(s) are currently on hold. |
||||
*** 17 - InUse&Hold - Related device(s) are currently on hold and in active calls. |
||||
* |
||||
* StatusText - Text representation of Status. |
||||
*** Idle |
||||
*** InUse |
||||
*** Busy |
||||
*** Unavailable |
||||
*** Ringing |
||||
*** InUse&Ringing |
||||
*** Hold |
||||
*** InUse&Hold |
||||
*** Unknown - Status does not match any of the above values. |
||||
*/ |
||||
|
||||
|
||||
const char *exten, *status, *status_text; |
||||
int i_status, peer_trunk; |
||||
|
||||
exten = ami_get_value( smanager->ami, event->args, "Exten" ); |
||||
if( !exten ) goto fail; |
||||
|
||||
{ // analisar se é um tronco
|
||||
if( ami_has_key( smanager->ami, event->args, "ActionID" ) == 0){ |
||||
peer_trunk = 0; |
||||
} |
||||
else{ |
||||
struct s_peer *peer = get_peer(exten); |
||||
if(peer){ |
||||
peer_trunk = peer->trunk; |
||||
} |
||||
else{ |
||||
/* aqui deve ter uma action para atualizar quem sçao troncos */ |
||||
create_action("SIPpeers", smanager, NULL); |
||||
peer_trunk = 1; |
||||
} |
||||
} |
||||
} |
||||
|
||||
status = ami_get_value( smanager->ami, event->args, "Status"); |
||||
if(!status) { i_status = 0; } else{ i_status = atoi(status); } |
||||
|
||||
status_text = ami_get_value( smanager->ami, event->args, "StatusText"); |
||||
if(!status_text) { goto fail; }
|
||||
|
||||
|
||||
{/* banco de dados */ |
||||
struct s_table_peer *table_peer; |
||||
|
||||
table_peer = get_extensionstatus_db( Select_extensionstatus, exten ); |
||||
if( table_peer ){ |
||||
|
||||
if( i_status == -2 || i_status == -1 ){ |
||||
/* delete row no banco
|
||||
* The extension was removed from the dialplan. */ |
||||
delete_extensionstatus_db(delete_extensionstatus, table_peer->id); |
||||
|
||||
struct s_peer *peer = get_peer(exten); |
||||
if(peer){ |
||||
remove_peer(peer); |
||||
} |
||||
|
||||
free_table_peer(&table_peer); |
||||
goto fail; |
||||
} |
||||
|
||||
else if( (table_peer->trunk != peer_trunk) ||
|
||||
table_peer->exten_status != i_status ||
|
||||
strcmp_n(table_peer->exten_statustext, status_text)) { |
||||
|
||||
if(update_extensionstatus_db(Update_extensionstatus, i_status, status_text, peer_trunk, table_peer->id) == -1){ |
||||
_WARNING("Falha %s %d\n", exten, __LINE__); |
||||
} |
||||
} |
||||
|
||||
free_table_peer(&table_peer); |
||||
} |
||||
else if (i_status != -2) { /* inserir novo extension no banco */ |
||||
insert_extensionstatus_db(Insert_extensionstatus, exten, i_status, status_text, peer_trunk); |
||||
} |
||||
|
||||
} |
||||
|
||||
{/* camada de persistência */ |
||||
/* struct s_peer {
|
||||
char *callerid_number; |
||||
char *callerid_name; |
||||
char *dynamic; |
||||
char *protocol; |
||||
char *status; |
||||
char *exten_status; |
||||
char *exten_statustext; |
||||
char *address; |
||||
int trunk; |
||||
char *time; |
||||
struct s_channel *channel; |
||||
struct s_variable *variable; |
||||
struct s_agent *agent; // trunk não pode agent
|
||||
struct s_peer *next; |
||||
}; |
||||
*/ |
||||
|
||||
struct s_peer *peer; |
||||
peer = get_peer(exten); |
||||
|
||||
if( !peer ){ // exten não existe na camada
|
||||
peer = create_peer();// cria estrutura de dados
|
||||
newstrncpy(&peer->callerid_number, exten); |
||||
peer->exten_status = i_status; |
||||
newstrncpy(&peer->exten_statustext, status_text); |
||||
peer->trunk = peer_trunk; |
||||
insert_peer(peer); //inseri o novo peer para persistência
|
||||
} |
||||
else { |
||||
if(i_status != -2 && i_status != -1){ |
||||
/*
|
||||
* update se necessário |
||||
*/ |
||||
if(strcmp_n(peer->exten_statustext, status_text) != 0){ |
||||
free(peer->exten_statustext); |
||||
newstrncpy(&peer->exten_statustext, status_text); |
||||
} |
||||
|
||||
if(peer->exten_status != i_status){ |
||||
peer->exten_status = i_status; |
||||
} |
||||
|
||||
if(peer->trunk != peer_trunk){ |
||||
peer->trunk = peer_trunk; |
||||
} |
||||
} |
||||
else { |
||||
remove_peer(peer); |
||||
} |
||||
|
||||
} |
||||
} |
||||
|
||||
return 1; |
||||
|
||||
fail: |
||||
return -1; |
||||
} |
||||
|
||||
|
||||
|
||||
int parse_event_peerentry( EVENT *event, s_manager *smanager ){ |
||||
/*
|
||||
Event: PeerEntry |
||||
Channeltype: SIP //tipo
|
||||
ObjectName: 0800 //nome
|
||||
ChanObjectType: peer // peer pode ser agent
|
||||
IPaddress: -none- //ip
|
||||
IPport: 0 //port
|
||||
Dynamic: yes // não está padronizado com o sistema web
|
||||
AutoForcerport: no //NAT
|
||||
Forcerport: yes //NAT
|
||||
AutoComedia: no
|
||||
Comedia: yes |
||||
VideoSupport: no //suportar vídeo
|
||||
TextSupport: no //suportar texto
|
||||
ACL: yes // permit|deny|acl
|
||||
Status: UNKNOWN //tempo de ping
|
||||
RealtimeDevice: no //banco de dados asterisk
|
||||
Description:
|
||||
Accountcode:
|
||||
*/ |
||||
|
||||
const char *channeltype, *objectname, *ipaddress; |
||||
struct s_table_peer *table_peer = NULL; // table peer value
|
||||
int peer_trunk; |
||||
|
||||
channeltype = ami_get_value(smanager->ami, event->args, "Channeltype"); |
||||
if(!channeltype) goto fail; |
||||
|
||||
objectname = ami_get_value(smanager->ami, event->args, "ObjectName"); |
||||
if(!objectname) goto fail; |
||||
|
||||
ipaddress = ami_get_value(smanager->ami, event->args, "IPaddress"); |
||||
if(!atoi(ipaddress)) { |
||||
ipaddress = NULL; |
||||
} |
||||
|
||||
struct s_peer *peer = get_peer(objectname); // get camada de persistência|verificar se é um tronco
|
||||
if( peer ){ |
||||
peer_trunk = peer->trunk; |
||||
} |
||||
else{ |
||||
peer_trunk = 1; |
||||
} |
||||
|
||||
{ /* Database
|
||||
* collumns id
|
||||
* callerid_number - ObjectName |
||||
* protocol - channeltype |
||||
* address - ip |
||||
* trunk - boolean |
||||
*/ |
||||
table_peer = get_peerentry_db( Select_peerentry, objectname ); |
||||
|
||||
if(table_peer){ |
||||
if( (table_peer->trunk != peer_trunk) || |
||||
(strcmp_n(table_peer->protocol, channeltype) != 0) ||
|
||||
(strcmp_n(table_peer->address, ipaddress) != 0) ) { |
||||
|
||||
update_peerentry_db(Update_peerentry, channeltype, ipaddress, peer_trunk, table_peer->id); |
||||
} |
||||
|
||||
free_table_peer(&table_peer); |
||||
} |
||||
else{ |
||||
insert_peerentry_db(Insert_peerentry, objectname, channeltype, ipaddress, peer_trunk); |
||||
} |
||||
} |
||||
|
||||
{// Camada de persistência
|
||||
|
||||
if(peer ) { |
||||
|
||||
if(strcmp_n(peer->callerid_number, objectname) != 0){ |
||||
free(peer->callerid_number); |
||||
newstrncpy(&peer->callerid_number, objectname); |
||||
} |
||||
|
||||
if(strcmp_n(peer->protocol, channeltype) != 0){ |
||||
free(peer->protocol); |
||||
newstrncpy(&peer->protocol, channeltype); |
||||
} |
||||
|
||||
if(strcmp_n(peer->address, ipaddress) != 0){ |
||||
free(peer->address); |
||||
newstrncpy(&peer->address, ipaddress); |
||||
} |
||||
|
||||
peer->trunk = peer_trunk; |
||||
} |
||||
else{ |
||||
peer = create_peer(); |
||||
|
||||
newstrncpy(&peer->callerid_number, objectname); |
||||
|
||||
newstrncpy(&peer->protocol, channeltype); |
||||
|
||||
newstrncpy(&peer->address, ipaddress); |
||||
|
||||
peer->trunk = peer_trunk; |
||||
|
||||
insert_peer(peer); |
||||
} |
||||
} |
||||
|
||||
return 1; |
||||
|
||||
fail: |
||||
return -1; |
||||
} |
||||
|
||||
|
||||
|
||||
int parse_event_peerstatus( EVENT *event, s_manager *smanager ){ |
||||
|
||||
/*
|
||||
* ChannelType - The channel technology of the peer. |
||||
* Peer - The name of the peer (including channel technology). |
||||
* PeerStatus - New status of the peer. |
||||
* Unknown |
||||
* Registered |
||||
* Unregistered |
||||
* Rejected |
||||
* Lagged |
||||
* Cause - The reason the status has changed. |
||||
* Address - New address of the peer. |
||||
* Port - New port for the peer. |
||||
* Time - Time it takes to reach the peer and receive a response. |
||||
*/ |
||||
|
||||
const char *protocol, *peer, *status, *address, *exten; |
||||
|
||||
protocol = ami_get_value(smanager->ami, event->args, "Channeltype"); |
||||
if(!protocol) goto fail; |
||||
|
||||
peer = ami_get_value(smanager->ami, event->args, "Peer"); |
||||
if(!peer) goto fail; |
||||
exten = get_parse_exten(peer); |
||||
if(!exten) goto fail; |
||||
|
||||
status = ami_get_value(smanager->ami, event->args, "PeerStatus"); |
||||
|
||||
address = ami_get_value(smanager->ami, event->args, "Address"); |
||||
|
||||
{ /* Database
|
||||
*
|
||||
* |
||||
*/ |
||||
struct s_table_peer *table_peer = NULL; |
||||
table_peer = get_peerstatus_db( Select_peerstatus, exten ); |
||||
if(table_peer){ |
||||
if( strcmp_n( table_peer->protocol, protocol ) ||
|
||||
strcmp_n( table_peer->address, address ) || |
||||
strcmp_n( table_peer->status, status )){ |
||||
|
||||
update_peerstatus_db( Update_peerstatus, protocol, status, address, table_peer->id ); |
||||
} |
||||
|
||||
free_table_peer(&table_peer); |
||||
}
|
||||
else { |
||||
insert_peerstatus_db( Insert_peerstatus, exten, protocol, status, address ); |
||||
} |
||||
} |
||||
|
||||
{ // frame
|
||||
struct s_peer *peer; |
||||
peer = get_peer(exten); |
||||
|
||||
if(peer){ |
||||
if( strcasecmp_n( "Unregistered", status) ||
|
||||
strcasecmp_n( "Rejected", status)) { |
||||
|
||||
remove_peer(peer); |
||||
} |
||||
if( strcmp_n( peer->protocol, protocol )){ |
||||
free( peer->protocol ); |
||||
newstrncpy( &peer->protocol, protocol ); |
||||
} |
||||
|
||||
if( strcmp_n( peer->address, address ) ){ |
||||
free(peer->address); |
||||
newstrncpy(&peer->address, address ); |
||||
} |
||||
|
||||
if( strcmp_n( peer->status, status )){ |
||||
free( peer->status ); |
||||
newstrncpy( &peer->status, status ); |
||||
} |
||||
} |
||||
else{ |
||||
peer = create_peer(); |
||||
|
||||
newstrncpy( &peer->callerid_number, exten); |
||||
|
||||
newstrncpy( &peer->status, status ); |
||||
|
||||
newstrncpy( &peer->protocol, protocol); |
||||
|
||||
newstrncpy( &peer->address, address); |
||||
|
||||
insert_peer( peer); |
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
return 1; |
||||
|
||||
fail: |
||||
return -1; |
||||
|
||||
} |
||||
|
||||
|
||||
int parse_event_peerlistcomplete(EVENT *event, s_manager *smanager){ |
||||
|
||||
|
||||
create_action("ExtensionStateList", smanager, NULL); |
||||
|
||||
return 1; |
||||
} |
||||
|
||||
|
||||
int parse_event_extensionstatelistcomplete( EVENT *event, s_manager *smanager ){ |
||||
|
||||
return 1; |
||||
} |
||||
|
||||
|
||||
|
||||
|
@ -0,0 +1,83 @@
|
||||
/***
|
||||
* _____ _ _ _____
|
||||
* / ____(_) | | |_ _|
|
||||
* | (___ _ _ __ ___ _ __ | | ___ ___ | | _ __
|
||||
* \___ \| | '_ ` _ \| '_ \| |/ _ \/ __| | | | '_ \
|
||||
* ____) | | | | | | | |_) | | __/\__ \ _| |_| |_) | |
||||
* |_____/|_|_| |_| |_| .__/|_|\___||___/ |_____| .__/
|
||||
* | \/ | | | | |
|
||||
* | \ / | __ _ _ __ |_|_ _ __ _ ___ _ __ |_|
|
||||
* | |\/| |/ _` | '_ \ / _` |/ _` |/ _ \ '__|
|
||||
* | | | | (_| | | | | (_| | (_| | __/ |
|
||||
* |_| |_|\__,_|_| |_|\__,_|\__, |\___|_|
|
||||
* __/ |
|
||||
* |___/
|
||||
*
|
||||
* copyright 2022 |
||||
* |
||||
*/ |
||||
|
||||
#ifndef PEER |
||||
#define PEER 1 |
||||
|
||||
#include <database/database.h> |
||||
#include <ami_c.h> |
||||
#include <main.h> |
||||
|
||||
|
||||
|
||||
struct s_table_peer { |
||||
unsigned long long id; |
||||
char *callerid_number; |
||||
char *callerid_name; |
||||
char *dynamic; |
||||
char *protocol; |
||||
char *status; |
||||
int exten_status; |
||||
char *exten_statustext; |
||||
char *address; |
||||
int trunk; |
||||
MYSQL_TIME *time; |
||||
struct s_table_peer *next; |
||||
}; |
||||
|
||||
|
||||
int parse_event_peerentry( EVENT *event, s_manager *smanager ); |
||||
int parse_event_peerlistcomplete(EVENT *event, s_manager *smanager); |
||||
int parse_event_peerstatus( EVENT *event, s_manager *smanager ); |
||||
int ExtensionStateListComplete( EVENT *event, s_manager *smanager ); |
||||
|
||||
|
||||
int add_table_peer(struct s_table_peer **D, struct s_table_peer *next); |
||||
int free_table_peer(struct s_table_peer **D); |
||||
|
||||
/* ExtensionStatus */ |
||||
int parse_event_extensionstatus(EVENT *event, s_manager *smanager); |
||||
int insert_extensionstatus_db(stmt_t type_stmt,
|
||||
const char *peer_callerid_number,
|
||||
int status,
|
||||
const char *status_text,
|
||||
int peer_trunk ); |
||||
int update_extensionstatus_db( stmt_t type_stmt,
|
||||
int status,
|
||||
const char *status_text,
|
||||
int peer_trunk,
|
||||
unsigned long long int id ); |
||||
struct s_table_peer *get_extensionstatus_db(stmt_t type_stmt, const char *peer_callerid_number); |
||||
int delete_extensionstatus_db(stmt_t type_stmt, unsigned long long peer_id); |
||||
|
||||
int update_peer_dynamic(stmt_t type_stmt, int dynamic, unsigned long long peer_id); |
||||
|
||||
int update_exten_trunk_db(stmt_t type_stmt, char *exten, unsigned long long peer_trunk); |
||||
|
||||
/* PeerEntry */ |
||||
struct s_table_peer *get_peerentry_db(stmt_t type_stmt, const char *objectname); |
||||
int update_peerentry_db(stmt_t type_stmt, const char *protocol, const char *peer_address, int peer_trunk, unsigned long long int peer_id); |
||||
int insert_peerentry_db(stmt_t type_stmt, const char *peer_callerid_number, const char *protocol, const char *peer_address, int peer_trunk); |
||||
|
||||
/* PeerStatus */ |
||||
struct s_table_peer *get_peerstatus_db(stmt_t type_stmt, const char *peer_callerid_number); |
||||
int update_peerstatus_db( stmt_t type_stmt, const char *protocol, const char *status, const char *address, unsigned long long int peer_id ); |
||||
int insert_peerstatus_db( stmt_t type_stmt, const char *peer_callerid_number, const char *protocol, const char *status, const char *address ); |
||||
|
||||
#endif |
@ -0,0 +1,508 @@
|
||||
#include <peer/peer.h> |
||||
#include <database/database.h> |
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
#include <string_functions.h> |
||||
|
||||
|
||||
|
||||
/* valores tabela peer */ |
||||
int add_table_peer(struct s_table_peer **D, struct s_table_peer *next){ |
||||
|
||||
while(*D){ |
||||
D = &(*D)->next; |
||||
} |
||||
|
||||
(*D) = next; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
/* liberar ponteiro da tabela */ |
||||
int free_table_peer(struct s_table_peer **D){ |
||||
|
||||
if((*D) == NULL) |
||||
return 0; |
||||
|
||||
free_table_peer( &(*D)->next ); |
||||
|
||||
free( (*D)->callerid_number ); |
||||
free( (*D)->callerid_name ); |
||||
free( (*D)->protocol ); |
||||
free( (*D)->status ); |
||||
free( (*D)->exten_statustext ); |
||||
free( (*D)->address ); |
||||
free( (*D)->time ); |
||||
free( *D ); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
/* ExtensionStatus */ |
||||
struct s_table_peer *get_extensionstatus_db(stmt_t type_stmt, const char *peer_callerid_number){ |
||||
// SELECT id, callerid_number, trunk, exten_status, exten_statustext FROM peer where callerid_number = ?;
|
||||
|
||||
MYSQL_STMT *stmt; |
||||
stmt = get_stmt(type_stmt); |
||||
if(!stmt){ |
||||
return NULL; |
||||
} |
||||
|
||||
pthread_mutex_lock(&m_db); |
||||
|
||||
MARIADB_BIND *bind = create_bind_manager( 1 ); |
||||
set_in_mariadb_column(&bind[0], ARG_STR_DB((char *)peer_callerid_number), (char *)peer_callerid_number, 0, isNULL(peer_callerid_number)); |
||||
|
||||
if(mariadb_stmt_execute(stmt, bind) == -1){ |
||||
goto fail; |
||||
} |
||||
|
||||
MARIADB_BIND *bind_result; |
||||
bind_result = get_bind_result(stmt); |
||||
|
||||
struct s_table_peer *table_peer = NULL, *table_peer_next = NULL; |
||||
int returnf = 0; |
||||
while(1){ |
||||
returnf = mysql_stmt_fetch(stmt); |
||||
|
||||
if(returnf == 1 || returnf == MYSQL_NO_DATA){ |
||||
break; |
||||
} |
||||
|
||||
table_peer_next = (struct s_table_peer *)calloc(1, sizeof(struct s_table_peer)); |
||||
if(!table_peer_next){ break; } |
||||
table_peer_next->next = NULL; |
||||
|
||||
/* column peer_id */ |
||||
table_peer_next->id = *(unsigned long long *)bind_result[0].buffer; |
||||
|
||||
/* columns peer_callerid_number */ |
||||
newstrncpy(&table_peer_next->callerid_number, bind_result[1].buffer); |
||||
|
||||
/* columns peer_trunk */ |
||||
table_peer_next->trunk = *(int *)bind_result[2].buffer; |
||||
|
||||
/* columns exten_status */ |
||||
table_peer_next->exten_status = *(int *)bind_result[3].buffer; |
||||
|
||||
/* columns exten_statustext */ |
||||
newstrncpy(&table_peer_next->exten_statustext, bind_result[4].buffer); |
||||
|
||||
add_table_peer(&table_peer, table_peer_next); |
||||
} |
||||
|
||||
destroy_bind_manager(bind_result); |
||||
|
||||
pthread_mutex_unlock(&m_db); |
||||
return table_peer; |
||||
fail:
|
||||
pthread_mutex_unlock(&m_db); |
||||
return NULL; |
||||
} |
||||
|
||||
|
||||
|
||||
/* ExtensionStatus */ |
||||
int insert_extensionstatus_db(stmt_t type_stmt,
|
||||
const char *peer_callerid_number,
|
||||
int status,
|
||||
const char *status_text,
|
||||
int peer_trunk ){ |
||||
//"INSERT INTO peer ( callerid_number, exten_status, exten_statustext, trunk ) VALUES(?, ?, ?, ?);"
|
||||
|
||||
MYSQL_STMT *stmt; |
||||
stmt = get_stmt(type_stmt); |
||||
if(!stmt){ |
||||
return -1; |
||||
} |
||||
|
||||
pthread_mutex_lock(&m_db); |
||||
|
||||
MARIADB_BIND *bind = create_bind_manager( 4 ); |
||||
set_in_mariadb_column(&bind[0], ARG_STR_DB((char *)peer_callerid_number), (char *)peer_callerid_number, 0, isNULL(peer_callerid_number)); |
||||
set_in_mariadb_column(&bind[1], MYSQL_TYPE_LONG, &status, 0, 0); |
||||
set_in_mariadb_column(&bind[2], ARG_STR_DB(status_text), (char *)status_text, 0, isNULL(status_text)); |
||||
set_in_mariadb_column(&bind[3], MYSQL_TYPE_LONG, &peer_trunk, 0, 0); |
||||
|
||||
if(mariadb_stmt_execute(stmt, bind) == -1){ |
||||
goto fail; |
||||
} |
||||
|
||||
int result = (int)mysql_stmt_affected_rows(stmt); |
||||
|
||||
pthread_mutex_unlock(&m_db); |
||||
return result; |
||||
|
||||
fail: |
||||
pthread_mutex_unlock(&m_db); |
||||
return -1; |
||||
} |
||||
|
||||
|
||||
|
||||
/* ExtensionStatus */ |
||||
int update_extensionstatus_db( stmt_t type_stmt, int status, const char *status_text, int peer_trunk, unsigned long long int id ){ |
||||
//"UPDATE peer SET exten_status=?, peer.exten_statustext=?, trunk=? WHERE id=?;"
|
||||
|
||||
MYSQL_STMT *stmt; |
||||
stmt = get_stmt(type_stmt); |
||||
if(!stmt){ |
||||
return -1; |
||||
} |
||||
|
||||
pthread_mutex_lock(&m_db); |
||||
|
||||
MARIADB_BIND *bind = create_bind_manager( 4 ); |
||||
|
||||
set_in_mariadb_column(&bind[0], MYSQL_TYPE_LONG, &status, 0, 0); |
||||
set_in_mariadb_column(&bind[1], ARG_STR_DB(status_text), (char *)status_text, 0, isNULL(status_text)); |
||||
set_in_mariadb_column(&bind[2], MYSQL_TYPE_LONG, &peer_trunk, 0, 0); |
||||
set_in_mariadb_column(&bind[3], MYSQL_TYPE_LONGLONG, &id, 1, 0); |
||||
|
||||
|
||||
if(mariadb_stmt_execute(stmt, bind) == -1){ |
||||
goto fail; |
||||
} |
||||
|
||||
int result = (int)mysql_stmt_affected_rows(stmt); |
||||
|
||||
pthread_mutex_unlock(&m_db); |
||||
return result; |
||||
|
||||
fail: |
||||
pthread_mutex_unlock(&m_db); |
||||
return -1; |
||||
} |
||||
|
||||
|
||||
int update_peer_dynamic(stmt_t type_stmt, int dynamic, unsigned long long peer_id){ |
||||
|
||||
MYSQL_STMT *stmt; |
||||
stmt = get_stmt(type_stmt); |
||||
if(!stmt){ |
||||
return -1; |
||||
} |
||||
|
||||
pthread_mutex_lock(&m_db); |
||||
MARIADB_BIND *bind = create_bind_manager(2); |
||||
set_in_mariadb_column(&bind[0], MYSQL_TYPE_LONGLONG, &dynamic, 0, 0); |
||||
set_in_mariadb_column(&bind[1], MYSQL_TYPE_LONGLONG, &peer_id, 0, 0); |
||||
|
||||
if(mariadb_stmt_execute(stmt, bind) == -1){ |
||||
goto fail; |
||||
} |
||||
|
||||
int result = (int)mysql_stmt_affected_rows(stmt); |
||||
pthread_mutex_unlock(&m_db); |
||||
return result; |
||||
|
||||
fail: |
||||
pthread_mutex_unlock(&m_db); |
||||
return -1; |
||||
|
||||
} |
||||
|
||||
|
||||
|
||||
/* ExtensionStatus */ |
||||
int delete_extensionstatus_db(stmt_t type_stmt, unsigned long long peer_id){ |
||||
|
||||
MYSQL_STMT *stmt; |
||||
stmt = get_stmt(type_stmt); |
||||
if(!stmt){ |
||||
return -1; |
||||
} |
||||
|
||||
pthread_mutex_lock(&m_db); |
||||
|
||||
MARIADB_BIND *bind = create_bind_manager(1); |
||||
set_in_mariadb_column(&bind[0], MYSQL_TYPE_LONGLONG, &peer_id, 1, 0); |
||||
|
||||
if(mariadb_stmt_execute(stmt, bind) == -1){ |
||||
goto fail; |
||||
} |
||||
|
||||
int result = (int)mysql_stmt_affected_rows(stmt); |
||||
pthread_mutex_unlock(&m_db); |
||||
|
||||
return result; |
||||
|
||||
fail: |
||||
pthread_mutex_unlock(&m_db); |
||||
return -1; |
||||
} |
||||
|
||||
|
||||
/* PeerEntry */ |
||||
struct s_table_peer *get_peerentry_db( stmt_t type_stmt, const char *objectname ){ |
||||
|
||||
if(!objectname){ |
||||
return NULL; |
||||
} |
||||
|
||||
MYSQL_STMT *stmt; |
||||
stmt = get_stmt(type_stmt); |
||||
if(!stmt){ |
||||
return NULL; |
||||
} |
||||
|
||||
int returnf; |
||||
|
||||
pthread_mutex_lock(&m_db); |
||||
|
||||
MARIADB_BIND *bind = create_bind_manager( 1 ); |
||||
set_in_mariadb_column(&bind[0], MYSQL_TYPE_STRING, (char *)objectname, 0, isNULL((char *)objectname)); |
||||
|
||||
if(mariadb_stmt_execute(stmt, bind) == -1) |
||||
goto fail; |
||||
|
||||
MARIADB_BIND *bind_result; |
||||
bind_result = get_bind_result(stmt); |
||||
|
||||
struct s_table_peer *table_peer = NULL, *table_peer_next = NULL; |
||||
while(1){ |
||||
returnf = mysql_stmt_fetch(stmt); |
||||
|
||||
if(returnf == 1 || returnf == MYSQL_NO_DATA){ |
||||
break; |
||||
} |
||||
|
||||
table_peer_next = (struct s_table_peer *)calloc(1, sizeof(struct s_table_peer)); |
||||
if(!table_peer_next){ break; } |
||||
table_peer_next->next = NULL; |
||||
|
||||
/* column peer_id */ |
||||
table_peer_next->id = *(unsigned long long *)bind_result[0].buffer; |
||||
|
||||
/* columns peer_callerid_number */ |
||||
newstrncpy(&table_peer_next->callerid_number, bind_result[1].buffer); |
||||
|
||||
/* columns peer_type */ |
||||
newstrncpy(&table_peer_next->protocol, bind_result[2].buffer); |
||||
|
||||
/* columns peer_address */ |
||||
newstrncpy(&table_peer_next->address, bind_result[3].buffer); |
||||
|
||||
/* columns peer_trunk */ |
||||
table_peer_next->trunk = *(int *)bind_result[4].buffer; |
||||
|
||||
add_table_peer(&table_peer, table_peer_next); |
||||
} |
||||
|
||||
destroy_bind_manager(bind_result); |
||||
|
||||
pthread_mutex_unlock(&m_db); |
||||
|
||||
return table_peer; |
||||
|
||||
fail: |
||||
pthread_mutex_unlock(&m_db); |
||||
return NULL; |
||||
|
||||
} |
||||
|
||||
|
||||
/* PeerEntry */ |
||||
int update_peerentry_db(stmt_t type_stmt, const char *protocol, const char *peer_address, int peer_trunk, unsigned long long int peer_id){ |
||||
|
||||
MYSQL_STMT *stmt; |
||||
stmt = get_stmt(type_stmt); |
||||
if(!stmt){ |
||||
return -1; |
||||
} |
||||
|
||||
pthread_mutex_lock(&m_db); |
||||
|
||||
MARIADB_BIND *bind = create_bind_manager( 4 ); |
||||
set_in_mariadb_column(&bind[0], ARG_STR_DB((char *)protocol), (char *)protocol, 0, isNULL((char *)protocol)); |
||||
set_in_mariadb_column(&bind[1], ARG_STR_DB((char *)peer_address), (char *)peer_address, 0, isNULL((char *)peer_address)); |
||||
set_in_mariadb_column(&bind[2], MYSQL_TYPE_TINY, &peer_trunk, 0, 0); |
||||
set_in_mariadb_column(&bind[3], MYSQL_TYPE_LONGLONG, &peer_id, 1, 0); |
||||
|
||||
if(mariadb_stmt_execute(stmt, bind) == -1){ |
||||
goto fail; |
||||
} |
||||
|
||||
int result = (int)mysql_stmt_affected_rows(stmt); |
||||
|
||||
pthread_mutex_unlock(&m_db); |
||||
|
||||
return result; |
||||
|
||||
fail: |
||||
pthread_mutex_unlock(&m_db); |
||||
return -1; |
||||
} |
||||
|
||||
|
||||
/* PeerEntry */ |
||||
int insert_peerentry_db(stmt_t type_stmt, const char *peer_callerid_number, const char *protocol, const char *peer_address, int peer_trunk){ |
||||
|
||||
MYSQL_STMT *stmt; |
||||
stmt = get_stmt(type_stmt); |
||||
if(!stmt){ |
||||
return -1; |
||||
} |
||||
|
||||
pthread_mutex_lock(&m_db); |
||||
|
||||
MARIADB_BIND *bind = create_bind_manager( 4 ); |
||||
set_in_mariadb_column(&bind[0], ARG_STR_DB((char *)peer_callerid_number), (char *)peer_callerid_number, 0, isNULL((char *)peer_callerid_number)); |
||||
set_in_mariadb_column(&bind[1], ARG_STR_DB((char *)protocol), (char *)protocol, 0, isNULL((char *)protocol)); |
||||
set_in_mariadb_column(&bind[2], ARG_STR_DB((char *)peer_address), (char *)peer_address, 0, isNULL((char *)peer_address)); |
||||
set_in_mariadb_column(&bind[3], MYSQL_TYPE_TINY, &peer_trunk, 0, 0); |
||||
|
||||
|
||||
if(mariadb_stmt_execute(stmt, bind) == -1){ |
||||
goto fail; |
||||
} |
||||
|
||||
int result = (int)mysql_stmt_affected_rows(stmt); |
||||
|
||||
pthread_mutex_unlock(&m_db); |
||||
return result; |
||||
|
||||
fail: |
||||
pthread_mutex_unlock(&m_db); |
||||
return -1; |
||||
} |
||||
|
||||
|
||||
struct s_table_peer *get_peerstatus_db(stmt_t type_stmt, const char *peer_callerid_number){ |
||||
// SELECT id, callerid_number, protocol, status, address FROM peer where callerid_number = ?;
|
||||
|
||||
if(!peer_callerid_number){ |
||||
return NULL; |
||||
} |
||||
|
||||
MYSQL_STMT *stmt; |
||||
stmt = get_stmt(type_stmt); |
||||
if(!stmt){ |
||||
return NULL; |
||||
} |
||||
|
||||
int returnf; |
||||
|
||||
pthread_mutex_lock(&m_db); |
||||
|
||||
MARIADB_BIND *bind = create_bind_manager( 1 ); |
||||
set_in_mariadb_column(&bind[0], ARG_STR_DB((char *)peer_callerid_number), (char *)peer_callerid_number, 0, isNULL((char *)peer_callerid_number)); |
||||
|
||||
if(mariadb_stmt_execute(stmt, bind) == -1){ |
||||
goto fail; |
||||
} |
||||
|
||||
MARIADB_BIND *bind_result; |
||||
bind_result = get_bind_result(stmt); |
||||
|
||||
struct s_table_peer *table_peer = NULL, *table_peer_next = NULL; |
||||
while(1){ |
||||
returnf = mysql_stmt_fetch(stmt); |
||||
|
||||
if(returnf == 1 || returnf == MYSQL_NO_DATA){ |
||||
break; |
||||
} |
||||
|
||||
table_peer_next = (struct s_table_peer *)calloc(1, sizeof(struct s_table_peer)); |
||||
if(!table_peer_next){ break; } |
||||
table_peer_next->next = NULL; |
||||
|
||||
/* column peer_id */ |
||||
table_peer_next->id = *(unsigned long long *)bind_result[0].buffer; |
||||
|
||||
/* columns callerid_number */ |
||||
newstrncpy(&table_peer_next->callerid_number, bind_result[1].buffer); |
||||
|
||||
/* columns protocol */ |
||||
newstrncpy(&table_peer_next->protocol, bind_result[2].buffer); |
||||
|
||||
/* columns status */ |
||||
newstrncpy(&table_peer_next->status, bind_result[3].buffer); |
||||
|
||||
/* columns address */ |
||||
newstrncpy(&table_peer_next->address, bind_result[4].buffer); |
||||
|
||||
add_table_peer(&table_peer, table_peer_next); |
||||
} |
||||
|
||||
destroy_bind_manager(bind_result); |
||||
|
||||
pthread_mutex_unlock(&m_db); |
||||
return table_peer; |
||||
|
||||
fail: |
||||
pthread_mutex_unlock(&m_db); |
||||
return NULL; |
||||
|
||||
} |
||||
|
||||
|
||||
|
||||
int update_peerstatus_db( stmt_t type_stmt, const char *protocol, const char *status, const char *address, unsigned long long int peer_id ){ |
||||
// UPDATE peer SET protocol=?, status=?, address=? WHERE id=?;
|
||||
|
||||
MYSQL_STMT *stmt; |
||||
stmt = get_stmt(type_stmt); |
||||
if(!stmt){ |
||||
return -1; |
||||
} |
||||
|
||||
pthread_mutex_lock(&m_db); |
||||
|
||||
MARIADB_BIND *bind = create_bind_manager( 4 ); |
||||
set_in_mariadb_column(&bind[0], ARG_STR_DB((char *)protocol), (char *)protocol, 0, isNULL((char *)protocol)); |
||||
set_in_mariadb_column(&bind[1], ARG_STR_DB((char *)status), (char *)status, 0, isNULL((char *)status)); |
||||
set_in_mariadb_column(&bind[2], ARG_STR_DB((char *)address), (char *)address, 0, isNULL((char *)address)); |
||||
set_in_mariadb_column(&bind[3], MYSQL_TYPE_LONGLONG, &peer_id, 1, 0); |
||||
|
||||
if(mariadb_stmt_execute(stmt, bind) == -1){ |
||||
goto fail; |
||||
} |
||||
|
||||
int result = (int)mysql_stmt_affected_rows(stmt); |
||||
|
||||
pthread_mutex_unlock(&m_db); |
||||
return result; |
||||
|
||||
fail: |
||||
pthread_mutex_unlock(&m_db); |
||||
return -1; |
||||
} |
||||
|
||||
|
||||
|
||||
int insert_peerstatus_db( stmt_t type_stmt, const char *peer_callerid_number, const char *protocol, const char *status, const char *address ){ |
||||
// INSERT INTO peer (callerid_number, protocol, status, address) VALUES(?, ?, ?, ?);
|
||||
|
||||
MYSQL_STMT *stmt; |
||||
stmt = get_stmt(type_stmt); |
||||
if(!stmt){ |
||||
return -1; |
||||
} |
||||
|
||||
pthread_mutex_lock(&m_db); |
||||
|
||||
MARIADB_BIND *bind = create_bind_manager(4); |
||||
set_in_mariadb_column(&bind[0], ARG_STR_DB((char *)peer_callerid_number), (char *)peer_callerid_number, 0, isNULL((char *)peer_callerid_number)); |
||||
set_in_mariadb_column(&bind[1], ARG_STR_DB((char *)protocol), (char *)protocol, 0, isNULL((char *)protocol)); |
||||
set_in_mariadb_column(&bind[2], ARG_STR_DB((char *)status), (char *)status, 0, isNULL((char *)status)); |
||||
set_in_mariadb_column(&bind[2], ARG_STR_DB((char *)address), (char *)address, 0, isNULL((char *)address)); |
||||
|
||||
if(mariadb_stmt_execute(stmt, bind) == -1){ |
||||
goto fail; |
||||
} |
||||
|
||||
int result = (int)mysql_stmt_affected_rows(stmt); |
||||
|
||||
pthread_mutex_unlock(&m_db); |
||||
|
||||
return result; |
||||
|
||||
fail: |
||||
pthread_mutex_unlock(&m_db); |
||||
return -1; |
||||
} |
||||
|
||||
|
@ -0,0 +1,278 @@
|
||||
/***
|
||||
* _____ _ _ _____
|
||||
* / ____(_) | | |_ _|
|
||||
* | (___ _ _ __ ___ _ __ | | ___ ___ | | _ __
|
||||
* \___ \| | '_ ` _ \| '_ \| |/ _ \/ __| | | | '_ \
|
||||
* ____) | | | | | | | |_) | | __/\__ \ _| |_| |_) | |
||||
* |_____/|_|_| |_| |_| .__/|_|\___||___/ |_____| .__/
|
||||
* | \/ | | | | |
|
||||
* | \ / | __ _ _ __ |_|_ _ __ _ ___ _ __ |_|
|
||||
* | |\/| |/ _` | '_ \ / _` |/ _` |/ _ \ '__|
|
||||
* | | | | (_| | | | | (_| | (_| | __/ |
|
||||
* |_| |_|\__,_|_| |_|\__,_|\__, |\___|_|
|
||||
* __/ |
|
||||
* |___/
|
||||
*
|
||||
* copyright 2022 |
||||
* |
||||
* |
||||
* |
||||
* |
||||
* Documentation: https://wiki.asterisk.org/wiki/download/attachments/19005471/Asterisk-17-Reference.pdf?version=1&modificationDate=1582306810980&api=v2
|
||||
*
|
||||
* |
||||
*/ |
||||
|
||||
|
||||
#include <main.h> |
||||
#include <string.h> |
||||
#include <frame/frame_asterisk.h> |
||||
#include <queue/queue.h> |
||||
#include <parse_actions.h> |
||||
#include <methods_actions.h> |
||||
#include <string_functions.h> |
||||
#include <stdlib.h> |
||||
|
||||
|
||||
int parse_event_queueparams( EVENT *event, s_manager *smanager ){ |
||||
|
||||
/* Event: QueueParams
|
||||
* Queue: FINANCEIRO_SIMPLES |
||||
* Max: 0 |
||||
* Strategy: ringall |
||||
* Calls: 0 |
||||
* Holdtime: 4 |
||||
* TalkTime: 67 |
||||
* Completed: 5 |
||||
* Abandoned: 3 |
||||
* ServiceLevel: 60 |
||||
* ServicelevelPerf: 100.0 |
||||
* Weight: 0 |
||||
* |
||||
*---------------------------- |
||||
* |
||||
* Queue ------- Nome da fila |
||||
* Max -------- Quantidades de chamadas permitidas. 0 ilimitado |
||||
* Strategy --- Estratégia da fila |
||||
* Calls ------ Número de chamadas atualmente esperando em fila |
||||
* Holdtime --- uma média de tempo de espera para chamadas que foram atendidas segundos |
||||
* TalkTime --- tempo que estão conectado (falando) |
||||
* Completed -- chamadas completadas na fila |
||||
* Abandoned -- chamadas abandonadas na fila |
||||
* ServiceLevel -- serviço primário métrica de performance |
||||
* ServicelevelPerf ---serviço segundario métric de perfomance |
||||
* Weight |
||||
*
|
||||
*
|
||||
* strategy - ringall ----- ring all available channels until one answers (default) |
||||
* leastrecent - ring interface which was least recently hung up by this queue |
||||
* fewestcalls - ring the one with fewest completed calls from this queue |
||||
* random ------ ring random interface |
||||
* rrmemory ---- round robin with memory, remember where we left off last ring pass |
||||
* rrordered --- same as rrmemory, except the queue member order from config fileis preserved |
||||
* linear ------ rings interfaces in the order specified in this configuration file. |
||||
* If you use dynamic members, the members will be rung in the order in |
||||
* which they were added |
||||
* wrandom ----- rings random interface, but uses the member's penalty as a weight |
||||
* when calculating their metric. So a member with penalty 0 will have |
||||
* a metric somewhere between 0 and 1000, and a member with penalty 1 will |
||||
* have a metric between 0 and 2000, and a member with penalty 2 will have |
||||
* a metric between 0 and 3000. Please note, if using this strategy, the member |
||||
* penalty is not the same as when using other queue strategies. It is ONLY used |
||||
* as a weight for calculating metric. |
||||
* |
||||
*/ |
||||
|
||||
const char *queue_name, *max, *strategy,
|
||||
*calls_waiting, *holdtime, *talktime, |
||||
*completed, *abandoned; |
||||
unsigned int i_max = 0, i_calls_waiting = 0, i_holdtime = 0, i_talktime = 0, i_completed = 0, i_abandoned = 0; |
||||
|
||||
queue_name = ami_get_value( smanager->ami, event->args, "Queue" ); |
||||
if(!queue_name){ goto fail;} |
||||
|
||||
max = ami_get_value( smanager->ami, event->args, "Max" ); |
||||
if(!max){ goto fail;} |
||||
i_max = atoi(max); |
||||
|
||||
strategy = ami_get_value( smanager->ami, event->args, "Strategy" ); |
||||
if(!strategy){ goto fail;} |
||||
|
||||
calls_waiting = ami_get_value( smanager->ami, event->args, "Calls" ); |
||||
if(!calls_waiting) { goto fail;} |
||||
i_calls_waiting = atoi(calls_waiting); |
||||
|
||||
holdtime = ami_get_value( smanager->ami, event->args, "Holdtime" ); |
||||
if(!holdtime){ goto fail;} |
||||
i_holdtime = atoi(holdtime); |
||||
|
||||
talktime = ami_get_value( smanager->ami, event->args, "Talktime" ); |
||||
if(!talktime){ goto fail;} |
||||
i_talktime = atoi(talktime); |
||||
|
||||
completed = ami_get_value( smanager->ami, event->args, "Completed" ); |
||||
if(!completed){ goto fail;} |
||||
i_completed = atoi(completed); |
||||
|
||||
abandoned = ami_get_value( smanager->ami, event->args, "Abandoned" ); |
||||
if(!abandoned){ goto fail;} |
||||
i_abandoned = atoi(abandoned); |
||||
|
||||
{ // banco de dados
|
||||
struct s_table_queue *table_queue = get_queueparams_db( Select_queueparams, queue_name ); |
||||
|
||||
if( table_queue ){ |
||||
if( strcmp(table_queue->strategy, strategy) || |
||||
table_queue->hold_time != i_holdtime || |
||||
table_queue->talk_time != i_talktime || |
||||
table_queue->calls_completed != i_completed || |
||||
table_queue->calls_abandoned != i_abandoned || |
||||
table_queue->calls_waiting != i_calls_waiting || |
||||
table_queue->calls_limit != i_max) { |
||||
|
||||
if( update_queueparams_db( Update_queueparams, strategy, i_holdtime, i_talktime, i_completed, i_abandoned, i_max, i_calls_waiting, table_queue->queue_id ) == -1){ |
||||
goto fail; |
||||
} |
||||
} |
||||
} |
||||
else { |
||||
if( insert_queueparams_db( Insert_queueparams, queue_name, strategy, i_holdtime, i_talktime, i_completed, i_abandoned, i_max, i_calls_waiting ) == -1){ |
||||
goto fail; |
||||
} |
||||
} |
||||
} |
||||
|
||||
{ // camada de persistência
|
||||
|
||||
/* struct s_queue {
|
||||
* unsigned long long id; |
||||
* char *queue_name; |
||||
* char *queue_number; |
||||
* char *strategy; |
||||
* unsigned int hold_time; |
||||
* unsigned int talk_time; |
||||
* unsigned int calls_completed; |
||||
* unsigned int calls_abandoned; |
||||
* unsigned int calls_limit; |
||||
* unsigned int calls_waiting; |
||||
* struct s_queue_member *member;
|
||||
* struct s_queue *next; |
||||
* }; |
||||
*/ |
||||
|
||||
struct s_queue *queue; |
||||
queue = get_queue(queue_name); |
||||
if(queue){ |
||||
if( strcmp_n(queue->strategy, strategy) ){ |
||||
free(queue->strategy); |
||||
newstrncpy(&queue->strategy, strategy); |
||||
} |
||||
|
||||
if( queue->hold_time != i_holdtime ){ |
||||
queue->hold_time = i_holdtime; |
||||
} |
||||
|
||||
if( queue->talk_time != i_talktime ){ |
||||
queue->talk_time = i_talktime; |
||||
} |
||||
|
||||
if( queue->calls_completed != i_completed ){ |
||||
queue->calls_completed = i_completed; |
||||
} |
||||
|
||||
if( queue->calls_abandoned != i_abandoned ){ |
||||
queue->calls_abandoned = i_abandoned; |
||||
} |
||||
|
||||
if( queue->calls_limit != i_max ){ |
||||
queue->calls_limit = i_max; |
||||
} |
||||
|
||||
if( queue->calls_waiting != i_calls_waiting ){ |
||||
queue->calls_waiting = i_calls_waiting; |
||||
} |
||||
} |
||||
|
||||
else { |
||||
queue = create_queue(); |
||||
newstrncpy(&queue->queue_name, queue_name); |
||||
newstrncpy(&queue->strategy, strategy); |
||||
|
||||
queue->hold_time = i_holdtime; |
||||
queue->talk_time = i_talktime; |
||||
queue->calls_completed = i_completed; |
||||
queue->calls_abandoned = i_abandoned; |
||||
queue->calls_limit = i_max; |
||||
queue->calls_waiting = i_calls_waiting; |
||||
|
||||
insert_queue(queue); |
||||
} |
||||
|
||||
} |
||||
|
||||
return 1; |
||||
|
||||
fail: |
||||
return -1; |
||||
} |
||||
|
||||
|
||||
|
||||
int parse_event__queuemember( EVENT *event, s_manager *smanager ){ |
||||
|
||||
/*
|
||||
* Queue - O nome da fila |
||||
* Name - ramal membro da fila |
||||
* Location - O canal membro da fila ou localização |
||||
* StateInterface - tecnologia do canal ou localização que ler estado do dispositivo. |
||||
* Membership
|
||||
* { |
||||
* dynamic |
||||
* realtime |
||||
* static |
||||
* } |
||||
* Penalty - O penalidade associado com membro da fila |
||||
* CallsTaken - O número de chamada que esse membro da fila tem participado |
||||
* LastCall - A hora em que esse membro atendeu pela última vez, expressa em segundos desde 00:00 de 1º de janeiro de 1970 UTC. |
||||
* InCall - Defini 1 se o membro está em uma chamada. Defini para 0 depois se não está, LastCall é atualizado. |
||||
* { |
||||
* 0 |
||||
* 1 |
||||
* } |
||||
* Status - O estado do dispositivo do membro da fila |
||||
* { |
||||
* 0 - AST_DEVICE_UNKNOWN |
||||
* 1 - AST_DEVICE_NOT_INUSE |
||||
* 2 - AST_DEVICE_INUSE |
||||
* 3 - AST_DEVICE_BUSY |
||||
* 4 - AST_DEVICE_INVALID |
||||
* 5 - AST_DEVICE_UNAVAILABLE |
||||
* 6 - AST_DEVICE_RINGING |
||||
* 7 - AST_DEVICE_RINGINUSE |
||||
* 8 - AST_DEVICE_ONHOLD |
||||
* } |
||||
* Paused |
||||
* { |
||||
* 0 |
||||
* 1 |
||||
* } |
||||
*
|
||||
*/ |
||||
|
||||
/*
|
||||
* Penalidade - Se a estratégia é definida como 'ringall', apenas esses dispositivos membros com o baixo prioridade irá
|
||||
* tocar. Examplo, se 200 não é ocupado, então apenas 200 vai tocar. Se 200 está ocupado, então apenas 201 e 203 vai tocar. |
||||
* Se 200, 201 e 203 estão ocupado, então apenas 202 vai tocar. |
||||
*
|
||||
*/ |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
return 1; |
||||
} |
||||
|
||||
|
||||
|
@ -0,0 +1,66 @@
|
||||
/***
|
||||
* _____ _ _ _____
|
||||
* / ____(_) | | |_ _|
|
||||
* | (___ _ _ __ ___ _ __ | | ___ ___ | | _ __
|
||||
* \___ \| | '_ ` _ \| '_ \| |/ _ \/ __| | | | '_ \
|
||||
* ____) | | | | | | | |_) | | __/\__ \ _| |_| |_) | |
||||
* |_____/|_|_| |_| |_| .__/|_|\___||___/ |_____| .__/
|
||||
* | \/ | | | | |
|
||||
* | \ / | __ _ _ __ |_|_ _ __ _ ___ _ __ |_|
|
||||
* | |\/| |/ _` | '_ \ / _` |/ _` |/ _ \ '__|
|
||||
* | | | | (_| | | | | (_| | (_| | __/ |
|
||||
* |_| |_|\__,_|_| |_|\__,_|\__, |\___|_|
|
||||
* __/ |
|
||||
* |___/
|
||||
*
|
||||
* copyright 2022 |
||||
* |
||||
*
|
||||
*/ |
||||
|
||||
#ifndef QUEUE |
||||
#define QUEUE 1 |
||||
|
||||
#include <main.h> |
||||
#include <database/database.h> |
||||
#include <ami_c.h> |
||||
|
||||
|
||||
struct s_table_queue { |
||||
|
||||
unsigned long long int queue_id; |
||||
char *queue_name; |
||||
char *queue_number; |
||||
char *strategy; |
||||
unsigned long long int hold_time; |
||||
unsigned long long int talk_time; |
||||
unsigned long long int calls_completed; |
||||
unsigned long long int calls_abandoned; |
||||
unsigned int calls_limit; |
||||
unsigned int calls_waiting; |
||||
|
||||
struct s_table_queue *next; |
||||
}; |
||||
|
||||
|
||||
int parse_event_queueparams( EVENT *event, s_manager *smanager ); |
||||
int add_table_queue( struct s_table_queue **D, struct s_table_queue *next ); |
||||
|
||||
int free_table_queue(struct s_table_queue **D); |
||||
|
||||
struct s_table_queue *get_queueparams_db( stmt_t type_stmt, const char *queue_name ); |
||||
|
||||
int update_queueparams_db(stmt_t type_stmt, const char *strategy, unsigned long long int i_holdtime,
|
||||
unsigned long long int i_talktime, unsigned long long int i_completed,
|
||||
unsigned long long int i_abandoned, unsigned long long int i_max,
|
||||
unsigned long long int i_calls_waiting, unsigned long long int queu_id); |
||||
int insert_queueparams_db(stmt_t type_stmt, const char *queue_name, const char *strategy,
|
||||
unsigned long long int i_holdtime, unsigned long long int i_talktime,
|
||||
unsigned long long int i_completed, unsigned long long int i_abandoned,
|
||||
unsigned long long int i_max, unsigned long long int i_calls_waiting ); |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
#endif |
@ -0,0 +1,192 @@
|
||||
#include <database/database.h> |
||||
#include <queue/queue.h> |
||||
#include <stdlib.h> |
||||
#include <stddef.h> |
||||
#include <string_functions.h> |
||||
|
||||
|
||||
/* valores tabela queue */ |
||||
int add_table_queue( struct s_table_queue **D, struct s_table_queue *next ){ |
||||
|
||||
while(*D){ |
||||
D = &(*D)->next; |
||||
} |
||||
|
||||
(*D) = next; |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
|
||||
/* liberar ponteiro da tabela */ |
||||
int free_table_queue(struct s_table_queue **D){ |
||||
|
||||
if((*D) == NULL) |
||||
return 0; |
||||
|
||||
free_table_queue(&(*D)->next); |
||||
|
||||
free((*D)->queue_name); |
||||
free((*D)->queue_number); |
||||
free((*D)->strategy); |
||||
free(*D); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
|
||||
struct s_table_queue *get_queueparams_db( stmt_t type_stmt, const char *queue_name ){ |
||||
// "select queue_id, queue_name, strategy, hold_time, talk_time, calls_completed, calls_abandoned, calls_limit, calls_waiting FROM queue where queue_name = ?;", NULL},
|
||||
|
||||
MYSQL_STMT *stmt; |
||||
stmt = get_stmt(type_stmt); |
||||
if(!stmt){ |
||||
return NULL; |
||||
} |
||||
|
||||
pthread_mutex_lock(&m_db); |
||||
|
||||
MARIADB_BIND *bind = create_bind_manager( 1 ); |
||||
set_in_mariadb_column(&bind[0], ARG_STR_DB((char *)queue_name), (char *)queue_name, 0, isNULL(queue_name)); |
||||
|
||||
if(mariadb_stmt_execute(stmt, bind) == -1){ |
||||
goto fail; |
||||
} |
||||
|
||||
MARIADB_BIND *bind_result; |
||||
bind_result = get_bind_result(stmt); |
||||
|
||||
struct s_table_queue *table_queue = NULL, *table_queue_next = NULL; |
||||
int returnf = 0; |
||||
while(1){ |
||||
returnf = mysql_stmt_fetch(stmt); |
||||
|
||||
if(returnf == 1 || returnf == MYSQL_NO_DATA){ |
||||
break; |
||||
} |
||||
|
||||
|
||||
table_queue_next = (struct s_table_queue *) calloc(1, sizeof(struct s_table_queue)); |
||||
if(!table_queue_next){ break; } |
||||
table_queue_next->next = NULL; |
||||
|
||||
/* column queue_id */ |
||||
table_queue_next->queue_id = *(unsigned long long int *)bind_result[0].buffer; |
||||
|
||||
/* columns queue_name */ |
||||
newstrncpy(&table_queue_next->queue_name, bind_result[1].buffer); |
||||
|
||||
/* columns queue_name */ |
||||
newstrncpy(&table_queue_next->strategy, bind_result[2].buffer); |
||||
|
||||
/* columns hold_time */ |
||||
table_queue_next->hold_time = *(int *)bind_result[3].buffer; |
||||
|
||||
/* columns talk_time */ |
||||
table_queue_next->talk_time = *(int *)bind_result[4].buffer; |
||||
|
||||
/* columns calls_completed */ |
||||
table_queue_next->calls_completed = *(int *)bind_result[5].buffer; |
||||
|
||||
/* columns calls_abandoned */ |
||||
table_queue_next->calls_abandoned = *(int *)bind_result[6].buffer; |
||||
|
||||
/* columns calls_limit */ |
||||
table_queue_next->calls_limit = *(int *)bind_result[7].buffer; |
||||
|
||||
/* columns calls_waiting */ |
||||
table_queue_next->calls_waiting = *(int *)bind_result[8].buffer; |
||||
|
||||
add_table_queue(&table_queue, table_queue_next); |
||||
} |
||||
|
||||
destroy_bind_manager(bind_result); |
||||
|
||||
pthread_mutex_unlock(&m_db); |
||||
return table_queue; |
||||
|
||||
fail: |
||||
return NULL; |
||||
|
||||
} |
||||
|
||||
|
||||
int update_queueparams_db(stmt_t type_stmt, const char *strategy, unsigned long long int i_holdtime,
|
||||
unsigned long long int i_talktime, unsigned long long int i_completed,
|
||||
unsigned long long int i_abandoned, unsigned long long int i_max,
|
||||
unsigned long long int i_calls_waiting, unsigned long long int queue_id) { |
||||
MYSQL_STMT *stmt; |
||||
stmt = get_stmt(type_stmt); |
||||
if(!stmt){ |
||||
return -1; |
||||
} |
||||
|
||||
pthread_mutex_lock(&m_db); |
||||
|
||||
MARIADB_BIND *bind = create_bind_manager( 8 ); |
||||
|
||||
set_in_mariadb_column(&bind[0], ARG_STR_DB(strategy), (char *)strategy, 0, isNULL(strategy)); |
||||
set_in_mariadb_column(&bind[1], MYSQL_TYPE_LONGLONG, &i_holdtime, 1, 0); |
||||
set_in_mariadb_column(&bind[2], MYSQL_TYPE_LONGLONG, &i_talktime, 1, 0); |
||||
set_in_mariadb_column(&bind[3], MYSQL_TYPE_LONGLONG, &i_completed, 1, 0); |
||||
set_in_mariadb_column(&bind[4], MYSQL_TYPE_LONGLONG, &i_abandoned, 1, 0); |
||||
set_in_mariadb_column(&bind[5], MYSQL_TYPE_LONG, &i_max, 0, 0); |
||||
set_in_mariadb_column(&bind[6], MYSQL_TYPE_LONGLONG, &i_calls_waiting, 0, 0); |
||||
set_in_mariadb_column(&bind[7], MYSQL_TYPE_LONGLONG, &queue_id, 1, 0); |
||||
|
||||
|
||||
if(mariadb_stmt_execute(stmt, bind) == -1){ |
||||
goto fail; |
||||
} |
||||
|
||||
int result = (int)mysql_stmt_affected_rows(stmt); |
||||
|
||||
pthread_mutex_unlock(&m_db); |
||||
return result; |
||||
|
||||
fail: |
||||
pthread_mutex_unlock(&m_db); |
||||
return -1; |
||||
} |
||||
|
||||
|
||||
int insert_queueparams_db(stmt_t type_stmt, const char *queue_name, const char *strategy,
|
||||
unsigned long long int i_holdtime, unsigned long long int i_talktime,
|
||||
unsigned long long int i_completed, unsigned long long int i_abandoned,
|
||||
unsigned long long int i_max, unsigned long long int i_calls_waiting ){ |
||||
|
||||
MYSQL_STMT *stmt; |
||||
stmt = get_stmt(type_stmt); |
||||
if(!stmt){ |
||||
return -1; |
||||
} |
||||
|
||||
pthread_mutex_lock(&m_db); |
||||
|
||||
MARIADB_BIND *bind = create_bind_manager( 8 ); |
||||
|
||||
set_in_mariadb_column(&bind[0], ARG_STR_DB(queue_name), (char *)queue_name, 0, isNULL(queue_name)); |
||||
set_in_mariadb_column(&bind[1], ARG_STR_DB(strategy), (char *)strategy, 0, isNULL(strategy)); |
||||
set_in_mariadb_column(&bind[2], MYSQL_TYPE_LONGLONG, &i_holdtime, 1, 0); |
||||
set_in_mariadb_column(&bind[3], MYSQL_TYPE_LONGLONG, &i_talktime, 1, 0); |
||||
set_in_mariadb_column(&bind[4], MYSQL_TYPE_LONGLONG, &i_completed, 1, 0); |
||||
set_in_mariadb_column(&bind[5], MYSQL_TYPE_LONGLONG, &i_abandoned, 1, 0); |
||||
set_in_mariadb_column(&bind[6], MYSQL_TYPE_LONG, &i_max, 0, 0); |
||||
set_in_mariadb_column(&bind[7], MYSQL_TYPE_LONGLONG, &i_calls_waiting, 0, 0); |
||||
|
||||
if(mariadb_stmt_execute(stmt, bind) == -1){ |
||||
goto fail; |
||||
} |
||||
|
||||
int result = (int)mysql_stmt_affected_rows(stmt); |
||||
|
||||
pthread_mutex_unlock(&m_db); |
||||
return result; |
||||
|
||||
fail: |
||||
pthread_mutex_unlock(&m_db); |
||||
return -1; |
||||
} |
||||
|
||||
|
@ -0,0 +1,226 @@
|
||||
#include <string_functions.h> |
||||
#include <stddef.h> |
||||
#include <string.h> |
||||
#include <stdlib.h> |
||||
#include <stdio.h> |
||||
#include <errno.h> |
||||
#include <stdarg.h> |
||||
#include <log/log.h> |
||||
|
||||
|
||||
/*!
|
||||
* strcpy_s é similar ao strcpy, porém verifica se tem |
||||
* |
||||
*/ |
||||
void strcpy_s(const char *str, char **event_name, char *p_end){ |
||||
|
||||
size_t bytes = strlen_event(str, p_end, 0); |
||||
if(bytes == 0){ |
||||
event_name[0] = NULL; |
||||
return; |
||||
} |
||||
|
||||
event_name[0] = alloc(1, bytes + 1); |
||||
|
||||
strncpy(event_name[0], str, bytes); |
||||
|
||||
event_name[0][bytes] = '\0'; |
||||
|
||||
} |
||||
|
||||
|
||||
/*!
|
||||
* O mesmo que strcpy, porém usa alloc (função usa calloc e também
|
||||
* verifica se houve erro para mandar ao log) |
||||
* \param new_str |
||||
* \param str |
||||
* \return new_str o |
||||
*/ |
||||
char *newstrncpy( char **new_str, const char *str){ |
||||
|
||||
if(!str){ |
||||
new_str[0] = NULL; |
||||
return new_str[0]; |
||||
} |
||||
|
||||
|
||||
size_t bytes = strlen_n(str); |
||||
if(bytes == 0 || bytes == 1){ |
||||
new_str[0] = NULL; |
||||
return new_str[0]; |
||||
} |
||||
|
||||
new_str[0] = alloc(1, bytes + 1); |
||||
|
||||
strncpy( new_str[0], str, bytes); |
||||
|
||||
new_str[0][bytes] = '\0'; |
||||
|
||||
return new_str[0]; |
||||
} |
||||
|
||||
int strcasecmp_n(const char *str1, const char *str2){ |
||||
|
||||
if(str1 == NULL && str2 == NULL ){ |
||||
return 0; |
||||
} |
||||
else if(str1 == NULL){ |
||||
return -1; |
||||
} |
||||
else if(str2 == NULL){ |
||||
return 1; |
||||
} |
||||
else { |
||||
return strncasecmp(str1, str2, (strlen_n(str1) > strlen_n(str2) ? strlen_n(str1) : strlen_n(str2))); |
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
int strcmp_n(const char *str1, const char *str2){ |
||||
|
||||
if(str1 == NULL && str2 == NULL ){ |
||||
return 0; |
||||
} |
||||
else if(str1 == NULL){ |
||||
return -1; |
||||
} |
||||
else if(str2 == NULL){ |
||||
return 1; |
||||
} |
||||
else { |
||||
return strncmp(str1, str2, (strlen_n(str1) > strlen_n(str2) ? strlen_n(str1) : strlen_n(str2))); |
||||
} |
||||
} |
||||
|
||||
size_t strlen_n(const char *str1){ |
||||
if(!str1){ |
||||
return 0; |
||||
} |
||||
|
||||
return strlen(str1); |
||||
} |
||||
|
||||
/*
|
||||
* copia string |
||||
* str = [str | dest] |
||||
*/ |
||||
char *str_cpy_in(char *dest, const char *str){ |
||||
|
||||
size_t len_str, len_dest; |
||||
|
||||
len_str = strlen_n(str); |
||||
len_dest = strlen_n(dest); |
||||
|
||||
char tmp[len_dest + 1]; |
||||
strncpy( tmp, dest, len_dest); |
||||
|
||||
dest = realloc(dest, len_dest + len_str + 1); |
||||
if(!dest){ |
||||
printf("não foi possível allocar - line %s - %d\n", __FILE__, __LINE__); |
||||
return NULL; |
||||
} |
||||
|
||||
memset(dest, 0, len_dest + len_str); |
||||
|
||||
strncpy( dest, str, len_str + 1 ); |
||||
|
||||
strncat( dest, tmp, len_dest ); |
||||
|
||||
dest[len_dest + len_str] = '\0'; |
||||
|
||||
return dest; |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
char *strnstr(const char *s, const char *find, size_t slen){ |
||||
char c, sc; |
||||
size_t len; |
||||
|
||||
if ((c = *find++) != '\0') { |
||||
len = strlen(find); |
||||
do { |
||||
do { |
||||
if (slen-- < 1 || (sc = *s++) == '\0') |
||||
return (NULL); |
||||
} while (sc != c); |
||||
if (len > slen) |
||||
return (NULL); |
||||
} while (strncmp(s, find, len) != 0); |
||||
s--; |
||||
} |
||||
|
||||
return ((char *)s); |
||||
} |
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
size_t strlen_event(const char *str, char *p_end, int use_char){ |
||||
|
||||
size_t len_str = 0; |
||||
|
||||
if(use_char == 0){ |
||||
while(*str && str != p_end){ |
||||
++len_str; |
||||
++str; |
||||
} |
||||
} |
||||
else if(use_char == 1){ |
||||
while(*str && *str != *p_end){ |
||||
++len_str; |
||||
++str; |
||||
} |
||||
} |
||||
|
||||
return len_str; |
||||
} |
||||
|
||||
|
||||
void *alloc(size_t nmemb, size_t size){ |
||||
char *p = NULL; |
||||
p = calloc(nmemb, size); |
||||
|
||||
if (p == NULL){ |
||||
_EMERG("Não há memória disponível: %s", strerror(errno)); |
||||
return NULL; |
||||
} |
||||
|
||||
return (void *)p; |
||||
} |
||||
|
||||
|
||||
|
||||
char *verify_device(const char *name, int isqueue){ |
||||
|
||||
char *only_name = NULL; |
||||
|
||||
only_name = strstr(name, "Queue:"); |
||||
if(only_name) return only_name + 6; |
||||
|
||||
only_name = strstr(name, "SIP/"); |
||||
if(only_name) return only_name + 4; |
||||
|
||||
only_name = strstr(name, "IAX2/"); |
||||
if(only_name) return only_name + 5; |
||||
|
||||
_NOTICE("AMI retornou devicestate-device: %s", name); |
||||
return NULL; |
||||
} |
||||
|
||||
|
||||
const char *get_parse_exten( const char *peer ){ |
||||
|
||||
char *exten = NULL; |
||||
|
||||
exten = strstr(peer, "/"); |
||||
if(exten) |
||||
return exten + 1; |
||||
|
||||
return exten; |
||||
} |
||||
|
@ -0,0 +1,23 @@
|
||||
|
||||
#ifndef STRING_FUNCTIONS_H |
||||
#define STRING_FUNCTIONS_H 1 |
||||
|
||||
#include <stddef.h> |
||||
|
||||
|
||||
void strcpy_s(const char *str, char **event_name, char *p_end); |
||||
char *newstrncpy( char **new_str, const char *str); |
||||
int strcasecmp_n(const char *str1, const char *str2); |
||||
int strcmp_n(const char *str1, const char *str2); |
||||
size_t strlen_n(const char *str1); |
||||
char *str_cpy_in(char *dest, const char *str); |
||||
char *strnstr(const char *s, const char *find, size_t slen); |
||||
void build_string(char *buf, ...); |
||||
int replace_char_null(char *str, char chr, size_t len); |
||||
size_t strlen_event(const char *str, char *p_end, int use_char); |
||||
void *alloc(size_t nmemb, size_t size); |
||||
char *verify_device(const char *name, int isqueue); |
||||
const char *get_parse_exten( const char *peer ); |
||||
|
||||
|
||||
#endif |
Loading…
Reference in new issue