Browse Source

Start ami_simplesip

dev
Rodgger 2 years ago
commit
02973373ff
  1. 4
      .gitignore
  2. 85
      Makefile
  3. 0
      build/delete-me
  4. 43
      etc/client_ami.conf
  5. 16
      info/structure
  6. 75
      install.sh
  7. 113
      src/agent/agent.c
  8. 20
      src/agent/agent.h
  9. 20
      src/agent/agent_db.c
  10. 0
      src/bridge/bridge.c
  11. 0
      src/channel/channel.c
  12. 794
      src/database/database.c
  13. 147
      src/database/database.h
  14. 993
      src/frame/frame_asterisk.c
  15. 261
      src/frame/frame_asterisk.h
  16. 309
      src/log/log.c
  17. 109
      src/log/log.h
  18. 441
      src/main.c
  19. 165
      src/main.h
  20. 157
      src/methods_actions.c
  21. 38
      src/methods_actions.h
  22. 267
      src/parse_actions.c
  23. 92
      src/parse_actions.h
  24. 92
      src/parse_events.c
  25. 69
      src/parse_events.h
  26. 436
      src/peer/peer.c
  27. 83
      src/peer/peer.h
  28. 508
      src/peer/peer_db.c
  29. 278
      src/queue/queue.c
  30. 66
      src/queue/queue.h
  31. 192
      src/queue/queue_db.c
  32. 226
      src/string_functions.c
  33. 23
      src/string_functions.h
  34. 12
      systemd/ami_simplesip.service

4
.gitignore vendored

@ -0,0 +1,4 @@
build/*.o
ami_simplesip

85
Makefile

@ -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
build/delete-me

43
etc/client_ami.conf

@ -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]

16
info/structure

@ -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

75
install.sh

@ -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´"

113
src/agent/agent.c

@ -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.
* 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;
}

20
src/agent/agent.h

@ -0,0 +1,20 @@
/***
* _____ _ _ _____
* / ____(_) | | |_ _|
* | (___ _ _ __ ___ _ __ | | ___ ___ | | _ __
* \___ \| | '_ ` _ \| '_ \| |/ _ \/ __| | | | '_ \
* ____) | | | | | | | |_) | | __/\__ \ _| |_| |_) |
* |_____/|_|_| |_| |_| .__/|_|\___||___/ |_____| .__/
* | \/ | | | | |
* | \ / | __ _ _ __ |_|_ _ __ _ ___ _ __ |_|
* | |\/| |/ _` | '_ \ / _` |/ _` |/ _ \ '__|
* | | | | (_| | | | | (_| | (_| | __/ |
* |_| |_|\__,_|_| |_|\__,_|\__, |\___|_|
* __/ |
* |___/
*
* copyright 2022
*
*/
int parse_event_agents( EVENT *event, s_manager *smanager );

20
src/agent/agent_db.c

@ -0,0 +1,20 @@
/***
* _____ _ _ _____
* / ____(_) | | |_ _|
* | (___ _ _ __ ___ _ __ | | ___ ___ | | _ __
* \___ \| | '_ ` _ \| '_ \| |/ _ \/ __| | | | '_ \
* ____) | | | | | | | |_) | | __/\__ \ _| |_| |_) |
* |_____/|_|_| |_| |_| .__/|_|\___||___/ |_____| .__/
* | \/ | | | | |
* | \ / | __ _ _ __ |_|_ _ __ _ ___ _ __ |_|
* | |\/| |/ _` | '_ \ / _` |/ _` |/ _ \ '__|
* | | | | (_| | | | | (_| | (_| | __/ |
* |_| |_|\__,_|_| |_|\__,_|\__, |\___|_|
* __/ |
* |___/
*
* copyright 2022
*
*/

0
src/bridge/bridge.c

0
src/channel/channel.c

794
src/database/database.c

@ -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;
}

147
src/database/database.h

@ -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

993
src/frame/frame_asterisk.c

@ -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
*
*/

261
src/frame/frame_asterisk.h

@ -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

309
src/log/log.c

@ -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);
}

109
src/log/log.h

@ -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

441
src/main.c

@ -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;
}

165
src/main.h

@ -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

157
src/methods_actions.c

@ -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;
}

38
src/methods_actions.h

@ -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

267
src/parse_actions.c

@ -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;
}

92
src/parse_actions.h

@ -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

92
src/parse_events.c

@ -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;
}

69
src/parse_events.h

@ -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

436
src/peer/peer.c

@ -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;
}

83
src/peer/peer.h

@ -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

508
src/peer/peer_db.c

@ -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;
}

278
src/queue/queue.c

@ -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;
}

66
src/queue/queue.h

@ -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

192
src/queue/queue_db.c

@ -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;
}

226
src/string_functions.c

@ -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;
}

23
src/string_functions.h

@ -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

12
systemd/ami_simplesip.service

@ -0,0 +1,12 @@
[Unit]
Description=Client asterisk AMI
After=network.target
[Service]
Type=forking
Restart=always
RestartSec=2
ExecStart=/usr/sbin/ami_simplesip
[Install]
WantedBy=multi-user.target
Loading…
Cancel
Save