Browse Source

Em repositório

master
Rodgger 2 years ago
commit
227dffd6f3
  1. 6
      .gitignore
  2. 2692
      Doxyfile
  3. 46
      Makefile
  4. 0
      obj/delete-me
  5. 434
      src/ami.c
  6. 249
      src/ami.h
  7. 314
      src/ami_simplesip.h
  8. 374
      src/asterisk.c
  9. 226
      src/asterisk.h
  10. 385
      src/net.c
  11. 134
      src/net.h
  12. 84
      src/parse_action.c
  13. 15
      src/parse_action.h
  14. 52
      src/parse_event.c
  15. 15
      src/parse_event.h
  16. 200
      src/parse_string.c
  17. 88
      src/parse_string.h

6
.gitignore vendored

@ -0,0 +1,6 @@
obj/*.o
doc
libami_c.so
libami_c.so.01

2692
Doxyfile

File diff suppressed because it is too large Load Diff

46
Makefile

@ -0,0 +1,46 @@
CC=gcc
NAME_LIBRARY=libami_c.so
DIR_OBJ=obj/
DIR_SRC=src/
IR_SRC=src/
CFLAGS =
OBJ=\
$(DIR_OBJ)parse_action.o \
$(DIR_OBJ)parse_event.o \
$(DIR_OBJ)parse_string.o \
$(DIR_OBJ)asterisk.o \
$(DIR_OBJ)net.o \
$(DIR_OBJ)ami.o
$(NAME_LIBRARY):$(OBJ)
$(CC) -shared -o $@ $^ -lpthread
$(DIR_OBJ)%.o: $(DIR_SRC)%.c
$(CC) -shared -fPIC -Wall -c -o $@ $< $(CFLAGS) -I$(DIR_SRC)
install:$(NAME_LIBRARY)
@cp libami_c.so /usr/local/lib/libami_c.so
@ln -s /usr/local/lib/libami_c.so /usr/lib/libami_c.so
$(info Copiado pra /usr/lib/libami_c.so)
.PHONY: clean
clean:
rm obj/*.o
.PHONY: uninstall
uninstall:
rm /usr/local/lib/libami_c.so
rm /usr/lib/libami_c.so

0
obj/delete-me

434
src/ami.c

@ -0,0 +1,434 @@
#include <ami.h>
#include <string.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdio.h>
#include <sys/time.h>
/*!
* Primeira função que deverá ser chamada. Essa função inicializa a estrutura necessária.\n
* \warning Não deve ser liberada diretamente esse ponteiro. Use a função close_ami.
* \return retorna NULL caso tenha erro
*/
AMI *init_ami(){
AMI *ami = calloc(1, sizeof(AMI));
if(!ami){
return NULL;
}
return ami;
}
/*!
* Essa função encerrará essa instância com ami. A memória será liberada dessa instância
* \return sucesso 0, falha -1
*/
int close_ami(AMI *ami){
return 0;
}
/*!
* A conexão com a AMI e algumas informações serão refeitas
* \return sucesso 0, falha -1
*/
int restart_ami(AMI *ami){
return 0;
}
/*!
* Defini as credenciais necessárias para fazer login com a ami
* \return sucesso 0, falha -1
*/
int set_credentials( AMI *ami, const char *username, const char *password ){
if(!username || !password){
return -1;
}
if(strlen(username) >= MAX_LEN_USERNAME){
return -1;
}
if(strlen(password) >= MAX_LEN_PASSWORD){
return -1;
}
strcpy(ami->credential.username, username);
strcpy(ami->credential.password, password);
return 0;
}
/*!
* defini o caminho para conectar ao ami
* \return sucesso 0, falha -1
*/
int set_net( AMI *ami, const char *address, int port ){
if(!address)
return -1;
if(strlen(address) >= MAX_LEN_ADDRESS){
return -1;
}
strcpy(ami->net.str_address, address);
ami->net.address = inet_addr(address);
ami->net.port = (port == 0 ? 5038 : port);
return 0;
}
/*!
* Começa o processo de conexão, obter informação e receber dados do ami
* \return sucesso 0, falha -1
*/
int ami (AMI *ami ){
net_start(ami);
return 0;
}
/*!
* Mostra a versão que essa instância está conectada. Ex: "13.38.1\0"
* \warning esse ponteiro não deve ser liberar.
*/
const char *show_version(AMI *ami){
return ami->asterisk.version.version;
}
/*!
* Mostra apenas o major da versão do asterisk. Ex: versão 13.38.1 -> 13 returno da função.
*
* \return sucesso major, falha -1
*/
int show_version_major(AMI *ami){
return ami->asterisk.version.major;
}
/*!
* Mostra apenas o minor da versão do asterisk. Ex versão 13.38.1 -> -> 38 returno da função.
* \return sucesso minor, falha -1
*/
int show_version_minor(AMI *ami){
return ami->asterisk.version.minor;
}
/*!
* Mostra apenas o minor2 da versão do asterisk. Ex versão 13.38.1 -> -> 1 returno da função.
* \return sucesso minor2, falha -1
*/
int show_version_minor2(AMI *ami){
return ami->asterisk.version.minor2;
}
/*!
* Retorna se o ami está ativado. Essa função retornará true se conseguir conectar ao ami.
* \return sucesso 0, falha -1
*/
int is_ami(AMI *ami){
return ami->asterisk.settings.subsystem.ami;
}
/*!
* Retorna se o ARA está ativado.
* \return sucesso 0, falha -1
*/
int is_ara(AMI *ami){
return ami->asterisk.settings.subsystem.ara;
}
/*!
* Retorna se o CDR está ativado.
* \return sucesso 0, falha -1
*
*/
int is_cdr(AMI *ami){
return ami->asterisk.settings.subsystem.cdr;
}
/*!
* Retorna quantidade de memória de acordo com o parâmetro.\n
* TOTAL_RAM = retorna total da memória
* FREE_RAM = retorna total livre
* BUFFER_RAM = retorna o total buffer
* TOTAL_SWAP = retorna total swap
* FREE_SWAP = retorna total swap livre
* \return sucesso >=0, falha -1
*/
int get_memory(AMI *ami, int type){
switch( type ){
case TOTAL_RAM:
return ami->asterisk.sysinfo.total_ram;
break;
case FREE_RAM:
return ami->asterisk.sysinfo.free_ram;
break;
case BUFFER_RAM:
return ami->asterisk.sysinfo.buffer_ram;
break;
case TOTAL_SWAP:
return ami->asterisk.sysinfo.total_swap_space;
break;
case FREE_SWAP:
return ami->asterisk.sysinfo.free_swap_space;
break;
default:
return 0;
break;
}
return 0;
}
/*!
* Retorna diretórios configurados de acordo com o parâmetro =
* CONFIG_FILE = arquivo de configuração
* CONFIG_DIR = diretório de configuração
* MODULE_DIR = diretório de módulos
* SPOOL_DIR = diretório spool
* LOG_DIR = diretório de logs
* RUN_SOCK_DIR = diretórios pid, ctl
* PID_FILE = arquivo pid
* VARLIB_DIR = diretórios de bibliotecas
* DATA_DIR = diretórios de dados
* ASTDB = armazena dados do banco interno do asterisk
* IAX_DIR = diretórios chaves utilizadas para autenticação
* AGI_DIR = diretório AGI que o asterisk procura por padrão
* \warning esse ponteiro não deve liberar.
* \return string ou NULL (NULL pode por diretório não definido pelo asterisk)
*/
const char *get_dir(AMI *ami, int type){
switch( type ){
case CONFIG_FILE:
return ami->asterisk.settings.dir.config_file;
break;
case CONFIG_DIR:
return ami->asterisk.settings.dir.config_dir;
break;
case MODULE_DIR:
return ami->asterisk.settings.dir.module_dir;
break;
case SPOOL_DIR:
return ami->asterisk.settings.dir.spool_dir;
break;
case LOG_DIR:
return ami->asterisk.settings.dir.log_dir;
break;
case RUN_SOCK_DIR:
return ami->asterisk.settings.dir.run_sock_dir;
break;
case PID_FILE:
return ami->asterisk.settings.dir.pid_file;
break;
case VARLIB_DIR:
return ami->asterisk.settings.dir.varlib_dir;
break;
case DATA_DIR:
return ami->asterisk.settings.dir.data_dir;
break;
case ASTDB:
return ami->asterisk.settings.dir.astdb;
break;
case IAX_DIR:
return ami->asterisk.settings.dir.iax_dir;
break;
case AGI_DIR:
return ami->asterisk.settings.dir.agi_dir;
break;
default:
return NULL;
break;
}
return NULL;
}
/*!
* A linguagem definida pelo asterisk
* \warning esse ponteiro não deve liberar.
* \return sucesso string, falha NULL
*/
int get_language(AMI *ami){
return ami->asterisk.settings.language;
}
/*!
* Qual o usuário do sistema que o asterisk está rodando
* \warning Esse ponteiro não deve ser liberar.
* \return nome do usuário
*/
const char *get_user(AMI *ami){
return ami->asterisk.settings.user;
}
/*!
* Retorna o grupo no qual o asterisk está execução
* \warning esse ponteiro não deve liberar.
* \return nome do grupo
*/
const char *get_group(AMI *ami){
return ami->asterisk.settings.group;
}
/*!
*
*
*/
int is_exec_includes(AMI *ami){
return ami->asterisk.settings.exec_includes;
}
/*!
* Retorna o socket dessa instância que está sendo usado
* \return socket(int)
*/
int get_socket(AMI *ami){
return ami->net.sock;
}
/*!
* Está connectado ao ami do asterisk.\n
* Caso não esteja conectado, a biblioteca continuará tentando conectar. A biblioteca irá parar de tentar conectar com a função close_ami.
* \return connectado 1, falha -1
*/
int is_connected(AMI *ami){
return ami->net.is_connected;
}
/*!
* Verifica se a comunicação está com login sucesso. Retorna 0 a biblioteca tentará fazer o mesmo login. Para parar as tentativas use função close_ami.
* \return sucesso 0, falha -1
*/
int is_logged(AMI *ami){
return ami->asterisk.is_logged;
}
/*!
* Envia a action que está na struct
* \return sucesso actionid, fail -1
*/
int send_action(AMI *ami, struct ss_action *action ){
int return_send = 0;
const char *str_action = NULL;
str_action = build_str_action(action);
actionid_add(&ami->asterisk.list_actionid, action->args[0].value);
return_send = dispatch_action(ami, str_action);
str_action_free((char *)str_action);
if(return_send == -1){
actionid_remove(&ami->asterisk.list_actionid, action->args[0].value);
}
return return_send;
}
/*!
* Cria uma nova estrutura e essa estrutura é usado para criar e mandar action. A actionid será criada com o primeiro argumento args[0].
* o args será acrescentada mais 1 para argumentos.
*
* struct s_args s_args_action {\n
* char key[MAX_LEN_KEY_ACTION];\n
* char value[MAX_LEN_VALUE_ACTION];\n
* };\n
* \n
* struct ss_action {\n
* char name_action[MAX_LEN_NAME_ACTION];\n
* int count_args;--- a quantidade de argumentos. action->args[0].key - actionid\n
* struct s_args *args;\n
* };\n
* Use destroy_action para liberar esse ponteiro
*
* \warning A actionid é de acordo com microseconds, portanto tome cuidado se for chamar várias vezes direto.
* \param args número de argumentos dessa action
*
* \return poteiro do tipo ss_action. A action será criada automaticamente na primeira posição dos argumentos
*/
struct ss_action *create_new_action(unsigned int args){
struct ss_action *action = NULL;
action = calloc(1, sizeof(struct ss_action));
action->args = calloc(args + 1, sizeof(struct ss_args));
struct timeval tv;
gettimeofday(&tv, NULL);
sprintf(action->args[0].key, "ActionID");
sprintf(action->args[0].value, "%ld.%ld", tv.tv_sec, tv.tv_usec);
action->count_args = args + 1;
return action;
}
/*!
* Libera ponteiro para para estrutura ss_action
* \return sucesso 0 sempre
*/
int destroy_action(struct ss_action *action){
free(action->args);
free(action);
return 0;
}

249
src/ami.h

@ -0,0 +1,249 @@
#ifndef AMI_H
#define AMI_H 1
#include <limits.h>
#include <time.h>
#include <pthread.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <ami_simplesip.h>
#define TYPE_EVENT 0x1
#define TIME_UPDATE_ASTERISK 60 /*!< tempo que a biblioteca vai atualizar informações do asterisk */
#define MAX_BUFFER_NET PATH_MAX /*!< O comprimento máximo que poderá obter através do recv */
/*!
* Estrutura armazena informações sobre sistema entregue pelo asterisk
* - core show sysinfo -
* dentro do ASTERISK
*/
struct s_sysinfo {
int total_ram; /*!< memória ram no sistema no qual asterisk está rodando */
int free_ram; /*!< memória ram livre no sistema no qual asterisk está rodando */
int buffer_ram; /*!< memória ram utilizada no sistema no qual asterisk está rodando */
int total_swap_space; /*!< memória swap no sistema no qual asterisk está rodando */
int free_swap_space; /*!< memória swap livre no sistema no qual asterisk está rodando */
int numprocs; /*!< número de processos rodando no sistema */
};
/*!
* Estrutura armazena informação de versão do asterisk
* core show version e core show settings
* dentro do ASTERISK
*/
struct s_version {
char *version; /*!< versão em string */
int major; /*!< versão major. Ex: 13.38.1 -> major = 13 */
int minor; /*!< versão minor. Ex: 13.38.1 - > minor = 38 */
int minor2; /*!< versão minor. Ex: 13.38.1 -> minor = 1 */
};
/*!
* Estrutura subsystem, armazena quais subsistema estão ativado
* ami = Asterisk Manager Interface
* cdr = call data record (call details record)
* ara = realtime architecture
* dentro da estrutura struct s_settings
*/
struct s_subsystem{
int ami:1; /*!< ami ativado. Sempre estará ativado.*/
int cdr:1; /*!< ativado ou desativado cdr*/
int ara:1; /*!< ativado ou desativado ara*/
};
/*!
* Estrutura de diretórios usado pelo asterisk
* Dentro da estrutura struct s_settings
*/
struct s_dir {
char config_file[PATH_MAX]; /*!< arquivo de configuração */
char config_dir[PATH_MAX]; /*!< diretório de configuração */
char module_dir[PATH_MAX]; /*!< diretório de módulos */
char spool_dir[PATH_MAX]; /*!< diretório de spool diretório de chamadas*/
char log_dir[PATH_MAX]; /*!< diretório de log */
char run_sock_dir[PATH_MAX]; /*!< diretórios socket e pid */
char pid_file[PATH_MAX]; /*!< arquivo mostra o pid do asterisk */
char varlib_dir[PATH_MAX]; /*!< biblioteca contendo dados usados em tempo de execução */
char data_dir[PATH_MAX]; /*!< arquivo contendo dados usados em tempo de execução */
char astdb[PATH_MAX]; /*!< armazenar arquivo do banco de dados internos do asterisk */
char iax_dir[PATH_MAX]; /*!< armazena arquivos das chaves utilizadas para autenticação */
char agi_dir[PATH_MAX]; /*!< scripts AGI que o asterisk procura por padrão */
};
/*
* Estrutura de configurações do asterisk
* - core show settings -
* Dentro do ASTERISK
*/
struct s_settings {
int language;
char *user;
char *group;
int exec_includes:1;
struct s_subsystem subsystem;
struct s_dir dir;
};
struct s_actionid {
char actionid[MAX_LEN_VALUE_ACTION];
struct s_actionid *next;
};
/*!
* Estrutura asterisk
* Dentro do AMI
*/
typedef struct s_asterisk {
struct s_version version; /*!< estrutura obtém versão do asterisk */
int calls_processed; /*!< chamadas processadas pelo asterisk */
struct tm uptime; /*!< tempo em execução */
struct tm last_reload; /*!< último reload */
struct s_sysinfo sysinfo; /*!< informação do sistema no qual asterisk está rodando */
struct s_settings settings; /*!< algumas configurações do asterisk */
int is_logged:1; /*!< */
int init_action:1; /*!< */
int time_update; /*!< */
int init_response:1; /*!< */
struct s_actionid *list_actionid;
struct s_actionid *list_intern_actionid;
} ASTERISK;
/*!
* Estrutura contém as informações de thread dessa instância
* Dentro AMI
*/
typedef struct s_thread {
pthread_t id_thread; /*!< identificador da thread */
} THREAD;
/*!
* Informações sobre comunicação
* Dentro AMI
*/
typedef struct s_net{
int address; /*!< endereço IPV4 da ami em binary */
char *str_address; /*!< endereço IPV4 da ami em ascii */
int port; /*!< número da porta que a ami está escutando */
struct sockaddr_in sock_addr; /*!< estrutura da rede linux */
char buffer_net[MAX_BUFFER_NET];
int sock; /*!< file descriptor, o socket */
int imcomplete_net:1;
int is_connected:1;
int timeout;
int q_ndata;
} NET;
/*!
* Informação sobre credenciais para fazer login no ami.
* Dentro AMI
*/
typedef struct s_credentials{
char *username; /*!< usuário do ami */
char *password; /*!< secret (password) do ami */
} CREDENTIAL;
/*!
* Estrutura dos dados que chegam da ami
* Ex:
*
* Event: event
* key: value
* key: value
*/
typedef struct s_args {
char *key; /*!< chave do argumento */
char *value; /*!< value do argumento */
struct s_args *next;
} ARGS;
/*!
* Estrutura de dados da resposta da AMI e suas chaves e valores
*/
typedef struct s_response {
char *response; /*!< valor da chave response no bloco */
ARGS *args; /*!< argumentos do bloco response */
int count; /*!< quantidade de argumentos */
} RESPONSE;
/*!
* informação do evento
*/
typedef struct s_event{
char *event; /*!< nome do evento */
ARGS *args; /*!< argumentos do evento */
int count; /*!< constagem do event. decrescente 1000 - 0 */
struct s_event *next;
} EVENT;
/*!
* informação da action recebida
* Dentro ami
*/
typedef struct s_action{
RESPONSE *response;
char *actionid;
EVENT *event;
struct s_action *next;
} ACTION;
/*!
* Estrutura principal para usar sobre ami.\n
* Essa estrutura será opaco para o user externo
*/
struct ami {
int error_code; /*!< erro no ami */
NET net; /*!< sobre a transmissão */
CREDENTIAL credential; /*!< credenciais do ami */
ACTION *actions; /*!< action recebido da ami. Respostas e event */
EVENT *events; /*!< event recebido da ami */
THREAD thread; /*!< informaçãos da thread em execução */
ASTERISK asterisk; /*!< informações relevantes do asterisk. Ex: memória, versão, diretórios . . . */
};
#include <ami_simplesip.h>
#include <parse_action.h>
#include <parse_event.h>
#include <parse_string.h>
#include <asterisk.h>
#include <net.h>
#endif

314
src/ami_simplesip.h

@ -0,0 +1,314 @@
#ifndef AMI_C_H
#define AMI_C_H 1
#define MAX_LEN_KEY_ACTION 50 /*!< maior comprimento permitido pelo chave no argumento */
#define MAX_LEN_VALUE_ACTION 256 /*!< maior comprimento permitido pelo valor da chave no argumento */
#define MAX_LEN_NAME_ACTION 50 /*!< maior comprimento permitido pelo nome de um action */
#define MAX_LEN_USERNAME 32 /*!< tamanho máximo que o username terá */
#define MAX_LEN_PASSWORD 64 /*!< tamanho máximo que o secret terá */
#define MAX_LEN_ADDRESS 15 /*!< texto ip. Ex: 10.100.100.10 */
struct ss_args {
char key[MAX_LEN_KEY_ACTION];
char value[MAX_LEN_VALUE_ACTION];
};
struct ss_action {
char name_action[MAX_LEN_NAME_ACTION];
int count_args;
struct s_args *args;
};
typedef struct ami AMI;
#define TOTAL_RAM 0x1
#define FREE_RAM 0x2
#define BUFFER_RAM 0x3
#define TOTAL_SWAP 0x4
#define FREE_SWAP 0x5
#define CONFIG_FILE 0x1
#define CONFIG_DIR 0x2
#define MODULE_DIR 0x3
#define SPOOL_DIR 0x4
#define LOG_DIR 0x5
#define RUN_SOCK_DIR 0x6
#define PID_FILE 0x7
#define VARLIB_DIR 0x8
#define DATA_DIR 0x9
#define ASTDB 0xa
#define IAX_DIR 0xb
#define AGI_DIR 0xc
/*!
* Primeira função que deverá ser chamada. Essa função inicializa a estrutura necessária.\n
* \warning Não deve ser liberada diretamente esse ponteiro. Use a função close_ami.
* \return retorna NULL caso tenha erro
*/
AMI *init_ami();
/*!
* Essa função encerrará essa instância com ami. A memória será liberada dessa instância
* \return sucesso 0, falha -1
*/
int close_ami(AMI *ami);
/*!
* A conexão com a AMI e algumas informações serão refeitas
* \return sucesso 0, falha -1
*/
int restart_ami(AMI *ami);
/*!
* Defini as credenciais necessárias para fazer login com a ami
* \return sucesso 0, falha -1
*/
int set_credentials( AMI *ami, const char *username, const char *password );
/*!
* defini o caminho para conectar ao ami
* \return sucesso 0, falha -1
*/
int set_net( AMI *ami, const char *address, int port );
/*!
* Começa o processo de conexão, obter informação e receber dados do ami
* \return sucesso 0, falha -1
*/
int ami (AMI *ami );
/*!
* Mostra a versão que essa instância está conectada. Ex: "13.38.1\0"
* \warning esse ponteiro não deve ser liberar.
*/
const char *show_version(AMI *ami);
/*!
* Mostra apenas o major da versão do asterisk. Ex: versão 13.38.1 -> 13 returno da função.
*
* \return sucesso major, falha -1
*/
int show_version_major(AMI *ami);
/*!
* Mostra apenas o minor da versão do asterisk. Ex versão 13.38.1 -> -> 38 returno da função.
* \return sucesso minor, falha -1
*/
int show_version_minor(AMI *ami);
/*!
* Mostra apenas o minor2 da versão do asterisk. Ex versão 13.38.1 -> -> 1 returno da função.
* \return sucesso minor2, falha -1
*/
int show_version_minor2(AMI *ami);
/*!
* Retorna se o ami está ativado. Essa função retornará true se conseguir conectar ao ami.
* \return sucesso 0, falha -1
*/
int is_ami(AMI *ami);
/*!
* Retorna se o ARA está ativado.
* \return sucesso 0, falha -1
*/
int is_ara(AMI *ami);
/*!
* Retorna se o CDR está ativado.
* \return sucesso 0, falha -1
*
*/
int is_cdr(AMI *ami);
/*!
* Retorna quantidade de memória de acordo com o parâmetro.\n
* TOTAL_RAM = retorna total da memória
* FREE_RAM = retorna total livre
* BUFFER_RAM = retorna o total buffer
* TOTAL_SWAP = retorna total swap
* FREE_SWAP = retorna total swap livre
* \return sucesso >=0, falha -1
*/
int get_memory(AMI *ami, int type);
/*!
* Retorna diretórios configurados de acordo com o parâmetro =
* CONFIG_FILE = arquivo de configuração
* CONFIG_DIR = diretório de configuração
* MODULE_DIR = diretório de módulos
* SPOOL_DIR = diretório spool
* LOG_DIR = diretório de logs
* RUN_SOCK_DIR = diretórios pid, ctl
* PID_FILE = arquivo pid
* VARLIB_DIR = diretórios de bibliotecas
* DATA_DIR = diretórios de dados
* ASTDB = armazena dados do banco interno do asterisk
* IAX_DIR = diretórios chaves utilizadas para autenticação
* AGI_DIR = diretório AGI que o asterisk procura por padrão
* \warning esse ponteiro não deve liberar.
* \return string ou NULL (NULL pode por diretório não definido pelo asterisk)
*/
const char *get_dir(AMI *ami, int type);
/*!
* A linguagem definida pelo asterisk
* \warning esse ponteiro não deve liberar.
* \return sucesso string, falha NULL
*/
int get_language(AMI *ami);
/*!
* Qual o usuário do sistema que o asterisk está rodando
* \warning Esse ponteiro não deve ser liberar.
* \return nome do usuário
*/
const char *get_user(AMI *ami);
/*!
* Retorna o grupo no qual o asterisk está execução
* \warning esse ponteiro não deve liberar.
* \return nome do grupo
*/
const char *get_group(AMI *ami);
/*!
*
*
*/
int is_exec_includes(AMI *ami);
/*!
* Retorna o socket dessa instância que está sendo usado
* \return socket(int)
*/
int get_socket(AMI *ami);
/*!
* Está connectado ao ami do asterisk.\n
* Caso não esteja conectado, a biblioteca continuará tentando conectar. A biblioteca irá parar de tentar conectar com a função close_ami.
* \return connectado 1, falha -1
*/
int is_connected(AMI *ami);
/*!
* Verifica se a comunicação está com login sucesso. Retorna 0 a biblioteca tentará fazer o mesmo login. Para parar as tentativas use função close_ami.
* \return sucesso 0, falha -1
*/
int is_logged(AMI *ami);
/*!
* Envia a action que está na struct
* \return sucesso actionid, fail -1
*/
int send_action(AMI *ami, struct ss_action *action );
/*!
* Cria uma nova estrutura e essa estrutura é usado para criar e mandar action. A actionid será criada com o primeiro argumento args[0].
* o args será acrescentada mais 1 para argumentos.
*
* struct s_args s_args_action {\n
* char key[MAX_LEN_KEY_ACTION];\n
* char value[MAX_LEN_VALUE_ACTION];\n
* };\n
* \n
* struct ss_action {\n
* char name_action[MAX_LEN_NAME_ACTION];\n
* int count_args;--- a quantidade de argumentos. action->args[0].key - actionid\n
* struct s_args *args;\n
* };\n
* Use destroy_action para liberar esse ponteiro
*
* \warning A actionid é de acordo com microseconds, portanto tome cuidado se for chamar várias vezes direto.
* \param args número de argumentos dessa action
*
* \return poteiro do tipo ss_action. A action será criada automaticamente na primeira posição dos argumentos
*/
struct ss_action *create_new_action(unsigned int args);
/*!
* Libera ponteiro para para estrutura ss_action
* \return sucesso 0 sempre
*/
int destroy_action(struct ss_action *action);
#endif

374
src/asterisk.c

@ -0,0 +1,374 @@
#include <ami.h>
#include <string.h>
/*!
* A função é usado para inicializar ami com métodos que retornarão informação ami ami
* \param ami estrutura geral sobre informações da ami (asterisk)
* \return sucesso 0, falha -1
*/
int init_methods( AMI *ami ){
struct ss_action *sysinfo = create_new_action(1);
strcpy(sysinfo->name_action, "command");
strcpy(sysinfo->args[1].key, "command");
strcpy(sysinfo->args[1].value, "core show sysinfo");
if(send_action(ami, sysinfo) == -1){
return -1;
}
struct ss_action *settings = create_new_action(1);
strcpy(settings->name_action, "command");
strcpy(settings->args[1].key, "command");
strcpy(settings->args[1].value, "core show settings");
if(send_action(ami, settings) == -1){
return -1;
}
return 0;
}
/*!
* Verifica se o evento continua esperando informação da AMI
*
* \param list_actions lista das actionid ativas, ou seja, esperando concluir a resposta
* \param actionid valor da actionid que será verificada
* \return sucesso 0, falha -1
*/
int is_actionid(struct s_actionid **list_actions, const char *actionid){
int bytes = strlen(actionid);
while(*list_actions){
if(!strncmp(actionid, (*list_actions)->actionid, (bytes < strlen((*list_actions)->actionid)) ? strlen((*list_actions)->actionid) : bytes)){
return 0;
}
list_actions = &(*list_actions)->next;
}
return -1;
}
/*!
* Adicionar novas actionid. A biblioteca obterá apenas actionid que estão nessa estrutura
*
* \param list_actions lista de actionid ativas
* \param actionid será adicionada na lista
*
* \return sucesso 0, falha -1
*/
int actionid_add(struct s_actionid **list_actions, const char *actionid){
while( (*list_actions) ){
list_actions = &(*list_actions)->next;
}
*list_actions = calloc(1, sizeof(struct s_actionid));
strcpy((*list_actions)->actionid, actionid);
return 0;
}
/*!
* remove a actionid da lista de actionid ativas. A biblioteca vai ignorar actionid que estão fora dessa estrutura.\n
* Apenas quando essa actionid for concluída
*
* \param list_actions lista de actionid ativas
* \param actionid actionid que será excluída da lista
*
* \return sucesso 0, falha -1
*/
int actionid_remove( struct s_actionid **list_actions, const char *actionid ){
struct s_actionid *drop_actionid = NULL;
while( (*list_actions) ){
if( !strcmp( (*list_actions)->actionid, actionid ) ){
drop_actionid = *list_actions;
actionid_free(drop_actionid);
*list_actions = (*list_actions)->next;
return 0;
}
}
return -1;
}
/*!
* Libera o actionid
* \param drop_actionid ponteiro para estrutura
* \return 0 sempre
*/
int actionid_free( struct s_actionid *drop_actionid ){
free(drop_actionid);
return 0;
}
////* EVENT *////
/*!
* Adicionar eventos lista de eventos da ami.
*
* \param event lista de eventos recebido do AMI
* \param next próximo evento que será incluído na lista de eventos
*
*/
void event_add(EVENT **event, EVENT *next){
while((*event)){
event = &(*event)->next;
}
*event = next;
}
/*!
* Cria a estrutura de um novo evento.
*
* \warning Esse ponteiro deve ser liberado através do free_event.
*
* \return p_event um novo espaço para alocar eventos da AMI
*/
EVENT *event_create(){
EVENT *p_event = calloc(1, sizeof(EVENT));
return p_event;
}
/*!
* Libera ponteiro do EVENT único e seus argumentos. Não vai liberar os próximos eventos "event->next"
*
* \param event estrutura que contém um evento da AMI
*/
void event_free( EVENT *event ){
free(event->event);
list_args_free(event->args);
free(event);
}
/*!
* Libera a lista do eventos da AMI
*
* \param event lista de eventos que serão liberadas
*/
void list_event_free(EVENT *event){
if(event->next){
list_event_free(event->next);
}
event_free(event);
}
////* ARGUMENTOS *////
/*!
* Adiciona o argumento dentro do evento
*
* \param event estrutura de evento que será
* \param arg
*
*/
void args_event_add(EVENT *event, struct s_args *arg){
struct s_args **args = &event->args;
while((*args)) {
args = &(*args)->next;
}
*args = arg;
}
/*!
* Adiciona argumento para estrutura RESPONSE
*
* \param args lista de argumentos
* \param arg argumento que será inserido
*/
void args_add( ARGS **args, ARGS *arg ){
while(*args){
args = &(*args)->next;
}
*args = arg;
}
/*!
* Cria uma estrutura para um argumento.
* \return arg estrutura do tipo struct s_args
*/
struct s_args *arg_create(){
struct s_args *arg = calloc(1, sizeof(struct s_args));
return arg;
}
/*!
* libera o ponteiro para estrutura do argumento.
* \param arg liberar ponteiro
*/
void args_free(ARGS *arg){
free(arg->key);
free(arg->value);
free(arg);
}
/*!
* libera lista de argumentos. O ponteiro atuais e membros next args->next
* \param args pointeiro para essa lista
*
*/
void list_args_free(ARGS *args){
if(args->next){
list_args_free(args->next);
}
args_free(args);
}
////* RESPONSE *////
/*!
* Cria estrutura RESPONSE
* \return response estrutura vazia que será usada para preencher resposta da AMI
*/
RESPONSE *response_create(){
RESPONSE *response;
response = calloc(1, sizeof(RESPONSE));
return response;
}
/*!
* Adiciona Response na estrutura Action
* \param action estrutura action
* \param response será adicionado para o ACtion
*/
void action_response_add(ACTION *action, RESPONSE *response){
if(!action->response){
action->response = response;
}
}
/*!
* Libera espaço do ponteiro da entrutura RESPONSE
* \param response estrutura response que será liberada
*/
int response_free(RESPONSE *response){
list_args_free(response->args);
free(response);
return 0;
}
////* ACTION *////
/*!
* criar estrutura para preenche-la com resposta da action
* \return ACTION nova estrutura ACTION
*/
ACTION *action_create(){
ACTION * action;
action = calloc(1, sizeof(ACTION));
return action;
}
/*!
* liberar uma action da estrutura
* \param action lista de actions
* \param toremove o action que será escluída da lista
* \return
*/
int action_remove(ACTION **list_action, ACTION *toremove){
while(*list_action){
if(*list_action == toremove){
ACTION *p = (*list_action);
(*list_action) = (*list_action)->next;
action_free(p);
}
}
return 0;
}
/*!
* libera toda a lista do action
* \param list_action lista das action
* \return 0
*/
int list_action_free(ACTION *list_action){
if(list_action){
list_action_free(list_action->next);
}
action_free(list_action);
return 0;
}
/*!
* libera action a estrutura action
* \param action ponteiro para estrutura action
* \return sempre sucesso 0
*/
int action_free(ACTION *action){
response_free(action->response);
free(action->actionid);
list_event_free(action->event);
free(action);
return 0;
}
/*!
* Adicionar action na lista de action
* \param action lista action
* \param next estrutura action que será inserida
* \return sucesso 0, falha -1
*/
int action_add(ACTION **action, ACTION *next){
while(*action){
action = &(*action)->next;
}
*action = next;
return 0;
}

226
src/asterisk.h

@ -0,0 +1,226 @@
#ifndef ASTERISK_H
#define ASTERISK_H 1
/*!
* A função é usado para inicializar ami com métodos que retornarão informação ami ami
* \param ami estrutura sobre informações da ami (asterisk)
*/
int init_methods( AMI *ami );
/*!
* Verifica se o evento continua esperando informação da AMI
*
* \param list_actions lista das actionid ativas, ou seja, esperando concluir a resposta
* \param actionid valor da actionid que será verificada
* \return sucesso 0, falha -1
*/
int is_actionid(struct s_actionid **list_actions, const char *actionid);
/*!
* Adicionar novas actionid. A biblioteca obterá apenas actionid que estão nessa estrutura
*
* \param list_actions lista de actionid ativas
* \param actionid será adicionada na lista
*
* \return sucesso 0, falha -1
*/
int actionid_add(struct s_actionid **list_actions, const char *actionid);
/*!
* remove a actionid da lista de actionid ativas. A biblioteca vai ignorar actionid que estão fora dessa estrutura.\n
* Apenas quando essa actionid for concluída
*
* \param list_actions lista de actionid ativas
* \param actionid actionid que será excluída da lista
*
* \return sucesso 0, falha -1
*/
int actionid_remove( struct s_actionid **list_actions, const char *actionid );
/*!
* Libera o actionid
* \param drop_actionid ponteiro para estrutura
* \return 0 sempre
*/
int actionid_free( struct s_actionid *drop_actionid );
/*!
* Adicionar eventos lista de eventos da ami.
*
* \param event lista de eventos recebido do AMI
* \param next próximo evento que será incluído na lista de eventos
*
*/
void event_add(EVENT **event, EVENT *next);
/*!
* Cria a estrutura de um novo evento.
*
* \warning Esse ponteiro deve ser liberado através do free_event.
*
* \return p_event um novo espaço para alocar eventos da AMI
*/
EVENT *event_create();
/*!
* Libera ponteiro do EVENT único e seus argumentos. Não vai liberar os próximos eventos "event->next"
*
* \param event estrutura que contém um evento da AMI
*/
void event_free( EVENT *event );
/*!
* Libera a lista do eventos da AMI
*
* \param event lista de eventos que serão liberadas
*/
void list_event_free(EVENT *event);
/*!
* Adiciona o argumento dentro do evento
*
* \param event estrutura de evento que será
* \param arg
*
*/
void args_event_add(EVENT *event, struct s_args *arg);
/*!
* Adiciona argumento para estrutura RESPONSE
* \param args lista de argumentos
* \param arg argumento que será inserido na lista
*/
void args_add( ARGS **args, ARGS *arg );
/*!
* Cria uma estrutura para um argumento.
* \return arg estrutura do tipo struct s_args
*/
struct s_args *arg_create();
/*!
* libera o ponteiro para estrutura do argumento.
*
* \return void
*/
void args_free(ARGS *arg);
/*!
* libera lista de argumentos. O ponteiro atuais e membros next args->next
* \param args pointeiro para essa lista
*
*/
void list_args_free(ARGS *args);
/*!
* Cria estrutura RESPONSE
* \return response estrutura vazia que será usada para preencher resposta da AMI
*/
RESPONSE *response_create();
/*!
* Adiciona Response na estrutura Action
* \param action estrutura action
* \param response será adicionado para o ACtion
*/
void action_response_add(ACTION *action, RESPONSE *response);
/*!
* Libera espaço do ponteiro da entrutura RESPONSE
* \param response estrutura response que será liberada
*/
int response_free(RESPONSE *response);
/*!
* criar estrutura para preenche-la com resposta da action
* \return ACTION nova estrutura ACTION
*/
ACTION *action_create();
/*!
* liberar uma action da estrutura
* \param action lista de actions
* \param toremove o action que será escluída da lista
* \return 0 sempre
*/
int action_remove(ACTION **list_action, ACTION *toremove);
/*!
* libera toda a lista do action
* \param list_action lista das action
* \return 0
*/
int list_action_free(ACTION *list_action);
/*!
* remove a actionid da lista de actionid ativas. A biblioteca vai ignorar actionid que estão fora dessa estrutura.\n
* Apenas quando essa actionid for concluída
*
* \param list_actions lista de actionid ativas
* \param actionid actionid que será excluída da lista
*
* \return sucesso 0, falha -1
*/
int actionid_remove( struct s_actionid **list_actions, const char *actionid );
/*!
* libera action a estrutura action
* \param action ponteiro para estrutura action
* \return sempre sucesso 0
*/
int action_free(ACTION *action);
/*!
* Adicionar action na lista de action
* \param action lista action
* \param next estrutura action que será inserida
* \return sucesso 0, falha -1
*/
int action_add(ACTION **action, ACTION *next);
#endif

385
src/net.c

@ -0,0 +1,385 @@
#include <ami.h>
#include <string.h>
#include <errno.h>
#include <poll.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
/*!
* Cria um sockect e defini opções desse conexão
*
* \return sucesso 0
*/
static int create_socket(NET *net);
/*!
* O módulo net começa ser usada. Essa função fará thread para começar a conexão.
* \param ami identifica qual instância da conexão
* \return sucesso 0
*/
int net_start(AMI *ami){
ami->thread.id_thread = pthread_create(&ami->thread.id_thread, NULL, net, (void *)ami);
return 0;
}
/*!
* Começará a conexão com a ami de acordo com os parâmetro passado
* \param void_ami identifica qual instância da conexão em tipo void *
* \return void *
*/
void *net(void *void_ami){
AMI *ami = void_ami;
create_socket(&ami->net);
while(1){
if(ami->net.is_connected == 0){
connect_ami(&ami->net);
}
if(ami->net.is_connected == 1 && ami->asterisk.is_logged == 0){
dispatch_login(ami);
}
if(ami->net.is_connected == 1 && ami->asterisk.is_logged == 1){
communication_ami(ami);
connect_login_down(&ami->net, &ami->asterisk);
}
}
}
/*!
* Retira o login e a conexão definida da estrutura.\n
* Reset conexão e login
*/
void connect_login_down(NET *net, ASTERISK *asterisk){
connect_down(net);
login_down(asterisk);
}
/*!
* Derruba a conexão com o ami
* \param net estrutura de informações de rede da biblioteca
*/
void connect_down(NET *net){
net->is_connected = 0;
net->imcomplete_net = 0;
sock_close(net->sock);
}
/*!
* Levanta a conexão, isto é, define na estrutura que a conexão está conectada.
* \param net estrutura responsável por tratar rede
*/
void connect_up(NET *net){
net->is_connected = 1;
}
/*!
* Define na estrutura que não está logado
* \param asterisk estrutura sobre o asterisk a ami do outro lado
* \return void
*/
void login_down(ASTERISK *asterisk){
asterisk->is_logged = 0;
asterisk->init_action = 0;
}
/*!
* Define na estrutura que está logado
*
*/
void login_up(ASTERISK *asterisk){
asterisk->is_logged = 1;
}
/*!
* Envia uma action para asterisk. send_action é função externa. dispatch_action é uma função interna
* \param ami estrutura de instância da biblioteca
* \param action action que será enviado
* \return sucesso 1, falha -1
*/
int dispatch_action(AMI *ami, const char *action){
if( !ami->net.is_connected || !ami->asterisk.is_logged ){
return -1;
}
ssize_t len, data_sent;
char *p_action;
p_action = (char *)action;
/*
* Enviar actions pela rede
*/
len = strlen(p_action);
while((data_sent = send(ami->net.sock, p_action, len, MSG_DONTWAIT|MSG_NOSIGNAL)) > 0){
/* looop enviar pacote que não foi enviado */
p_action += data_sent;
len -= data_sent;
}
if(data_sent == -1){
return -1;
}
return 0;
}
/*!
* envia a action para login ami
* \return sucesso 0, falha -1
*/
int dispatch_login(AMI *ami){
if( ami->net.is_connected == 0 || ami->asterisk.is_logged == 0 ){
return -1;
}
const char *str_login = NULL;
str_login = build_str_login(&ami->credential);
if( dispatch_login(ami) == -1 ){
return -1;
}
free_str_login((char *) str_login);
if( done_login( &ami->net ) == -1 ){
connect_login_down(&ami->net, &ami->asterisk);
return -1;
}
login_up(&ami->asterisk);
return 0;
}
/*!
* Fecha o socket que está conectado com a ami
*
*/
int sock_close(int sock){
if(close(sock) == -1){
if(errno == EINTR){
close(sock);
return 0;
}
return -1;
}
return 0;
}
/*!
* Verifica a resposta do login, se retornar 0 o usuário está logado
*
* \return sucesso 0, falha -1
*/
int done_login( NET *net ){
int len_message_login = 512;
char result_login[len_message_login];
char login_success[56] = "Response: Success\r\nMessage: Authentication accepted\r\n";
int bytes = 0;
int attempt_wait_login = 0;
while( 1 ){
struct pollfd pfd[1];
pfd[0].fd = net->sock;
pfd[0].events = POLLIN;
if(poll(pfd, 1, 10) == -1){
return -1;
}
if(pfd[0].revents & POLLHUP) {
return -1;
}
if(pfd[0].revents & POLLERR) {
return -1;
}
else if(pfd[0].revents & POLLIN) {
bytes = recv(net->sock, result_login, len_message_login - 1, 0);
result_login[bytes] = '\0';
if(!strstr(result_login, "Response")){
continue;
}
if(strstr(result_login, login_success) != NULL){
break;
}
else { /* login fail */
return -1;
}
}
attempt_wait_login++;
if(attempt_wait_login == 100){
return -1;
}
}
return 0;
}
/*!
* Connectar a ami e retorna está conectado
*
* \return sucesso 0, falha -1
*/
int connect_ami(NET *net){
while(1){
if (connect(net->sock, (struct sockaddr *)&net->sock_addr, sizeof(struct sockaddr_in) ) == -1){
sleep(1);
continue;
}
connect_up(net);
break;
}
return 0;
}
/*!
* Cria um sockect e defini opções desse conexão
* \return sucesso 0
*/
static int create_socket(NET *net){
bzero(&net->sock_addr, sizeof(net->sock_addr));
net->sock_addr.sin_family = AF_INET;
net->sock_addr.sin_port = htons(net->port);
net->sock_addr.sin_addr.s_addr = net->address;
net->sock = socket(net->sock_addr.sin_family, SOCK_STREAM, 0);
fcntl(net->sock, F_SETFL, O_NONBLOCK);
return 0;
}
/*!
* Começa receber dados do ami, essa função é depois que connect_ami e dispatch_login
* Direciona os dados que chegam da ami para determinados ramos
* \return void
*/
int communication_ami(AMI *ami){
int bytes = 0;
char more_buffer[MAX_BUFFER_NET + MAX_BUFFER_NET];
while(1){
struct pollfd pfd[1];
pfd[0].fd = ami->net.sock;
pfd[0].events = POLLIN;
if(poll(pfd, 1, 10) == -1){
if(errno == EINTR){
continue;
}
return -1;
}
if(pfd[0].revents & POLLHUP) {
return -1;
}
if(pfd[0].revents & POLLERR) {
return -1;
}
if(ami->asterisk.init_action == 0){
if(init_methods(ami) == -1){
connect_login_down(&ami->net, &ami->asterisk);
break;
}
}
else if(pfd[0].revents & POLLIN) {
char *buffer = NULL;
char *block = NULL;
if(ami->net.imcomplete_net == 0){
bytes = recv(ami->net.sock, ami->net.buffer_net, MAX_BUFFER_NET - 1, MSG_DONTWAIT);
ami->net.buffer_net[bytes] = '\0';
if(bytes == (MAX_BUFFER_NET - 2)){
ami->net.imcomplete_net = 1;
continue;
}
buffer = ami->net.buffer_net;
}
else{
strcpy(more_buffer, ami->net.buffer_net);
bytes = recv(ami->net.sock, (more_buffer + (MAX_BUFFER_NET - 1)), MAX_BUFFER_NET - 1, MSG_DONTWAIT);
more_buffer[bytes] = '\0';
ami->net.imcomplete_net = 0;
buffer = more_buffer;
}
block = define_block(buffer, &buffer);
while(block){
if(!strncmp(block, "Response: ", 10)){
parse_response(ami, block);
}
else if(!strncmp(block, "Event: ", 7)){
parse_event(ami, block);
}
block = define_block(NULL, &buffer);
}
}
}
return 0;
}

134
src/net.h

@ -0,0 +1,134 @@
/*!
*
*
*/
/*!
* O módulo net começa ser usada. Essa função fará thread para começar a conexão.
* \param ami identifica qual instância da conexão
* \return sucesso 0
*/
int net_start(AMI *ami);
/*!
* Começará a conexão com a ami de acordo com os parâmetro passado
* \param void_ami identifica qual instância da conexão em tipo void *
* \return void *
*/
void *net(void *void_ami);
/*!
* Retira o login e a conexão definida da estrutura.\n
* Reset conexão e login
*/
void connect_login_down(NET *net, ASTERISK *asterisk);
/*!
* Derruba a conexão com o ami
* \param net estrutura de informações de rede da biblioteca
*/
void connect_down(NET *net);
/*!
* Levanta a conexão, isto é, define na estrutura que a conexão está conectada.
* \param net l
* \return
*/
void connect_up(NET *net);
/*!
* Define na estrutura que não está logado
* \param asterisk estrutura sobre o asterisk a ami do outro lado
* \return void
*/
void login_down(ASTERISK *asterisk);
/*!
* Define na estrutura que está logado
*
*/
void login_up(ASTERISK *asterisk);
/*!
* Envia uma action para asterisk. send_action é função externa. dispatch_action é uma função interna
* \param ami estrutura de instância da biblioteca
* \param action action que será enviado
* \return sucesso 1, falha -1
*/
int dispatch_action(AMI *ami, const char *action);
/*!
* envia a action para login ami
* \return sucesso 0, falha -1
*/
int dispatch_login(AMI *ami);
/*!
* Fecha o socket que está conectado com a ami
*
*/
int sock_close(int sock);
/*!
* Verifica a resposta do login, se retornar 0 o usuário está logado
*
* \return sucesso 0, falha -1
*/
int done_login( NET *net );
/*!
* Connectar a ami e retorna está conectado
*
* \return sucesso 0, falha -1
*/
int connect_ami(NET *net);
/*!
* Começa receber dados do ami, essa função é depois que connect_ami e dispatch_login
* Direciona os dados que chegam da ami para determinados ramos
* \return void
*/
int communication_ami(AMI *ami);

84
src/parse_action.c

@ -0,0 +1,84 @@
#include <ami.h>
#include <string.h>
/*!
* Cuida das respostas que chegam da AMi das actions enviadas
* \param ami estrutura da AMI, a principal estrutura da AMI
* \param buffer
* \return void
*/
void parse_response(AMI *ami, const char *buffer){
char *end_response = "\r\n\r";
char *p_end = NULL;
RESPONSE *p_response = NULL;
ACTION *p_action = NULL;
size_t len_command = 0;
p_end = strstr(buffer, end_response);
if( !p_end ){
return ;
}
p_action = action_create();
p_response = response_create();
p_response = p_response + 10;
size_t len = len_action_ami(buffer);
p_response->response = calloc(1, len + 1);
strncpy(p_response->response, buffer, len);
p_response->response[len] = '\0';
buffer = buffer + len + 2;
action_response_add(p_action, p_response);
while(buffer < p_end){
ARGS *arg = arg_create();
len = len_key_ami( buffer );
arg->key = calloc(1, len + 1);
strncpy(arg->key, buffer, len);
buffer = buffer + 2;
//command
if(!strcmp(arg->key, "Output")){
size_t len = strlen(buffer);
arg->value = calloc(1, len + 1);
strcpy(arg->value, buffer);
arg->value[len] = '\0';
break;
}
len = len_value_ami(buffer, 0);
arg->value = calloc(1, len);
strncpy(arg->value, buffer, len);
buffer = buffer + 2;
args_add(&p_response->args, arg);
len_command = len_command_old_ami(buffer);
//action comando antigo
if( len_command && !strcmp(arg->key, "Privilege") && !strcmp(arg->value, "Command") ){
ARGS *arg = arg_create();
arg->key = calloc(1, sizeof(7));
strcpy(arg->key, "Output");
arg->key[6] = '\0';
arg->value = calloc(1, len_command + 1 );
strncpy(arg->value, buffer, len_command);
arg->value[len_command] = '\0';
break;
}
}
return;
}
int verify_response(AMI *ami, char *buffer){
return 0;
}

15
src/parse_action.h

@ -0,0 +1,15 @@
#ifndef PARSE_ACTION_H
#define PARSE_ACTION_H 1
/*!
* Tratará das respostas das actions
* \param substring inicio da resposta
*
*/
void parse_response(AMI *ami, const char *buffer);
#endif

52
src/parse_event.c

@ -0,0 +1,52 @@
#include <ami.h>
#include <string.h>
/*!
* Colocar cada evento dentro da estrutura Event.
*
* \param substring
* \param ami
* \return diferente de NULL significa que o evento será completado na proxima revc
*/
void parse_event(AMI *ami, char *buffer){
char *end_event = "\r\n\r";
char *p_end = NULL;
EVENT *p_event = NULL;
p_end = strstr(buffer, end_event);
if( !p_end ){
return;
}
p_event = event_create();
buffer = buffer + 8;
size_t len = len_action_ami(buffer);
p_event->event = calloc(1, sizeof(len));
strncpy(p_event->event, buffer, len);
p_event->event[len] = '\0';
buffer = buffer + len + 2;
while(buffer < p_end){
ARGS *arg = arg_create();
len = len_key_ami( buffer );
arg->key = calloc(1, len + 1);
strncpy(arg->key, buffer, len);
arg->key[len] = '\0';
buffer = buffer + 2;
len = len_value_ami(buffer, TYPE_EVENT);
arg->value = calloc(1, len);
strncpy(arg->value, buffer, len);
buffer = buffer + 2;
args_add(&p_event->args, arg);
}
event_add(&ami->events, p_event);
}

15
src/parse_event.h

@ -0,0 +1,15 @@
#ifndef PARSE_EVENT_H
#define PARSE_EVENT_H 1
/*!
* Colocar cada evento dentro da estrutura Event.
* \param substring
* \param ami
* \return diferente de NULL significa que o evento será completado na proxima revc
*/
void parse_event(AMI *ami, char *buffer);
#endif

200
src/parse_string.c

@ -0,0 +1,200 @@
#include <ami.h>
#include <string.h>
#include <stdio.h>
#define END_AND_EVENT "\r\n\r\nEvent: "
#define END_AND_RESPONSE "\r\n\r\nResponse: "
/*!
* Constrói o msg de login de acordo com as credenciais informadas pelo usuários
*
* \return action para ser enviado ao login, para dar free use a função free_str_login
*/
const char *build_str_login(CREDENTIAL *credential) {
char *str_login = NULL;
str_login = calloc(1, strlen("action: Login\r\nusername: %s\r\nsecret: %s\r\n\r\n") + strlen(credential->username) + strlen(credential->password) + 2);
sprintf(str_login, "action: Login\r\nusername: %s\r\nsecret: %s\r\n\r\n", credential->username, credential->password);
return str_login;
}
/*!
* libera ponteiro que está o action do login
* \param str_login action em texto
*/
void free_str_login(char *str_login){
free(str_login);
}
/*!
* Constrói texto da action de acordo com parâmetros que foi criado pelo create_new_action e preenchido pelo usuário
* \param action estrutura criada pelo create_new_action
* \return string da action, essa action deve ser chamada free_str_action para liberar
*/
const char *build_str_action(struct ss_action *action){
int len_total = (MAX_LEN_NAME_ACTION + 10) + ( action->count_args * (MAX_LEN_KEY_ACTION + MAX_LEN_VALUE_ACTION + 6));
char *str_action = calloc(1, len_total + 1);
snprintf(str_action, len_total, "action:%s\r\n", action->name_action);
int i;
for( i = 0; i < action->count_args; i++ ) {
strcat(str_action, action->args[i].key);
strcat(str_action, action->args[i].value);
strcat(str_action, "\r\n");
}
strcat(str_action, "\r\n");
return str_action;
}
/*!
* Será usado para liberar action criada pelo create_new_action
* \param str_action liberar ponteiro que está o texto action
*/
void str_action_free(char *str_action){
free(str_action);
}
/*!
* Comprimento do nome da action que vem da ami
* \param str texto da AMI
* \return retorna o comprimento da AMI ou 0 se encontrar byte \0
*/
size_t len_action_ami(const char *str){
size_t len_action = 0;
do{
len_action++;
if(*str == '\0'){
return 0;
}
}while (*(++str) != '\r');
return len_action;
}
/*!
* tamanho da chave que vem no texto da AMI
* \param str texto da AMI
* \return comprimento da ami ou 0 se encontrar byte nulo
*/
size_t len_key_ami(const char *str){
size_t len_action = 0;
do{
len_action++;
if(*str == '\0'){
return 0;
}
}while (*(++str) != ':');
return len_action;
}
/*!
* Comprimento do valor da chave
* \param str texto do evento da ami
* \return comprimento do valor ou 0 se encontrar byte nulo \0
*/
size_t len_value_ami( const char *str, int type ){
size_t len_action = 0;
do{
len_action++;
if(*str == '\0'){
return 0;
}
}while (*(++str) != '\r');
return len_action;
}
/*!
* Cada bloco é colocado um \0 no final. O final do bloco tem \\r\\n\\r\\n -> \\r\\n\\r\\0
* O parâmetro str será incluído uma data para buscar blocos, os próximos blocos parâmetro deve ser NULL. O parâmetro saveptr
* deve ser usado para achar os próximos blocos.\n
*
* primeiro bloco:\n
* point = define_block(str, &point_block);
* outros blocos:\n
* point = define_block(NULL, &point_block);
*
* \param str
* \param saveptr
* \return sucesso bloco de dados ou NULL não tem mais blocos definidos
*/
char *define_block(char *str, char **saveptr){
char *point_response, *point_event;
if(!(*saveptr)){
return NULL;
}
if(str == NULL){
str = *saveptr;
}
point_event = strstr(str, END_AND_EVENT);
point_response = strstr(str, END_AND_RESPONSE);
if( (point_response < point_event && point_response) || (point_response && !point_event) ){
point_response = point_response + 3;
*point_response = '\0';
point_response++;
*saveptr = point_response;
}
else if( (point_event < point_response && point_event) || (!point_response && point_event) ){
point_event = point_event + 3;
*point_event = '\0';
point_event++;
*saveptr = point_event;
}
else{
*saveptr = NULL;
}
return str;
}
/* Verifica se existe a string "--END COMMAND--\r\n\r" esse trecho é usado no asterisk 13 e anterior
* Caso estiver esse texto, retornará quando caracteres até ele
* \param command cadeia que verificará se existe a frase
* \return len quantidade de carcteres até a frase, falha 0 significa que a string não existe
*/
size_t len_command_old_ami(const char *command){
char *end_command = NULL;
size_t len = 0;
char *str_end_command = "--END COMMAND--\r\n\r";
end_command = strstr(command, str_end_command);
if(!end_command){
return 0;
}
while(command != end_command){
len++;
}
return len;
}

88
src/parse_string.h

@ -0,0 +1,88 @@
#ifndef PARSE_STRING_H
#define PARSE_STRING_H 1
/*!
* Constrói o msg de login de acordo com as credenciais informadas pelo usuários
*
* \return action para ser enviado ao login, para dar free use a função free_str_login
*/
const char *build_str_login(CREDENTIAL *credential);
/*!
* libera ponteiro que está o action do login
* \param str_login action em texto
*/
void free_str_login(char *str_login);
/*!
* Constrói texto da action de acordo com parâmetros que foi criado pelo create_new_action e preenchido pelo usuário
* \param action estrutura criada pelo create_new_action
* \return string da action, essa action deve ser chamada free_str_action para liberar
*/
const char *build_str_action(struct ss_action *action);
/*!
* Será usado para liberar action criada pelo create_new_action
* /param str_action liberar ponteiro que está o texto action
*/
void free_str_action(char *str_action);
/*!
* Comprimento do nome da action que vem da ami
* \param str texto da AMI
* \return retorna o comprimento da AMI ou 0 se encontrar byte \0
*/
size_t len_action_ami(const char *str);
/*!
* tamanho da chave que vem no texto da AMI
* \param str texto da AMI
* \return comprimento da ami ou 0 se encontrar byte nulo
*/
size_t len_key_ami(const char *str);
/*!
* Comprimento do valor da chave
* \param str texto do evento da ami
* \param type
* \return comprimento do valor ou 0 se encontrar byte nulo \0
*/
size_t len_value_ami( const char *str, int type );
/*!
* define o bloco dos dados da AMI colocando um \\0 no último \\n
* Essa função é similar ao strtok_r
* \param str começo do dados da AMI
* \param saveptr esse ponteiro será preenchido para o próxima chamada
* \return sucesso dados não null, falha NULL não tem blocos definidos
*/
char *define_block(char *str, char **saveptr);
/* Verifica se existe a string "--END COMMAND--\r\n\r" esse trecho é usado no asterisk 13 e anterior
* Caso estiver esse texto, retornará quando caracteres até ele
* \param command cadeia que verificará se existe a frase
* \return len quantidade de carcteres até a frase, falha 0 significa que a string não existe
*/
size_t len_command_old_ami(const char *command);
/*!
* Será usado para liberar action criada pelo create_new_action
* /param str_action liberar ponteiro que está o texto action
*/
void str_action_free(char *str_action);
#endif
Loading…
Cancel
Save