├── test ├── .gitignore ├── common.py ├── test_device_states.py ├── test_systems.py └── test_ob_plan.py ├── _config.yml ├── doc ├── source │ ├── _static │ │ ├── Basic_concept.png │ │ └── intro-outbound.png │ ├── intro.rst │ ├── configuration.rst │ ├── websocket.rst │ ├── index.rst │ ├── event.rst │ ├── user_api.rst │ ├── structure.rst │ ├── glossary.rst │ ├── installation.rst │ ├── park_event.rst │ ├── ob_basic.rst │ ├── manager_api.rst │ └── queue_event.rst ├── make.bat └── Makefile ├── jade.conf ├── src ├── includes │ ├── misc_handler.h │ ├── ob_event_handler.h │ ├── ami_event_handler.h │ ├── data_handler.h │ ├── config.h │ ├── ami_handler.h │ ├── agent_handler.h │ ├── event_handler.h │ ├── call_handler.h │ ├── ob_ami_handler.h │ ├── ami_response_handler.h │ ├── common.h │ ├── action_handler.h │ ├── subscription_handler.h │ ├── ob_dlma_handler.h │ ├── slog.h │ ├── db_ctx_handler.h │ ├── ob_destination_handler.h │ ├── ami_action_handler.h │ ├── voicemail_handler.h │ ├── ob_plan_handler.h │ ├── http_handler.h │ ├── park_handler.h │ ├── ob_http_handler.h │ ├── minGlue.h │ ├── core_handler.h │ ├── me_handler.h │ ├── dialplan_handler.h │ ├── publication_handler.h │ ├── sip_handler.h │ ├── ob_campaign_handler.h │ ├── manager_handler.h │ ├── queue_handler.h │ ├── utils.h │ ├── chat_handler.h │ ├── ob_dl_handler.h │ ├── conf_handler.h │ ├── ob_dialing_handler.h │ ├── user_handler.h │ ├── resource_handler.h │ ├── pjsip_handler.h │ ├── minIni.h │ └── admin_handler.h ├── main │ ├── base64.h │ ├── websocket_handler.h │ ├── Makefile │ ├── zmq_handler.h │ ├── slog.c │ ├── base64.c │ ├── action_handler.c │ ├── call_handler.c │ ├── misc_handler.c │ ├── subscription_handler.c │ ├── event_handler.c │ ├── zmq_handler.c │ ├── ami_handler.c │ ├── main.c │ └── config.c ├── modules │ ├── Makefile │ └── agent_handler.c └── Makefile ├── .travis.yml ├── scripts └── travis_install.sh ├── LICENSE ├── backend_wrap.sh ├── CODE_OF_CONDUCT.md └── README.md /test/.gitignore: -------------------------------------------------------------------------------- 1 | /common.pyc 2 | -------------------------------------------------------------------------------- /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /doc/source/_static/Basic_concept.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pchero/jade/HEAD/doc/source/_static/Basic_concept.png -------------------------------------------------------------------------------- /doc/source/_static/intro-outbound.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/pchero/jade/HEAD/doc/source/_static/intro-outbound.png -------------------------------------------------------------------------------- /doc/source/intro.rst: -------------------------------------------------------------------------------- 1 | .. intro 2 | 3 | ************ 4 | Introduction 5 | ************ 6 | This project is designed for asterisk call manager. 7 | 8 | Provide useful APIs for call handling. -------------------------------------------------------------------------------- /jade.conf: -------------------------------------------------------------------------------- 1 | { 2 | "serv_addr": "127.0.0.1", 3 | "serv_port": "5038", 4 | "username": "", 5 | "password": "", 6 | "loglevel": "7", 7 | 8 | "general" : { 9 | "result_filename" : "./outbound_result.json" 10 | }, 11 | 12 | "database" : { 13 | "name": "./database.db" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /src/includes/misc_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * misc_handler.h 3 | * 4 | * Created on: Dec 17, 2017 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef SRC_MISC_HANDLER_H_ 9 | #define SRC_MISC_HANDLER_H_ 10 | 11 | #include 12 | 13 | bool misc_init_handler(void); 14 | 15 | 16 | #endif /* SRC_MISC_HANDLER_H_ */ 17 | -------------------------------------------------------------------------------- /src/includes/ob_event_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * event_handler.h 3 | * 4 | * Created on: Nov 9, 2015 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef SRC_EVENT_HANDLER_H_ 9 | #define SRC_EVENT_HANDLER_H_ 10 | 11 | bool ob_init_handler(void); 12 | void ob_term_handler(void); 13 | 14 | #endif /* SRC_EVENT_HANDLER_H_ */ 15 | -------------------------------------------------------------------------------- /src/includes/ami_event_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ami_event_handler.h 3 | * 4 | * Created on: Mar 4, 2017 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef BACKEND_SRC_AMI_EVENT_HANDLER_H_ 9 | #define BACKEND_SRC_AMI_EVENT_HANDLER_H_ 10 | 11 | void ami_message_handler(const char* msg); 12 | 13 | #endif /* BACKEND_SRC_AMI_EVENT_HANDLER_H_ */ 14 | -------------------------------------------------------------------------------- /src/main/base64.h: -------------------------------------------------------------------------------- 1 | /* 2 | * base64.h 3 | * 4 | * Created on: Feb 1, 2018 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef SRC_MAIN_BASE64_H_ 9 | #define SRC_MAIN_BASE64_H_ 10 | 11 | int base64decode(char* b64message, char** buffer); 12 | int base64encode(const char* message, char** buffer); 13 | 14 | 15 | #endif /* SRC_MAIN_BASE64_H_ */ 16 | -------------------------------------------------------------------------------- /src/includes/data_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * data_handler.h 3 | * 4 | * Created on: Apr 3, 2017 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef BACKEND_SRC_DATA_HANDLER_H_ 9 | #define BACKEND_SRC_DATA_HANDLER_H_ 10 | 11 | #include 12 | 13 | bool data_init_handler(void); 14 | void data_term_handler(void); 15 | 16 | #endif /* BACKEND_SRC_DATA_HANDLER_H_ */ 17 | -------------------------------------------------------------------------------- /src/includes/config.h: -------------------------------------------------------------------------------- 1 | /* 2 | * config.h 3 | * 4 | * Created on: Feb 2, 2017 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef BACKEND_SRC_CONFIG_H_ 9 | #define BACKEND_SRC_CONFIG_H_ 10 | 11 | #include 12 | #include 13 | 14 | bool config_init(void); 15 | bool config_update_filename(const char* filename); 16 | 17 | #endif /* BACKEND_SRC_CONFIG_H_ */ 18 | -------------------------------------------------------------------------------- /src/includes/ami_handler.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef __AMI_HANDLER_H__ 3 | #define __AMI_HANDLER_H__ 4 | 5 | #include 6 | #include 7 | 8 | json_t* ami_parse_msg(const char* msg); 9 | json_t* ami_parse_agi_env(const char* msg); 10 | 11 | int ami_send_cmd_raw(const char* cmd); 12 | bool ami_send_cmd(json_t* j_cmd); 13 | 14 | void ami_set_socket(int socket); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /src/includes/agent_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * agent_handler.h 3 | * 4 | * Created on: Dec 12, 2017 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef SRC_AGENT_HANDLER_H_ 9 | #define SRC_AGENT_HANDLER_H_ 10 | 11 | #include 12 | 13 | void agent_htp_get_agent_agents(evhtp_request_t *req, void *data); 14 | void agent_htp_get_agent_agents_detail(evhtp_request_t *req, void *data); 15 | 16 | 17 | #endif /* SRC_AGENT_HANDLER_H_ */ 18 | -------------------------------------------------------------------------------- /src/includes/event_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * event_handler.h 3 | * 4 | * Created on: Feb 5, 2017 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef BACKEND_SRC_EVENT_HANDLER_H_ 9 | #define BACKEND_SRC_EVENT_HANDLER_H_ 10 | 11 | #include 12 | #include 13 | 14 | bool event_init_handler(void); 15 | void event_term_handler(void); 16 | 17 | void event_add_handler(struct event* ev); 18 | 19 | #endif /* BACKEND_SRC_EVENT_HANDLER_H_ */ 20 | -------------------------------------------------------------------------------- /src/main/websocket_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * websocket_handler.h 3 | * 4 | * Created on: Jan 17, 2018 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef SRC_WEBSOCKET_HANDLER_H_ 9 | #define SRC_WEBSOCKET_HANDLER_H_ 10 | 11 | #include 12 | 13 | bool websocket_init_handler(void); 14 | void websocket_term_handler(void); 15 | 16 | 17 | void* websocket_get_subscription_socket(const char* authtoken); 18 | 19 | #endif /* SRC_WEBSOCKET_HANDLER_H_ */ 20 | -------------------------------------------------------------------------------- /doc/source/configuration.rst: -------------------------------------------------------------------------------- 1 | .. configuration 2 | 3 | ************* 4 | Configuration 5 | ************* 6 | 7 | :: 8 | 9 | { 10 | "serv_addr": "127.0.0.1", 11 | "serv_port": "5038", 12 | "username": "", 13 | "password": "", 14 | "loglevel": "7", 15 | 16 | "general" : { 17 | "result_filename" : "./outbound_result.json" 18 | }, 19 | 20 | "database" : { 21 | "name": "./database.db" 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /src/includes/call_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * call_handler.h 3 | * 4 | * Created on: Apr 13, 2018 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef SRC_INCLUDES_CALL_HANDLER_H_ 9 | #define SRC_INCLUDES_CALL_HANDLER_H_ 10 | 11 | #include 12 | #include 13 | 14 | bool call_hangup_by_unique_id(const char* unique_id); 15 | bool call_originate_call_to_device(const char* source, const char* destination); 16 | 17 | #endif /* SRC_INCLUDES_CALL_HANDLER_H_ */ 18 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | 2 | os: 3 | - linux 4 | 5 | language: c 6 | 7 | before_install: 8 | - pip install --user cpp-coveralls 9 | - sudo apt-get install gcovr 10 | 11 | install: 12 | - ./scripts/travis_install.sh 13 | 14 | script: 15 | - cd src 16 | - make GCOV=1 17 | 18 | after_success: 19 | - coveralls --root . --exclude doc --exclude scripts --exclude test --gcov-options '\-lp' 20 | 21 | sudo: required 22 | 23 | addons: 24 | coverity_scan: 25 | project: 26 | name: "pchero/jade" 27 | notification_email: pchero21@gmail.com 28 | -------------------------------------------------------------------------------- /src/main/Makefile: -------------------------------------------------------------------------------- 1 | #Makefile 2 | # Created on: Jan 30, 2018 3 | # Author: pchero 4 | 5 | CC = gcc 6 | CFLAGS = -g -Wall -I../includes 7 | BUILD = ../$(BUILDDIR) 8 | ifeq ($(GCOV),1) 9 | CFLAGS += -fprofile-arcs -ftest-coverage 10 | endif 11 | 12 | 13 | .PHONY: default all clean 14 | #.PRECIOUS: $(TARGET) $(OBJECTS) 15 | 16 | OBJECTS = $(patsubst %.c, %.o, $(wildcard *.c)) 17 | HEADERS = $(wildcard *.h) 18 | 19 | %.o: %.c $(HEADERS) 20 | $(CC) $(CFLAGS) -c $< -o $(BUILD)/$@ 21 | 22 | default: $(OBJECTS) 23 | all: default 24 | 25 | clean: 26 | -rm -f *.o 27 | -rm -f $(TARGET) 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/modules/Makefile: -------------------------------------------------------------------------------- 1 | #Makefile 2 | # Created on: Jan 30, 2018 3 | # Author: pchero 4 | 5 | 6 | CC = gcc 7 | CFLAGS = -g -Wall -I../includes 8 | BUILD = ../$(BUILDDIR) 9 | 10 | ifeq ($(GCOV),1) 11 | CFLAGS += -fprofile-arcs -ftest-coverage 12 | endif 13 | 14 | .PHONY: default all clean 15 | #.PRECIOUS: $(TARGET) $(OBJECTS) 16 | 17 | OBJECTS = $(patsubst %.c, %.o, $(wildcard *.c)) 18 | HEADERS = $(wildcard *.h) 19 | 20 | %.o: %.c $(HEADERS) 21 | $(CC) $(CFLAGS) -c $< -o $(BUILD)/$@ 22 | 23 | default: $(OBJECTS) 24 | all: default 25 | 26 | clean: 27 | -rm -f *.o 28 | -rm -f $(TARGET) 29 | 30 | -------------------------------------------------------------------------------- /src/main/zmq_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * zmq_handler.h 3 | * 4 | * Created on: Dec 20, 2017 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef SRC_ZMQ_HANDLER_H_ 9 | #define SRC_ZMQ_HANDLER_H_ 10 | 11 | #include 12 | #include 13 | 14 | bool zmq_init_handler(void); 15 | void zmq_term_handler(void); 16 | 17 | bool zmq_publish_message(const char* pub_target, json_t* j_data); 18 | void* zmq_get_context(void); 19 | const char* zmq_get_pub_addr(void); 20 | 21 | int zmq_send_string(void* socket, const char* data); 22 | char* zmq_recv_string(void* socket); 23 | 24 | #endif /* SRC_ZMQ_HANDLER_H_ */ 25 | -------------------------------------------------------------------------------- /src/includes/ob_ami_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ob_ami_handler.h 3 | * 4 | * Created on: Feb 15, 2017 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef BACKEND_SRC_OB_AMI_HANDLER_H_ 9 | #define BACKEND_SRC_OB_AMI_HANDLER_H_ 10 | 11 | #include "action_handler.h" 12 | 13 | ACTION_RES ob_ami_response_handler_originate(json_t* j_action, json_t* j_msg); 14 | ACTION_RES ob_ami_response_handler_status(json_t* j_action, json_t* j_msg); 15 | 16 | bool ob_originate_to_exten(json_t* j_dialing); 17 | bool ob_originate_to_application(json_t* j_dialing); 18 | 19 | bool ob_originate_to_exten_preview(json_t* j_dialing); 20 | 21 | #endif /* BACKEND_SRC_OB_AMI_HANDLER_H_ */ 22 | -------------------------------------------------------------------------------- /src/includes/ami_response_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ami_response_handler.h 3 | * 4 | * Created on: Mar 31, 2017 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef BACKEND_SRC_AMI_RESPONSE_HANDLER_H_ 9 | #define BACKEND_SRC_AMI_RESPONSE_HANDLER_H_ 10 | 11 | #include 12 | 13 | ACTION_RES ami_response_handler_corestatus(json_t* j_action, json_t* j_msg); 14 | ACTION_RES ami_response_handler_coresettings(json_t* j_action, json_t* j_msg); 15 | ACTION_RES ami_response_handler_modulecheck(json_t* j_action, json_t* j_msg); 16 | ACTION_RES ami_response_handler_moduleload(json_t* j_action, json_t* j_msg); 17 | 18 | #endif /* BACKEND_SRC_AMI_RESPONSE_HANDLER_H_ */ 19 | -------------------------------------------------------------------------------- /doc/source/websocket.rst: -------------------------------------------------------------------------------- 1 | .. _websocket: 2 | 3 | ************** 4 | Websock basics 5 | ************** 6 | The jade supports subscription through the Websocket. 7 | 8 | Topic subscription 9 | ================== 10 | To subscribe topic through the websocket, the client needs to send subscription request first. 11 | 12 | :: 13 | 14 | { 15 | "type": "", 16 | "topic": "" 17 | } 18 | 19 | * ``message type``: message type. 20 | * * subscribe: add subsciption. 21 | * * unsubscribe: remove subscription. 22 | * ``topic``: Subscribe/Unsubscribe topic. 23 | 24 | Example 25 | +++++++ 26 | 27 | :: 28 | 29 | {"type":"subscribe", "topic": "/"} 30 | -------------------------------------------------------------------------------- /src/includes/common.h: -------------------------------------------------------------------------------- 1 | /* 2 | * common.h 3 | * 4 | * Created on: Feb 2, 2017 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef BACKEND_SRC_COMMON_H_ 9 | #define BACKEND_SRC_COMMON_H_ 10 | 11 | #include 12 | #include 13 | 14 | #include "db_ctx_handler.h" 15 | 16 | typedef struct _app { 17 | json_t* j_conf; ///< jade configuration 18 | struct event_base* evt_base; ///< event base 19 | } app; 20 | 21 | typedef enum _E_USE 22 | { 23 | E_USE_NO = 0, 24 | E_USE_OK = 1, 25 | } E_USE; 26 | 27 | extern db_ctx_t* g_db_memory; ///< sqlite3 database for asterisk. 28 | extern app* g_app; 29 | 30 | 31 | 32 | #endif /* BACKEND_SRC_COMMON_H_ */ 33 | -------------------------------------------------------------------------------- /doc/source/index.rst: -------------------------------------------------------------------------------- 1 | .. jade documentation master file, created by 2 | sphinx-quickstart on Sun Feb 5 23:48:19 2017. 3 | You can adapt this file completely to your liking, but it should at least 4 | contain the root `toctree` directive. 5 | 6 | Welcome to jade's manual! 7 | ========================= 8 | 9 | Contents: 10 | 11 | .. toctree:: 12 | :maxdepth: 2 13 | 14 | glossary 15 | intro 16 | installation 17 | configuration 18 | structure 19 | api 20 | event 21 | websocket 22 | ob_basic 23 | ob_structure 24 | ob_tutorial 25 | 26 | Indices and tables 27 | ================== 28 | 29 | * :ref:`genindex` 30 | * :ref:`modindex` 31 | * :ref:`search` 32 | 33 | -------------------------------------------------------------------------------- /src/includes/action_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * action_handler.h 3 | * 4 | * Created on: Feb 15, 2017 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef BACKEND_SRC_ACTION_HANDLER_H_ 9 | #define BACKEND_SRC_ACTION_HANDLER_H_ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | typedef enum _ACTION_RES { 16 | ACTION_RES_COMPLETE = 1, 17 | ACTION_RES_CONTINUE = 2, 18 | ACTION_RES_ERROR = 3, 19 | } ACTION_RES; 20 | 21 | bool action_insert(const char* id, const char* type, const json_t* j_data); 22 | bool action_delete(const char* id); 23 | json_t* action_get_and_delete(const char* id); 24 | json_t* action_get(const char* id); 25 | 26 | 27 | #endif /* BACKEND_SRC_ACTION_HANDLER_H_ */ 28 | -------------------------------------------------------------------------------- /src/includes/subscription_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * subscription_handler.h 3 | * 4 | * Created on: Apr 15, 2018 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef SRC_INCLUDES_SUBSCRIPTION_HANDLER_H_ 9 | #define SRC_INCLUDES_SUBSCRIPTION_HANDLER_H_ 10 | 11 | 12 | #include 13 | 14 | bool subscription_init_handler(void); 15 | bool subscription_term_handler(void); 16 | bool subscription_reload_handler(void); 17 | 18 | bool subscription_subscribe_topics_client(const char* authtoken, void* zmq_sock); 19 | bool subscription_subscribe_topic(const char* authtoken, const char* topic); 20 | 21 | bool subscription_unsubscribe_topic(const char* authtoken, const char* topic); 22 | 23 | 24 | #endif /* SRC_INCLUDES_SUBSCRIPTION_HANDLER_H_ */ 25 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | 2 | TARGET = jade_backend 3 | 4 | LIBS = -ljansson -levhtp -levent -levent_openssl -lssl -lcrypto -lpthread -luuid -lsqlite3 -lbsd -lonig -lzmq -levent_pthreads -lwebsockets -lm 5 | BUILDDIR = build 6 | SUBDIRS = modules main 7 | CC = gcc 8 | 9 | ifeq ($(GCOV),1) 10 | DEFS = GCOV=1 11 | LIBS += -lgcov --coverage 12 | endif 13 | 14 | export BUILDDIR 15 | 16 | .PHONY: all $(SUBDIRS) 17 | .PHONY: clean $(SUBDIRS) 18 | 19 | all: 20 | -mkdir -p $(BUILDDIR); 21 | for dir in $(SUBDIRS); do \ 22 | $(MAKE) $(DEFS) -C $$dir all; \ 23 | done 24 | 25 | $(CC) -o $(BUILDDIR)/$(TARGET) $(BUILDDIR)/*.o $(LIBS) 26 | 27 | 28 | clean: 29 | -rm -rf $(BUILDDIR) 30 | for dir in $(SUBDIRS); do \ 31 | $(MAKE) -C $$dir clean; \ 32 | done 33 | -------------------------------------------------------------------------------- /src/main/slog.c: -------------------------------------------------------------------------------- 1 | /* 2 | * log.c 3 | * 4 | * Created on: Feb 1, 2017 5 | * Author: pchero 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "common.h" 13 | 14 | #define PROGNAME "jade" 15 | #define DEF_LOGLEVEL 3 16 | 17 | extern app* g_app; 18 | 19 | bool g_log_initiated = false; 20 | 21 | 22 | bool slog_init_handler(void) 23 | { 24 | // set max loglevel 25 | setlogmask(LOG_UPTO(DEF_LOGLEVEL)); 26 | 27 | // set log 28 | openlog(PROGNAME, LOG_CONS | LOG_PID | LOG_NDELAY, LOG_LOCAL1); 29 | printf("Complete init_log.\n"); 30 | 31 | return true; 32 | } 33 | 34 | bool slog_update_log_level(int level) 35 | { 36 | setlogmask(LOG_UPTO(level)); 37 | 38 | return true; 39 | } 40 | 41 | -------------------------------------------------------------------------------- /src/includes/ob_dlma_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ob_dlma_handler.h 3 | * 4 | * Created on: Mar 21, 2017 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef BACKEND_SRC_OB_DLMA_HANDLER_H_ 9 | #define BACKEND_SRC_OB_DLMA_HANDLER_H_ 10 | 11 | #include 12 | #include 13 | 14 | bool ob_validate_dlma(json_t* j_data); 15 | json_t* ob_create_dlma(json_t* j_dlma); 16 | json_t* ob_update_dlma(const json_t* j_dlma); 17 | json_t* ob_delete_dlma(const char* uuid); 18 | json_t* ob_get_dlma(const char* uuid); 19 | json_t* ob_get_deleted_dlma(const char* uuid); 20 | 21 | json_t* ob_get_dlmas_all(void); 22 | json_t* ob_get_dlmas_all_uuid(void); 23 | char* ob_get_dlma_table_name(const char* dlma_uuid); 24 | 25 | bool ob_is_dlma_deletable(const char* uuid); 26 | 27 | 28 | #endif /* BACKEND_SRC_OB_DLMA_HANDLER_H_ */ 29 | -------------------------------------------------------------------------------- /doc/source/event.rst: -------------------------------------------------------------------------------- 1 | .. _event: 2 | 3 | ************ 4 | EVENT basics 5 | ************ 6 | 7 | EVENT description 8 | ================= 9 | 10 | Event name 11 | ---------- 12 | Publish event name. 13 | And description of EVENT. 14 | 15 | Topic 16 | +++++ 17 | Event's topic. If the client subscribe this topic, then can receive this event. 18 | 19 | :: 20 | 21 | 22 | 23 | Description of the detail of topic. 24 | 25 | 26 | Event 27 | +++++ 28 | Description of event. Described in detail. 29 | 30 | :: 31 | 32 | { 33 | ... 34 | } 35 | 36 | Example 37 | +++++++ 38 | Simple example of the event. It would be little bit different with real response. 39 | 40 | :: 41 | 42 | { 43 | ... 44 | } 45 | 46 | 47 | ***** 48 | EVENT 49 | ***** 50 | 51 | .. include:: core_event.rst 52 | .. include:: park_event.rst 53 | .. include:: queue_event.rst -------------------------------------------------------------------------------- /src/includes/slog.h: -------------------------------------------------------------------------------- 1 | /* 2 | * log.h 3 | * 4 | * Created on: Feb 1, 2017 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef BACKEND_SRC_SLOG_H_ 9 | #define BACKEND_SRC_SLOG_H_ 10 | 11 | #include 12 | #include 13 | 14 | #define LOG_EMERG 0 /* system is unusable */ 15 | #define LOG_ALERT 1 /* action must be taken immediately */ 16 | #define LOG_CRIT 2 /* critical conditions */ 17 | #define LOG_ERR 3 /* error conditions */ 18 | #define LOG_WARNING 4 /* warning conditions */ 19 | #define LOG_NOTICE 5 /* normal but significant condition */ 20 | #define LOG_INFO 6 /* informational */ 21 | #define LOG_DEBUG 7 /* debug-level messages */ 22 | #define LOG_VERBOSE 8 23 | 24 | bool slog_init_handler(void); 25 | bool slog_update_log_level(int level); 26 | 27 | #define slog(...) syslog(__VA_ARGS__) 28 | 29 | #endif /* BACKEND_SRC_LOG_H_ */ 30 | -------------------------------------------------------------------------------- /src/includes/db_ctx_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * db_handler_ctx.h 3 | * 4 | * Created on: Apr 27, 2017 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef BACKEND_SRC_DB_CTX_HANDLER_H_ 9 | #define BACKEND_SRC_DB_CTX_HANDLER_H_ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | typedef struct _db_ctx_t 16 | { 17 | struct sqlite3* db; 18 | 19 | struct sqlite3_stmt* stmt; 20 | } db_ctx_t; 21 | 22 | db_ctx_t* db_ctx_init(const char* name); 23 | void db_ctx_term(db_ctx_t* ctx); 24 | 25 | bool db_ctx_exec(db_ctx_t* ctx, const char* query); 26 | bool db_ctx_query(db_ctx_t* ctx, const char* query); 27 | json_t* db_ctx_get_record(db_ctx_t* ctx); 28 | 29 | bool db_ctx_insert(db_ctx_t* ctx, const char* table, const json_t* j_data); 30 | bool db_ctx_insert_or_replace(db_ctx_t* ctx, const char* table, const json_t* j_data); 31 | 32 | char* db_ctx_get_update_str(const json_t* j_data); 33 | char* db_ctx_get_condition_str(const json_t* j_data); 34 | 35 | bool db_ctx_free(db_ctx_t* ctx); 36 | 37 | 38 | #endif /* BACKEND_SRC_DB_CTX_HANDLER_H_ */ 39 | -------------------------------------------------------------------------------- /src/includes/ob_destination_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * destination_handler.h 3 | * 4 | * Created on: Oct 19, 2016 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef SRC_DESTINATION_HANDLER_H_ 9 | #define SRC_DESTINATION_HANDLER_H_ 10 | 11 | #include 12 | #include 13 | 14 | typedef enum _E_DESTINATION_TYPE { 15 | DESTINATION_EXTEN = 0, 16 | DESTINATION_APPLICATION = 1, 17 | } E_DESTINATION_TYPE; 18 | 19 | #define DEF_DESTINATION_AVAIL_CNT_UNLIMITED -1 20 | 21 | json_t* ob_create_destination(json_t* j_dest); 22 | json_t* ob_delete_destination(const char* uuid); 23 | json_t* ob_get_destination(const char* uuid); 24 | json_t* ob_get_destinations_all(void); 25 | json_t* ob_get_destinations_all_uuid(void); 26 | json_t* ob_update_destination(const json_t* j_dest); 27 | 28 | int ob_get_destination_available_count(json_t* j_dest); 29 | json_t* ob_create_dial_destination_info(json_t* j_dest); 30 | 31 | bool ob_validate_destination(json_t* j_data); 32 | 33 | bool ob_is_exist_destination(const char* uuid); 34 | bool ob_is_deletable_destination(const char* uuid); 35 | 36 | #endif /* SRC_DESTINATION_HANDLER_H_ */ 37 | -------------------------------------------------------------------------------- /scripts/travis_install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ "$TRAVIS_OS_NAME" == "linux" ]; 4 | then 5 | sudo apt-get update -qq 6 | 7 | sudo apt-get install -y -qq build-essential openssl libxml2-dev libncurses5-dev uuid-dev sqlite3 libsqlite3-dev pkg-config curl libjansson-dev 8 | sudo apt-get install -y -qq curl libssl-dev git cmake libevent-dev libjansson-dev libbsd-dev libzmq3-dev libonig-dev 9 | 10 | 11 | # libevhtp 12 | sudo mkdir -p /opt/src/libevhtp 13 | sudo curl -s https://codeload.github.com/criticalstack/libevhtp/tar.gz/1.2.16 | sudo tar xz -C /opt/src/libevhtp --strip-components=1 14 | sudo mkdir -p /opt/src/libevhtp/build 15 | cd /opt/src/libevhtp/build 16 | sudo cmake .. 17 | sudo make 18 | sudo make install 19 | 20 | 21 | # libwebsockets 22 | sudo mkdir -p /opt/src/libwebsockets 23 | sudo curl -s https://codeload.github.com/warmcat/libwebsockets/tar.gz/v2.4.2 | sudo tar xz -C /opt/src/libwebsockets --strip-components=1 24 | sudo mkdir -p /opt/src/libwebsockets/build 25 | cd /opt/src/libwebsockets/build 26 | sudo cmake -DLWS_WITH_LIBEVENT=1 ../ 27 | sudo make 28 | sudo make install 29 | 30 | fi 31 | 32 | -------------------------------------------------------------------------------- /src/includes/ami_action_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ami_action_handler.h 3 | * 4 | * Created on: Dec 15, 2017 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef SRC_AMI_ACTION_HANDLER_H_ 9 | #define SRC_AMI_ACTION_HANDLER_H_ 10 | 11 | #include 12 | 13 | bool ami_action_agi(const char* channel, const char* cmd, const char* cmd_id); 14 | bool ami_action_hangup(const char* channel); 15 | bool ami_action_hangup_by_uniqueid(const char* unique_id); 16 | bool ami_action_modulecheck(const char* name); 17 | bool ami_action_moduleload(const char* name, const char* type); 18 | bool ami_action_originate_application(const char* channel, const char* application, const char* data); 19 | bool ami_action_queueadd(const char* queue, const char* interface, const char* penalty, const char* paused, const char* member_name, const char* state_interface); 20 | bool ami_action_queuepause(const char* queue_name, const char* interface, const char* paused, const char* reason); 21 | bool ami_action_queuepenalty(const char* queue_name, const char* interface, const char* penalty); 22 | bool ami_action_queueremove(const char* queue_name, const char* interface); 23 | bool ami_action_setvar(const char* channel, const char* key, const char* value); 24 | 25 | 26 | #endif /* SRC_AMI_ACTION_HANDLER_H_ */ 27 | -------------------------------------------------------------------------------- /src/includes/voicemail_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * voicemail_handler.h 3 | * 4 | * Created on: Dec 4, 2017 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef SRC_VOICEMAIL_HANDLER_H_ 9 | #define SRC_VOICEMAIL_HANDLER_H_ 10 | 11 | #include 12 | 13 | void voicemail_htp_get_voicemail_users(evhtp_request_t *req, void *data); 14 | void voicemail_htp_post_voicemail_users(evhtp_request_t *req, void *data); 15 | void voicemail_htp_get_voicemail_users_detail(evhtp_request_t *req, void *data); 16 | void voicemail_htp_put_voicemail_users_detail(evhtp_request_t *req, void *data); 17 | void voicemail_htp_delete_voicemail_users_detail(evhtp_request_t *req, void *data); 18 | 19 | void voicemail_htp_get_voicemail_vms(evhtp_request_t *req, void *data); 20 | void voicemail_htp_get_voicemail_vms_msgname(evhtp_request_t *req, void *data); 21 | void voicemail_htp_delete_voicemail_vms_msgname(evhtp_request_t *req, void *data); 22 | 23 | void voicemail_htp_get_voicemail_config(evhtp_request_t *req, void *data); 24 | void voicemail_htp_put_voicemail_config(evhtp_request_t *req, void *data); 25 | 26 | void voicemail_htp_get_voicemail_configs(evhtp_request_t *req, void *data); 27 | void voicemail_htp_get_voicemail_configs_detail(evhtp_request_t *req, void *data); 28 | void voicemail_htp_delete_voicemail_configs_detail(evhtp_request_t *req, void *data); 29 | 30 | #endif /* SRC_VOICEMAIL_HANDLER_H_ */ 31 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2017, Sungtae Kim 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | * Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | * Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /src/includes/ob_plan_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * plan_handler.h 3 | * 4 | * Created on: Nov 30, 2015 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef SRC_PLAN_HANDLER_H_ 9 | #define SRC_PLAN_HANDLER_H_ 10 | 11 | #include 12 | 13 | typedef enum _E_DIAL_MODE { 14 | E_DIAL_MODE_NONE = 0, /// No dial mode 15 | E_DIAL_MODE_PREDICTIVE = 1, /// 16 | E_DIAL_MODE_PREVIEW = 2, /// 17 | E_DIAL_MODE_POWER = 3, /// 18 | E_DIAL_MODE_ROBO = 4, /// 19 | E_DIAL_MODE_REDIRECT = 5, /// 20 | } E_DIAL_MODE; 21 | 22 | /** 23 | * Determine when the dial list end. 24 | */ 25 | typedef enum _E_PLAN_DL_END_HANDLE { 26 | E_PLAN_DL_END_NONSTOP = 0, /// Keep current status. 27 | E_PLAN_DL_END_STOP = 1, /// Stop the campaign. 28 | } E_PLAN_DL_END_HANDLE; 29 | 30 | 31 | bool ob_init_plan(void); 32 | 33 | bool ob_validate_plan(json_t* j_data); 34 | json_t* ob_create_plan(json_t* j_plan); 35 | json_t* ob_delete_plan(const char* uuid); 36 | json_t* ob_update_plan(const json_t* j_plan); 37 | json_t* ob_get_plan(const char* uuid); 38 | json_t* ob_get_plans_all(void); 39 | json_t* ob_get_plans_all_uuid(void); 40 | 41 | json_t* ob_create_dial_plan_info(json_t* j_plan); 42 | bool ob_is_plan_enable(json_t* j_plan); 43 | bool ob_is_dl_handle_nonstop(json_t* j_plan); 44 | bool ob_is_plan_exist(const char* uuid); 45 | bool ob_is_plan_deletable(const char* uuid); 46 | 47 | #endif /* SRC_PLAN_HANDLER_H_ */ 48 | -------------------------------------------------------------------------------- /src/includes/http_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * http_handler.h 3 | * 4 | * Created on: Feb 2, 2017 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef BACKEND_SRC_HTTP_HANDLER_H_ 9 | #define BACKEND_SRC_HTTP_HANDLER_H_ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #define DEF_REG_UUID "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}" 16 | 17 | enum EN_HTTP_PERMS { 18 | EN_HTTP_PERM_ADMIN = 1, 19 | EN_HTTP_PERM_USER, 20 | }; 21 | 22 | #define DEF_USER_PERM_ADMIN "admin" 23 | #define DEF_USER_PERM_USER "user" 24 | 25 | bool http_init_handler(void); 26 | void http_term_handler(void); 27 | 28 | json_t* http_create_default_result(int code); 29 | 30 | void http_simple_response_error(evhtp_request_t *req, int status_code, int err_code, const char* err_msg); 31 | void http_simple_response_normal(evhtp_request_t *req, json_t* j_msg); 32 | 33 | json_t* http_get_json_from_request_data(evhtp_request_t* req); 34 | char* http_get_text_from_request_data(evhtp_request_t* req); 35 | char* http_get_parsed_detail(evhtp_request_t* req); 36 | char* http_get_parsed_detail_start(evhtp_request_t* req); 37 | 38 | bool http_get_htp_id_pass(evhtp_request_t* req, char** agent_uuid, char** agent_pass); 39 | char* http_get_authtoken(evhtp_request_t* req); 40 | char* http_get_parameter(evhtp_request_t* req, const char* key); 41 | json_t* http_get_userinfo(evhtp_request_t *req); 42 | 43 | bool http_is_request_has_permission(evhtp_request_t *req, enum EN_HTTP_PERMS perm); 44 | 45 | 46 | #endif /* BACKEND_SRC_HTTP_HANDLER_H_ */ 47 | -------------------------------------------------------------------------------- /src/includes/park_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * park_handler.h 3 | * 4 | * Created on: Dec 14, 2017 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef SRC_PARK_HANDLER_H_ 9 | #define SRC_PARK_HANDLER_H_ 10 | 11 | #include 12 | 13 | bool park_init_handler(void); 14 | bool park_term_handler(void); 15 | bool park_reload_handler(void); 16 | 17 | // callback 18 | bool park_register_callback_db_parkedcall(bool (*func)(enum EN_RESOURCE_UPDATE_TYPES, const json_t*)); 19 | 20 | // parkinglot 21 | json_t* park_get_parkinglots_all(void); 22 | json_t* park_get_parkinglot_info(const char* name); 23 | bool park_create_parkinglot_info(const json_t* j_tmp); 24 | 25 | // parkedcall 26 | json_t* park_get_parkedcalls_all(); 27 | json_t* park_get_parkedcall_info(const char* key); 28 | bool park_create_parkedcall_info(const json_t* j_data); 29 | bool park_update_parkedcall_info(const json_t* j_data); 30 | bool park_delete_parkedcall_info(const char* key); 31 | 32 | // cfg 33 | json_t* park_cfg_get_parkinglots_all(void); 34 | json_t* park_cfg_get_parkinglot_info(const char* name); 35 | bool park_cfg_create_parkinglot_info(const json_t* j_data); 36 | bool park_cfg_update_parkinglot_info(const json_t* j_data); 37 | bool park_cfg_delete_parkinglot_info(const char* parkinglot); 38 | 39 | 40 | // configuration 41 | json_t* park_get_configurations_all(void); 42 | json_t* park_get_configuration_info(const char* name); 43 | bool park_update_configuration_info(const json_t* j_data); 44 | bool park_delete_configuration_info(const char* name); 45 | 46 | 47 | #endif /* SRC_PARK_HANDLER_H_ */ 48 | -------------------------------------------------------------------------------- /backend_wrap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # myapp daemon 3 | # chkconfig: 345 20 80 4 | # description: myapp daemon 5 | # processname: myapp 6 | 7 | DAEMON_PATH="/opt/bin" 8 | 9 | DAEMON=jade_backend 10 | DAEMONOPTS="" 11 | 12 | NAME=jade_bakcend 13 | DESC="My daemon description" 14 | PIDFILE=/var/run/$NAME.pid 15 | SCRIPTNAME=/etc/init.d/$NAME 16 | 17 | case "$1" in 18 | start) 19 | printf "%-50s" "Starting $NAME..." 20 | cd $DAEMON_PATH 21 | $DAEMON $DAEMONOPTS > /dev/null 2>&1 & 22 | if [ -z $PIDFILE ]; then 23 | printf "%s\n" "Fail" 24 | else 25 | echo $PID > $PIDFILE 26 | printf "%s\n" "Ok" 27 | fi 28 | ;; 29 | status) 30 | printf "%-50s" "Checking $NAME..." 31 | if [ -f $PIDFILE ]; then 32 | PID=`cat $PIDFILE` 33 | if [ -z "`ps axf | grep ${PID} | grep -v grep`" ]; then 34 | printf "%s\n" "Process dead but pidfile exists" 35 | else 36 | echo "Running" 37 | fi 38 | else 39 | printf "%s\n" "Service not running" 40 | fi 41 | ;; 42 | stop) 43 | printf "%-50s" "Stopping $NAME" 44 | PID=`cat $PIDFILE` 45 | cd $DAEMON_PATH 46 | if [ -f $PIDFILE ]; then 47 | kill -HUP $PID 48 | printf "%s\n" "Ok" 49 | rm -f $PIDFILE 50 | else 51 | printf "%s\n" "pidfile not found" 52 | fi 53 | ;; 54 | 55 | restart) 56 | $0 stop 57 | $0 start 58 | ;; 59 | 60 | *) 61 | echo "Usage: $0 {status|start|stop|restart}" 62 | exit 1 63 | esac -------------------------------------------------------------------------------- /test/common.py: -------------------------------------------------------------------------------- 1 | import pycurl 2 | import cStringIO 3 | import base64 4 | 5 | def http_send(url, method, data): 6 | ''' 7 | @param url: Access url. 8 | @param auth: Authorization info. 9 | @param method: [GET, POST, PUT, DELETE] 10 | @param data: Send data 11 | 12 | @return: code, get_data. 13 | ''' 14 | 15 | if url is None: 16 | raise Exception("No url to send.") 17 | 18 | conn = pycurl.Curl() 19 | 20 | conn.setopt(pycurl.URL, url) 21 | 22 | # set response buffer 23 | response = cStringIO.StringIO() 24 | conn.setopt(pycurl.WRITEFUNCTION, response.write) 25 | 26 | # set request buffer 27 | if data is not None: 28 | conn.setopt(pycurl.POST, 1) 29 | conn.setopt(pycurl.POSTFIELDSIZE, len(data)) 30 | conn.setopt(pycurl.POSTFIELDS, data) 31 | # conn.setopt(conn.HTTPHEADER, ["Content-Type: application/json"]) 32 | 33 | 34 | # print "Send data[%s]" % (data) 35 | # conn.setopt(pycurl.POSTFIELDS, data) 36 | 37 | # set method 38 | if method == "POST": 39 | conn.setopt(pycurl.POST, 1) 40 | elif method == "GET": 41 | conn.setopt(pycurl.HTTPGET, 1) 42 | elif method == "PUT": 43 | conn.setopt(pycurl.CUSTOMREQUEST, "PUT") 44 | elif method == "DELETE": 45 | conn.setopt(pycurl.CUSTOMREQUEST, "DELETE") 46 | else: 47 | raise Exception("Unsupported method.") 48 | 49 | # perform 50 | conn.perform() 51 | 52 | # return 53 | return conn.getinfo(pycurl.HTTP_CODE), response.getvalue() 54 | 55 | -------------------------------------------------------------------------------- /src/includes/ob_http_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * ob_http_handler.h 3 | * 4 | * Created on: Mar 15, 2017 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef BACKEND_SRC_OB_HTTP_HANDLER_H_ 9 | #define BACKEND_SRC_OB_HTTP_HANDLER_H_ 10 | 11 | #include 12 | 13 | // campaigns 14 | void ob_cb_htp_ob_campaigns(evhtp_request_t *req, void *data); 15 | void ob_cb_htp_ob_campaigns_all(evhtp_request_t *req, void *data); 16 | void ob_cb_htp_ob_campaigns_detail(evhtp_request_t *req, void *data); 17 | 18 | // plans 19 | void ob_cb_htp_ob_plans(evhtp_request_t *req, void *data); 20 | void ob_cb_htp_ob_plans_all(evhtp_request_t *req, void *data); 21 | void ob_cb_htp_ob_plans_detail(evhtp_request_t *req, void *data); 22 | 23 | // destinations 24 | void ob_cb_htp_ob_destinations(evhtp_request_t *req, void *data); 25 | void ob_cb_htp_ob_destinations_all(evhtp_request_t *req, void *data); 26 | void ob_cb_htp_ob_destinations_detail(evhtp_request_t *req, void *data); 27 | 28 | // dlmas 29 | void ob_cb_htp_ob_dlmas(evhtp_request_t *req, void *data); 30 | void ob_cb_htp_ob_dlmas_all(evhtp_request_t *req, void *data); 31 | void ob_cb_htp_ob_dlmas_detail(evhtp_request_t *req, void *data); 32 | 33 | // dls 34 | void ob_cb_htp_ob_dls(evhtp_request_t *req, void *data); 35 | void ob_cb_htp_ob_dls_all(evhtp_request_t *req, void *data); 36 | void ob_cb_htp_ob_dls_detail(evhtp_request_t *req, void *data); 37 | 38 | // dialings 39 | void ob_cb_htp_ob_dialings(evhtp_request_t *req, void *data); 40 | void ob_cb_htp_ob_dialings_all(evhtp_request_t *req, void *data); 41 | void ob_cb_htp_ob_dialings_detail(evhtp_request_t *req, void *data); 42 | 43 | 44 | #endif /* BACKEND_SRC_OB_HTTP_HANDLER_H_ */ 45 | -------------------------------------------------------------------------------- /doc/source/user_api.rst: -------------------------------------------------------------------------------- 1 | .. _user_api: 2 | 3 | 4 | .. _user_contacts: 5 | 6 | /user/contacts 7 | ============== 8 | 9 | Methods 10 | ------- 11 | GET : Get list of all user contacts info. 12 | 13 | POST : Create user contact info 14 | 15 | .. _get_user_contacts: 16 | 17 | Method: GET 18 | ----------- 19 | Get list of all user contacts info. 20 | 21 | Example 22 | +++++++ 23 | :: 24 | 25 | $ curl localhost:8081/user/contacts\?authtoken=f1b5cd49-3c54-4aad-8585-754e3ab1796c 26 | 27 | { 28 | "api_ver": "0.1", 29 | "result": { 30 | "list": [ 31 | { 32 | "detail": "test target detail", 33 | "name": "test target", 34 | "target": "pjagent-01", 35 | "tm_create": "2018-02-04T01:34:34.972284886Z", 36 | "tm_update": null, 37 | "type": "pjsip_endpoint", 38 | "user_uuid": "b47977bc-913a-44d9-aaa9-33cc10970c30", 39 | "uuid": "a39b43a6-004f-472a-9c7b-80a9fbb91600" 40 | } 41 | ] 42 | }, 43 | "statuscode": 200, 44 | "timestamp": "2018-02-04T01:37:48.578013046Z" 45 | } 46 | 47 | .. _post_user_contacts: 48 | 49 | Method: POST 50 | ----------- 51 | Create user contacts info. 52 | 53 | Example 54 | +++++++ 55 | :: 56 | 57 | $ curl -X POST localhost:8081/user/contacts\?authtoken=674b1d39-9c48-476c-951c-a6a172500f06 -d \ 58 | '{"user_uuid": "59e3a7d5-b05f-43cd-abdf-db7009eed6cf", "type": "pjsip_endpoint", "target": "rtcagent-01", "name": "test target", "detail": "test target detail"}' 59 | 60 | {"api_ver": "0.1", "timestamp": "2018-02-04T01:34:34.983477950Z", "statuscode": 200} 61 | 62 | -------------------------------------------------------------------------------- /src/includes/minGlue.h: -------------------------------------------------------------------------------- 1 | /* Glue functions for the minIni library, based on the C/C++ stdio library 2 | * 3 | * Or better said: this file contains macros that maps the function interface 4 | * used by minIni to the standard C/C++ file I/O functions. 5 | * 6 | * By CompuPhase, 2008-2014 7 | * This "glue file" is in the public domain. It is distributed without 8 | * warranties or conditions of any kind, either express or implied. 9 | */ 10 | 11 | /* map required file I/O types and functions to the standard C library */ 12 | #include 13 | 14 | #define INI_FILETYPE FILE* 15 | #define ini_openread(filename,file) ((*(file) = fopen((filename),"rb")) != NULL) 16 | #define ini_openwrite(filename,file) ((*(file) = fopen((filename),"wb")) != NULL) 17 | #define ini_openrewrite(filename,file) ((*(file) = fopen((filename),"r+b")) != NULL) 18 | #define ini_close(file) (fclose(*(file)) == 0) 19 | #define ini_read(buffer,size,file) (fgets((buffer),(size),*(file)) != NULL) 20 | #define ini_write(buffer,file) (fputs((buffer),*(file)) >= 0) 21 | #define ini_rename(source,dest) (rename((source), (dest)) == 0) 22 | #define ini_remove(filename) (remove(filename) == 0) 23 | 24 | #define INI_FILEPOS long int 25 | #define ini_tell(file,pos) (*(pos) = ftell(*(file))) 26 | #define ini_seek(file,pos) (fseek(*(file), *(pos), SEEK_SET) == 0) 27 | 28 | /* for floating-point support, define additional types and functions */ 29 | #define INI_REAL float 30 | #define ini_ftoa(string,value) sprintf((string),"%f",(value)) 31 | #define ini_atof(string) (INI_REAL)strtod((string),NULL) 32 | -------------------------------------------------------------------------------- /src/includes/core_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * core_handler.h 3 | * 4 | * Created on: Dec 12, 2017 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef SRC_CORE_HANDLER_H_ 9 | #define SRC_CORE_HANDLER_H_ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | bool core_init_handler(void); 16 | bool core_term_handler(void); 17 | bool core_reload_handler(void); 18 | 19 | // callback 20 | bool core_register_callback_module(bool (*func)(enum EN_RESOURCE_UPDATE_TYPES, const json_t*)); 21 | bool core_register_callback_db_channel(bool (*func)(enum EN_RESOURCE_UPDATE_TYPES, const json_t*)); 22 | bool core_register_callback_db_module(bool (*func)(enum EN_RESOURCE_UPDATE_TYPES, const json_t*)); 23 | bool core_register_callback_db_system(bool (*func)(enum EN_RESOURCE_UPDATE_TYPES, const json_t*)); 24 | 25 | // channel 26 | json_t* core_get_channels_all(void); 27 | json_t* core_get_channels_by_devicename(const char* device_name); 28 | json_t* core_get_channel_info(const char* unique_id); 29 | bool core_create_channel_info(const json_t* j_data); 30 | int core_update_channel_info(const json_t* j_tmp); 31 | int core_delete_channel_info(const char* key); 32 | 33 | // module 34 | json_t* core_get_modules_all(void); 35 | json_t* core_get_module_info(const char* key); 36 | bool core_create_module(json_t* j_tmp); 37 | bool core_update_module_info(const json_t* j_data); 38 | 39 | // system 40 | json_t* core_get_systems_all(void); 41 | json_t* core_get_system_info(const char* id); 42 | bool core_create_system_info(const json_t* j_data); 43 | bool core_update_system_info(const json_t* j_data); 44 | 45 | // etc 46 | bool core_module_load(const char* name); 47 | bool core_module_reload(const char* name); 48 | bool core_module_unload(const char* name); 49 | 50 | 51 | #endif /* SRC_CORE_HANDLER_H_ */ 52 | -------------------------------------------------------------------------------- /doc/source/structure.rst: -------------------------------------------------------------------------------- 1 | .. structure: 2 | 3 | ********* 4 | Structure 5 | ********* 6 | 7 | Basic structures 8 | ================ 9 | 10 | .. _agent_status: 11 | 12 | Agent status 13 | ------------ 14 | Agent's status. 15 | 16 | .. table:: Agent status 17 | 18 | =============== =========== 19 | Status Detail 20 | =============== =========== 21 | AGENT_LOGGEDOFF Agent is not logged in. 22 | AGENT_IDLE Agent is logged in status idle. 23 | AGENT_ONCALL Agent is logged in and now on call. 24 | =============== =========== 25 | 26 | .. _device_state: 27 | 28 | Device state 29 | ------------ 30 | Device's state 31 | 32 | .. table:: Device state 33 | 34 | =========== =========== 35 | State Detail 36 | =========== =========== 37 | UNKNOWN Device is valid but channel didn't know state. 38 | NOT_INUSE Device is not used. 39 | BUSY Device is in use. 40 | INVALID Device is invalid. 41 | UNAVAILABLE Device is unavailable. 42 | RINGING Device is ringing. 43 | RINGINUSE Device is ringing *and* in use. 44 | ONHOLD Device is on hold. 45 | =========== =========== 46 | 47 | .. _peer_monitoring_status: 48 | 49 | Peer monitoring status 50 | ---------------------- 51 | Peer's monitoring status. 52 | 53 | .. table:: Peer monitoring sttus 54 | 55 | ========== ============== 56 | Status Detail 57 | ========== ============== 58 | ========== ============== 59 | 60 | 61 | .. _peer_status: 62 | 63 | Peer status 64 | ----------- 65 | Peer's status. 66 | 67 | .. table:: Peer status 68 | 69 | ============ ============= 70 | Status Detail 71 | ============ ============= 72 | Unknow Unknwon status. 73 | Registered Peer has been registered. 74 | Unregistered Peer has been unregistered. 75 | Rejected Rejected. 76 | Lagged Lagged. 77 | ============ ============= 78 | -------------------------------------------------------------------------------- /src/includes/me_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * me_handler.h 3 | * 4 | * Created on: Feb 4, 2018 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef SRC_MAIN_ME_HANDLER_H_ 9 | #define SRC_MAIN_ME_HANDLER_H_ 10 | 11 | #include 12 | 13 | bool me_init_handler(void); 14 | bool me_reload_handler(void); 15 | void me_term_handler(void); 16 | 17 | 18 | json_t* me_get_subscribable_topics_all(const json_t* j_user); 19 | 20 | 21 | // http handlers 22 | void me_htp_get_me_info(evhtp_request_t *req, void *data); 23 | void me_htp_put_me_info(evhtp_request_t *req, void *data); 24 | 25 | void me_htp_get_me_buddies(evhtp_request_t *req, void *data); 26 | void me_htp_post_me_buddies(evhtp_request_t *req, void *data); 27 | 28 | void me_htp_get_me_buddies_detail(evhtp_request_t *req, void *data); 29 | void me_htp_put_me_buddies_detail(evhtp_request_t *req, void *data); 30 | void me_htp_delete_me_buddies_detail(evhtp_request_t *req, void *data); 31 | 32 | void me_htp_get_me_calls(evhtp_request_t *req, void *data); 33 | void me_htp_post_me_calls(evhtp_request_t *req, void *data); 34 | 35 | void me_htp_get_me_contacts(evhtp_request_t *req, void *data); 36 | 37 | void me_htp_get_me_chats(evhtp_request_t *req, void *data); 38 | void me_htp_post_me_chats(evhtp_request_t *req, void *data); 39 | 40 | void me_htp_get_me_chats_detail(evhtp_request_t *req, void *data); 41 | void me_htp_put_me_chats_detail(evhtp_request_t *req, void *data); 42 | void me_htp_delete_me_chats_detail(evhtp_request_t *req, void *data); 43 | 44 | void me_htp_post_me_chats_detail_messages(evhtp_request_t *req, void *data); 45 | void me_htp_get_me_chats_detail_messages(evhtp_request_t *req, void *data); 46 | 47 | void me_htp_post_me_login(evhtp_request_t *req, void *data); 48 | void me_htp_delete_me_login(evhtp_request_t *req, void *data); 49 | 50 | void me_htp_get_me_search(evhtp_request_t *req, void *data); 51 | 52 | #endif /* SRC_MAIN_ME_HANDLER_H_ */ 53 | -------------------------------------------------------------------------------- /src/includes/dialplan_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * dialplan_handler.h 3 | * 4 | * Created on: Jan 21, 2018 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef SRC_DIALPLAN_HANDLER_H_ 9 | #define SRC_DIALPLAN_HANDLER_H_ 10 | 11 | #include 12 | #include 13 | 14 | bool dialplan_init_handler(void); 15 | bool dialplan_term_handler(void); 16 | bool dialplan_reload_handler(void); 17 | 18 | bool dialplan_reload_asterisk(void); 19 | 20 | 21 | // dpma 22 | json_t* dialplan_get_dpmas_all(void); 23 | json_t* dialplan_get_dpma_info(const char* key); 24 | bool dialplan_create_dpma_info(const json_t* j_data); 25 | bool dialplan_update_dpma_info(const json_t* j_data); 26 | bool dialplan_delete_dpma_info(const char* uuid); 27 | 28 | // dialplan 29 | json_t* dialplan_get_dialplans_all(void); 30 | json_t* dialplan_get_dialplans_by_dpma_uuid_order_sequence(const char* dpma_uuid); 31 | json_t* dialplan_get_dialplan_info(const char* key); 32 | json_t* dialplan_get_dialplan_info_by_dpma_seq(const char* dpma_uuid, int seq); 33 | 34 | bool dialplan_create_dialplan_info(const json_t* j_data); 35 | bool dialplan_update_dialplan_info(const json_t* j_data); 36 | bool dialplan_delete_dialplan_info(const char* uuid); 37 | 38 | bool dialplan_add_cmds(const char* agi_uuid); 39 | 40 | char* dialplan_get_default_dpma_originate_to_device(void); 41 | 42 | // static dialplan 43 | json_t* dialplan_get_sdialplans_all(void); 44 | json_t* dialplan_get_sdialplan_info(const char* name); 45 | bool dialplan_create_sdialplan_info(const json_t* j_data); 46 | bool dialplan_update_sdialplan_info(const json_t* j_data); 47 | bool dialplan_delete_sdialplan_info(const char* name); 48 | 49 | // configuration 50 | json_t* dialplan_get_configurations_all(void); 51 | json_t* dialplan_get_configuration_info(const char* name); 52 | bool dialplan_update_configuration_info(const json_t* j_data); 53 | bool dialplan_delete_configuration_info(const char* name); 54 | 55 | 56 | 57 | #define DEF_DIALPLAN_JADE_AGI_NAME "jade_dialplan" 58 | 59 | #endif /* SRC_DIALPLAN_HANDLER_H_ */ 60 | -------------------------------------------------------------------------------- /src/includes/publication_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * publish_handler.h 3 | * 4 | * Created on: Dec 22, 2017 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef SRC_PUBLISH_HANDLER_H_ 9 | #define SRC_PUBLICATION_HANDLER_H_ 10 | 11 | #include 12 | #include 13 | 14 | #define DEF_PUB_TYPE_CREATE "create" 15 | #define DEF_PUB_TYPE_UPDATE "update" 16 | #define DEF_PUB_TYPE_DELETE "delete" 17 | 18 | enum EN_PUBLISH_TYPES { 19 | EN_PUBLISH_CREATE = 1, 20 | EN_PUBLISH_UPDATE = 2, 21 | EN_PUBLISH_DELETE = 3, 22 | }; 23 | 24 | bool publication_publish_event(const char* topic, const char* event_prefix, enum EN_PUBLISH_TYPES type, const json_t* j_data); 25 | 26 | bool publication_publish_event_core_channel(const char* type, json_t* j_data); 27 | bool publication_publish_event_core_agi(const char* type, json_t* j_data); 28 | bool publication_publish_event_core_module(const char* type, json_t* j_data); 29 | 30 | bool publication_publish_event_dp_dialplan(const char* type, json_t* j_data); 31 | bool publication_publish_event_dp_dpma(const char* type, json_t* j_data); 32 | 33 | bool publication_publish_event_park_parkedcall(const char* type, json_t* j_data); 34 | bool publication_publish_event_park_parkinglot(const char* type, json_t* j_data); 35 | 36 | bool publication_publish_event_pjsip_aor(const char* type, json_t* j_data); 37 | bool publication_publish_event_pjsip_auth(const char* type, json_t* j_data); 38 | bool publication_publish_event_pjsip_contact(const char* type, json_t* j_data); 39 | bool publication_publish_event_pjsip_endpoint(const char* type, json_t* j_data); 40 | 41 | bool publication_publish_event_queue_member(const char* type, json_t* j_data); 42 | bool publication_publish_event_queue_queue(const char* type, json_t* j_data); 43 | bool publication_publish_event_queue_entry(const char* type, json_t* j_data); 44 | 45 | bool publication_publish_event_sip_peer(const char* type, json_t* j_data); 46 | bool publication_publish_event_sip_registry(const char* type, json_t* j_data); 47 | 48 | 49 | #endif /* SRC_PUBLISH_HANDLER_H_ */ 50 | -------------------------------------------------------------------------------- /src/includes/sip_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * sip_handler.h 3 | * 4 | * Created on: Dec 12, 2017 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef SRC_SIP_HANDLER_H_ 9 | #define SRC_SIP_HANDLER_H_ 10 | 11 | #include 12 | 13 | bool sip_init_handler(void); 14 | bool sip_reload_handler(void); 15 | bool sip_term_handler(void); 16 | 17 | void sip_htp_get_sip_config(evhtp_request_t *req, void *data); 18 | void sip_htp_put_sip_config(evhtp_request_t *req, void *data); 19 | 20 | void sip_htp_get_sip_configs(evhtp_request_t *req, void *data); 21 | 22 | void sip_htp_get_sip_configs_detail(evhtp_request_t *req, void *data); 23 | void sip_htp_delete_sip_configs_detail(evhtp_request_t *req, void *data); 24 | 25 | void sip_htp_get_sip_peers_detail(evhtp_request_t *req, void *data); 26 | void sip_htp_get_sip_peers(evhtp_request_t *req, void *data); 27 | 28 | void sip_htp_get_sip_registries(evhtp_request_t *req, void *data); 29 | void sip_htp_get_sip_registries_detail(evhtp_request_t *req, void *data); 30 | 31 | void sip_htp_get_sip_settings(evhtp_request_t *req, void *data); 32 | void sip_htp_post_sip_settings(evhtp_request_t *req, void *data); 33 | 34 | void sip_htp_get_sip_settings_detail(evhtp_request_t *req, void *data); 35 | void sip_htp_put_sip_settings_detail(evhtp_request_t *req, void *data); 36 | 37 | 38 | // sip_peer 39 | bool sip_create_peer_info(const json_t* j_data); 40 | bool sip_update_peer_info(const json_t* j_data); 41 | bool sip_delete_peer_info(const char* key); 42 | json_t* sip_get_peers_all_peer(void); 43 | json_t* sip_get_peers_all(void); 44 | json_t* sip_get_peer_info(const char* name); 45 | 46 | // sip_registry 47 | bool sip_create_registry_info(const json_t* j_data); 48 | bool sip_update_registry_info(const json_t* j_data); 49 | bool sip_delete_registry_info(const char* key); 50 | json_t* sip_get_registries_all_account(void); 51 | json_t* sip_get_registries_all(void); 52 | json_t* sip_get_registry_info(const char* account); 53 | 54 | // sip_peeraccount 55 | bool sip_create_peeraccount_info(const json_t* j_data); 56 | json_t* sip_get_peeraccount_info(const char* peer); 57 | 58 | 59 | #endif /* SRC_SIP_HANDLER_H_ */ 60 | -------------------------------------------------------------------------------- /src/includes/ob_campaign_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * campaign_handler.h 3 | * 4 | * Created on: Nov 26, 2015 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef SRC_CAMPAIGN_HANDLER_H_ 9 | #define SRC_CAMPAIGN_HANDLER_H_ 10 | 11 | #include 12 | #include 13 | 14 | typedef enum _E_CAMP_STATUS_T 15 | { 16 | // static status 17 | E_CAMP_STOP = 0, 18 | E_CAMP_START = 1, 19 | E_CAMP_PAUSE = 2, 20 | // E_CAMP_SCHEDULE_STOP = 3, 21 | 22 | // on going status 23 | E_CAMP_STOPPING = 10, 24 | E_CAMP_STARTING = 11, 25 | E_CAMP_PAUSING = 12, 26 | // E_CAMP_SCHEDULE_STOPPING = 13, 27 | 28 | // force status 29 | E_CAMP_STOPPING_FORCE = 30, 30 | } E_CAMP_STATUS_T; 31 | 32 | typedef enum _E_CAMP_SCHEDULE_MODE 33 | { 34 | E_CAMP_SCHEDULE_OFF = 0, 35 | E_CAMP_SCHEDULE_ON = 1, 36 | } E_CAMP_SCHEDULE_MODE; 37 | 38 | json_t* ob_create_campaign(json_t* j_camp); 39 | json_t* ob_delete_campaign(const char* uuid); 40 | json_t* ob_update_campaign(const json_t* j_camp); 41 | bool ob_update_campaign_status(const char* uuid, E_CAMP_STATUS_T status); 42 | 43 | json_t* ob_get_campaign(const char* uuid); 44 | json_t* ob_get_campaign_for_dialing(void); 45 | json_t* ob_get_campaign_stat(const char* uuid); 46 | json_t* ob_get_campaigns_all(void); 47 | json_t* ob_get_campaigns_all_uuid(void); 48 | json_t* ob_get_campaigns_schedule_start(void); 49 | json_t* ob_get_campaigns_schedule_end(void); 50 | json_t* ob_get_campaigns_by_status(E_CAMP_STATUS_T status); 51 | json_t* ob_get_campaigns_stat_all(void); 52 | 53 | bool ob_is_referenced_destination_by_campaign(const char* uuid_dest); 54 | bool ob_is_referenced_dlma_by_campaign(const char* uuid_dlma); 55 | bool ob_is_referenced_plan_by_campaign(const char* uuid_plan); 56 | 57 | bool ob_clear_campaign_destination(const char* uuid_dest); 58 | bool ob_clear_campaign_dlma(const char* uuid_dlma); 59 | bool ob_clear_campaign_plan(const char* uuid_plan); 60 | 61 | bool ob_is_stoppable_campgain(json_t* j_camp); 62 | bool ob_is_startable_campgain(json_t* j_camp); 63 | bool ob_is_exist_campaign(const char* uuid); 64 | bool ob_validate_campaign(json_t* j_data); 65 | 66 | #endif /* SRC_CAMPAIGN_HANDLER_H_ */ 67 | -------------------------------------------------------------------------------- /src/includes/manager_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * manager_handler.h 3 | * 4 | * Created on: Apr 20, 2018 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef SRC_INCLUDES_MANAGER_HANDLER_H_ 9 | #define SRC_INCLUDES_MANAGER_HANDLER_H_ 10 | 11 | #include 12 | #include 13 | 14 | bool manager_init_handler(void); 15 | bool manager_term_handler(void); 16 | bool manager_reload_handler(void); 17 | 18 | json_t* manager_get_subscribable_topics_all(const json_t* j_user); 19 | 20 | // http handlers 21 | 22 | // login 23 | void manager_htp_post_manager_login(evhtp_request_t *req, void *data); 24 | void manager_htp_delete_manager_login(evhtp_request_t *req, void *data); 25 | 26 | // info 27 | void manager_htp_get_manager_info(evhtp_request_t *req, void *data); 28 | void manager_htp_put_manager_info(evhtp_request_t *req, void *data); 29 | 30 | // users 31 | void manager_htp_get_manager_users(evhtp_request_t *req, void *data); 32 | void manager_htp_post_manager_users(evhtp_request_t *req, void *data); 33 | 34 | void manager_htp_get_manager_users_detail(evhtp_request_t *req, void *data); 35 | void manager_htp_put_manager_users_detail(evhtp_request_t *req, void *data); 36 | void manager_htp_delete_manager_users_detail(evhtp_request_t *req, void *data); 37 | 38 | // trunks 39 | void manager_htp_post_manager_trunks(evhtp_request_t *req, void *data); 40 | void manager_htp_get_manager_trunks(evhtp_request_t *req, void *data); 41 | 42 | void manager_htp_get_manager_trunks_detail(evhtp_request_t *req, void *data); 43 | void manager_htp_put_manager_trunks_detail(evhtp_request_t *req, void *data); 44 | void manager_htp_delete_manager_trunks_detail(evhtp_request_t *req, void *data); 45 | 46 | // sdialplans 47 | void manager_htp_get_manager_sdialplans(evhtp_request_t *req, void *data); 48 | void manager_htp_post_manager_sdialplans(evhtp_request_t *req, void *data); 49 | 50 | void manager_htp_get_manager_sdialplans_detail(evhtp_request_t *req, void *data); 51 | void manager_htp_put_manager_sdialplans_detail(evhtp_request_t *req, void *data); 52 | void manager_htp_delete_manager_sdialplans_detail(evhtp_request_t *req, void *data); 53 | 54 | #endif /* SRC_INCLUDES_MANAGER_HANDLER_H_ */ 55 | -------------------------------------------------------------------------------- /src/includes/queue_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * queue_handler.h 3 | * 4 | * Created on: Dec 14, 2017 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef SRC_QUEUE_HANDLER_H_ 9 | #define SRC_QUEUE_HANDLER_H_ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | bool queue_init_handler(void); 16 | bool queue_reload_handler(void); 17 | bool queue_term_handler(void); 18 | 19 | // param 20 | json_t* queue_get_queue_param_info(const char* name); 21 | json_t* queue_get_queue_params_all(void); 22 | bool queue_create_param_info(const json_t* j_tmp); 23 | 24 | // member 25 | json_t* queue_get_members_all(void); 26 | json_t* queue_get_members_all_by_queuename(const char* name); 27 | json_t* queue_get_member_info(const char* id); 28 | bool queue_create_member_info(const json_t* j_data); 29 | bool queue_update_member_info(const json_t* j_data); 30 | bool queue_delete_member_info(const char* key); 31 | 32 | // entry 33 | json_t* queue_get_entries_all_by_queuename(const char* name); 34 | json_t* queue_get_entries_all(void); 35 | json_t* queue_get_entry_info(const char* key); 36 | bool queue_create_entry_info(const json_t* j_tmp); 37 | bool queue_delete_entry_info(const char* key); 38 | 39 | // cfg 40 | json_t* queue_cfg_get_queues_all(void); 41 | json_t* queue_cfg_get_queue_info(const char* name); 42 | bool queue_cfg_create_queue_info(const json_t* j_data); 43 | bool queue_cfg_update_queue_info(const json_t* j_data); 44 | bool queue_cfg_delete_queue_info(const char* name); 45 | 46 | // configuration 47 | json_t* queue_get_configurations_all(void); 48 | json_t* queue_get_configuration_info(const char* name); 49 | bool queue_update_configuration_info(const json_t* j_data); 50 | bool queue_delete_configuration_info(const char* name); 51 | 52 | // action 53 | bool queue_action_update_member_paused_penalty(const json_t* j_data); 54 | bool queue_action_delete_member_from_queue(const char* id); 55 | bool queue_action_add_member_to_queue(const json_t* j_data); 56 | 57 | // callback 58 | bool queue_register_callback_db_entry(bool (*func)(enum EN_RESOURCE_UPDATE_TYPES, const json_t*)); 59 | bool queue_register_callback_db_member(bool (*func)(enum EN_RESOURCE_UPDATE_TYPES, const json_t*)); 60 | 61 | #endif /* SRC_QUEUE_HANDLER_H_ */ 62 | -------------------------------------------------------------------------------- /src/includes/utils.h: -------------------------------------------------------------------------------- 1 | /* 2 | * utils.h 3 | * 4 | * Created on: Feb 2, 2017 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef BACKEND_SRC_UTILS_H_ 9 | #define BACKEND_SRC_UTILS_H_ 10 | 11 | #include 12 | #include 13 | #include 14 | 15 | #define sfree(p) { if(p != NULL) free(p); p=NULL; } 16 | 17 | #define DEF_UTILS_MAX_CALLBACKS 256 18 | 19 | 20 | enum EN_RESOURCE_UPDATE_TYPES { 21 | EN_RESOURCE_CREATE = 1, 22 | EN_RESOURCE_UPDATE = 2, 23 | EN_RESOURCE_DELETE = 3, 24 | 25 | EN_RESOURCE_LOAD = 10, 26 | EN_RESOURCE_UNLOAD = 11, 27 | EN_RESOURCE_RELOAD = 12, 28 | }; 29 | 30 | struct st_callback { 31 | bool (*callback[DEF_UTILS_MAX_CALLBACKS])(enum EN_RESOURCE_UPDATE_TYPES, const json_t*); 32 | int count; 33 | }; 34 | 35 | void utils_trim(char * s); 36 | 37 | char* utils_gen_uuid(void); 38 | char* utils_get_utc_timestamp(void); 39 | int utils_get_utc_timestamp_day(void); 40 | char* utils_get_utc_timestamp_date(void); 41 | char* utils_get_utc_timestamp_time(void); 42 | char* utils_get_utc_timestamp_using_timespec(struct timespec timeptr); 43 | time_t utils_get_unixtime_from_utc_timestamp(const char* timestamp); 44 | 45 | char* utils_get_variables_info_ami_str_from_string(const char* str); 46 | char* utils_get_variables_ami_str_from_object(json_t* j_variables); 47 | 48 | char* utils_uri_decode(const char* uri); 49 | char* utils_uri_encode(const char* uri); 50 | int utils_convert_time_string(const char* time, const char* format); 51 | char* utils_strip_ext(char *fname); 52 | 53 | 54 | bool utils_is_string_exist_in_file(const char* filename, const char* str); 55 | bool utils_append_string_to_file_end(const char* filename, const char* str); 56 | bool utils_create_empty_file(const char* filename); 57 | 58 | char* utils_string_replace_char(const char* str, const char org, const char target); 59 | 60 | bool utils_register_callback(struct st_callback* callback, bool (*func)(enum EN_RESOURCE_UPDATE_TYPES, const json_t*)); 61 | struct st_callback* utils_create_callback(void); 62 | void utils_terminate_callback(struct st_callback* callback); 63 | 64 | void utils_execute_callbacks(struct st_callback* callbacks, enum EN_RESOURCE_UPDATE_TYPES type, const json_t* j_data); 65 | 66 | #endif /* BACKEND_SRC_UTILS_H_ */ 67 | -------------------------------------------------------------------------------- /src/includes/chat_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * chat_handler.h 3 | * 4 | * Created on: Mar 26, 2018 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef SRC_INCLUDES_CHAT_HANDLER_H_ 9 | #define SRC_INCLUDES_CHAT_HANDLER_H_ 10 | 11 | 12 | #include 13 | #include 14 | 15 | enum EN_CHAT_ROOM_TYPE { 16 | EN_CHAT_ROOM_SINGLE = 1, 17 | EN_CHAT_ROOM_GROUP = 2, 18 | }; 19 | 20 | bool chat_init_handler(void); 21 | bool chat_term_handler(void); 22 | 23 | bool chat_register_callback_room(bool (*func)(enum EN_RESOURCE_UPDATE_TYPES, const json_t*)); 24 | bool chat_register_callback_userroom(bool (*func)(enum EN_RESOURCE_UPDATE_TYPES, const json_t*)); 25 | bool chat_register_callback_message(bool (*func)(enum EN_RESOURCE_UPDATE_TYPES, const json_t*)); 26 | 27 | json_t* chat_get_room(const char* uuid); 28 | json_t* chat_get_rooms_by_useruuid(const char* user_uuid); 29 | bool chat_create_room_with_foreach_userroom(const char* uuid, const char* uuid_user, const json_t* j_data); 30 | bool chat_delete_room(const char* uuid); 31 | 32 | bool chat_delete_info_by_useruuid(const char* uuid_user); 33 | 34 | json_t* chat_get_userrooms_by_useruuid(const char* user_uuid); 35 | 36 | json_t* chat_get_userroom(const char* uuid); 37 | json_t* chat_get_userrooms_by_roomuuid(const char* uuid); 38 | bool chat_create_userroom(const char* uuid_user, const char* uuid_userroom, const json_t* j_data); 39 | bool chat_update_userroom(const char* uuid_userroom, const json_t* j_data); 40 | bool chat_delete_userroom(const char* uuid_userroom); 41 | 42 | bool chat_create_message_to_userroom(const char* uuid_message, const char* uuid_userroom, const char* uuid_user, const json_t* message); 43 | json_t* chat_get_userroom_messages_newest(const char* uuid_userroom, const char* timestamp, const unsigned int count); 44 | 45 | json_t* chat_get_messages_newest_of_room(const char* uuid_room, const char* timestamp, const unsigned int count); 46 | json_t* chat_get_message_info_by_userroom(const char* uuid_message, const char* uuid_userroom); 47 | json_t* chat_get_message_info(const char* table_name, const char* uuid); 48 | 49 | char* chat_get_uuidroom_by_uuiduserroom(const char* uuid_userroom); 50 | json_t* chat_get_members_by_userroom(const char* uuid_userroom); 51 | 52 | bool chat_is_user_userroom_owned(const char* uuid_user, const char* uuid_userroom); 53 | 54 | 55 | #endif /* SRC_INCLUDES_CHAT_HANDLER_H_ */ 56 | -------------------------------------------------------------------------------- /src/modules/agent_handler.c: -------------------------------------------------------------------------------- 1 | /* 2 | * agent_handler.c 3 | * 4 | * Created on: Dec 12, 2017 5 | * Author: pchero 6 | */ 7 | 8 | 9 | #include 10 | 11 | #include "http_handler.h" 12 | #include "resource_handler.h" 13 | #include "slog.h" 14 | #include "utils.h" 15 | 16 | #include "agent_handler.h" 17 | 18 | /** 19 | * GET ^/agent/agents request handler. 20 | * @param req 21 | * @param data 22 | */ 23 | void agent_htp_get_agent_agents(evhtp_request_t *req, void *data) 24 | { 25 | json_t* j_res; 26 | json_t* j_tmp; 27 | 28 | if(req == NULL) { 29 | slog(LOG_WARNING, "Wrong input parameter."); 30 | return; 31 | } 32 | slog(LOG_INFO, "Fired htp_get_agent_agents."); 33 | 34 | j_tmp = get_agent_agents_all(); 35 | if(j_tmp == NULL) { 36 | http_simple_response_error(req, EVHTP_RES_SERVERR, 0, NULL); 37 | return; 38 | } 39 | 40 | // create result 41 | j_res = http_create_default_result(EVHTP_RES_OK); 42 | json_object_set_new(j_res, "result", json_object()); 43 | json_object_set_new(json_object_get(j_res, "result"), "list", j_tmp); 44 | 45 | http_simple_response_normal(req, j_res); 46 | json_decref(j_res); 47 | 48 | return; 49 | } 50 | 51 | 52 | /** 53 | * GET ^/agent/agents/(*) request handler. 54 | * @param req 55 | * @param data 56 | */ 57 | void agent_htp_get_agent_agents_detail(evhtp_request_t *req, void *data) 58 | { 59 | json_t* j_res; 60 | json_t* j_tmp; 61 | char* detail; 62 | 63 | if(req == NULL) { 64 | slog(LOG_WARNING, "Wrong input parameter."); 65 | return; 66 | } 67 | slog(LOG_INFO, "Fired htp_get_agent_agents_detail."); 68 | 69 | // get detail 70 | detail = http_get_parsed_detail(req); 71 | if(detail == NULL) { 72 | slog(LOG_NOTICE, "Could not get id info."); 73 | http_simple_response_error(req, EVHTP_RES_BADREQ, 0, NULL); 74 | return; 75 | } 76 | 77 | // get channel info. 78 | j_tmp = get_agent_agent_info(detail); 79 | sfree(detail); 80 | if(j_tmp == NULL) { 81 | slog(LOG_NOTICE, "Could not get agent info."); 82 | http_simple_response_error(req, EVHTP_RES_NOTFOUND, 0, NULL); 83 | return; 84 | } 85 | 86 | // create result 87 | j_res = http_create_default_result(EVHTP_RES_OK); 88 | json_object_set_new(j_res, "result", j_tmp); 89 | 90 | http_simple_response_normal(req, j_res); 91 | json_decref(j_res); 92 | 93 | return; 94 | } 95 | 96 | -------------------------------------------------------------------------------- /src/main/base64.c: -------------------------------------------------------------------------------- 1 | /* 2 | * base64.c 3 | * 4 | * Created on: Feb 1, 2018 5 | * Author: pchero 6 | */ 7 | 8 | 9 | /*! 10 | \file base64.c 11 | \brief 12 | \author Sungtae Kim 13 | \date Aug 18, 2014 14 | */ 15 | 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | /** 23 | * Calculates the length of a decoded base64 string 24 | * @param b64input 25 | * @return 26 | */ 27 | static int calcDecodeLength(const char* b64input) 28 | { 29 | int len = strlen(b64input); 30 | int padding = 0; 31 | 32 | if (b64input[len-1] == '=' && b64input[len-2] == '=') { //last two chars are = 33 | padding = 2; 34 | } 35 | else if (b64input[len-1] == '=') { //last char is = 36 | padding = 1; 37 | } 38 | 39 | return (int)len*0.75 - padding; 40 | } 41 | 42 | /** 43 | * Decodes a base64 encoded string 44 | * @param b64message 45 | * @param buffer 46 | * @return 47 | */ 48 | int base64decode(char* b64message, char** buffer) 49 | { 50 | BIO *bio, *b64; 51 | int decodeLen = calcDecodeLength(b64message), 52 | len = 0; 53 | *buffer = (char*)malloc(decodeLen+1); 54 | FILE* stream = fmemopen(b64message, strlen(b64message), "r"); 55 | 56 | b64 = BIO_new(BIO_f_base64()); 57 | bio = BIO_new_fp(stream, BIO_NOCLOSE); 58 | bio = BIO_push(b64, bio); 59 | BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); //Do not use newlines to flush buffer 60 | len = BIO_read(bio, *buffer, strlen(b64message)); 61 | //Can test here if len == decodeLen - if not, then return an error 62 | (*buffer)[len] = '\0'; 63 | 64 | BIO_free_all(bio); 65 | fclose(stream); 66 | 67 | return (0); //success 68 | } 69 | 70 | /** 71 | * Encodes a string to base64 72 | * @param message 73 | * @param buffer 74 | * @return 75 | */ 76 | int base64encode(const char* message, char** buffer) 77 | { 78 | BIO *bio, *b64; 79 | FILE* stream; 80 | int encodedSize = 4*ceil((double)strlen(message)/3); 81 | *buffer = (char *)malloc(encodedSize+1); 82 | 83 | stream = fmemopen(*buffer, encodedSize+1, "w"); 84 | b64 = BIO_new(BIO_f_base64()); 85 | bio = BIO_new_fp(stream, BIO_NOCLOSE); 86 | bio = BIO_push(b64, bio); 87 | BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL); //Ignore newlines - write everything in one line 88 | BIO_write(bio, message, strlen(message)); 89 | BIO_flush(bio); 90 | BIO_free_all(bio); 91 | fclose(stream); 92 | 93 | return (0); //success 94 | } 95 | -------------------------------------------------------------------------------- /test/test_device_states.py: -------------------------------------------------------------------------------- 1 | import common 2 | import ast 3 | import json 4 | import subprocess 5 | 6 | 7 | def check_device_states_data_types(j_data): 8 | 9 | if j_data["device"] == None or isinstance(j_data["device"], str) != True: 10 | print("Type error. device. type[%s]" % type(j_data["device"])) 11 | return False 12 | 13 | 14 | if j_data["state"] == None or isinstance(j_data["state"], str) != True: 15 | print("Type error. state. type[%s]" % type(j_data["state"])) 16 | return False 17 | 18 | 19 | return True 20 | 21 | 22 | def test_default_return_device_states(): 23 | url = "127.0.0.1:8081/device_states" 24 | ret_code, ret_data = common.http_send(url, "GET", None) 25 | ret_json = ast.literal_eval(ret_data) 26 | if ret_code != 200: 27 | print("Return value error") 28 | return False 29 | 30 | if "api_ver" not in ret_json \ 31 | or "timestamp" not in ret_json \ 32 | or "statuscode" not in ret_json \ 33 | or "result" not in ret_json: 34 | 35 | print("Return value error") 36 | return False 37 | 38 | 39 | if "list" not in ret_json["result"] : 40 | print("Return value error") 41 | return False 42 | 43 | print("Finished test_default_return_device_states.") 44 | return True 45 | 46 | 47 | def test_default_return_device_states_detail_type_check(): 48 | 49 | # get first id 50 | cmd = ["curl", "-s", "-X", "GET", "127.0.0.1:8081/device_states"] 51 | ret_data = subprocess.check_output(cmd, stderr=subprocess.STDOUT) 52 | ret_json = ast.literal_eval(ret_data) 53 | j_res = ret_json["result"]["list"][0] 54 | id = j_res["device"] 55 | 56 | # send request 57 | cmd = ["curl", "-s", "-X", "GET", "127.0.0.1:8081/device_states/", "-d", "{\"device\": \"%s\"}" % id] 58 | ret_data = subprocess.check_output(cmd, stderr=subprocess.STDOUT) 59 | ret_json = ast.literal_eval(ret_data) 60 | j_res = ret_json["result"] 61 | 62 | ret = check_device_states_data_types(j_res) 63 | if ret != True: 64 | return False 65 | 66 | 67 | print("Finished test_default_return_systems_detail_type_check.") 68 | 69 | return True 70 | 71 | 72 | #### Test 73 | 74 | 75 | print("test_device_states") 76 | ret = test_default_return_device_states() 77 | if ret != True: 78 | raise 79 | 80 | ret = test_default_return_device_states_detail_type_check() 81 | if ret != True: 82 | raise 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /src/includes/ob_dl_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * dl_handler.h 3 | * 4 | * Created on: Nov 29, 2015 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef SRC_DL_HANDLER_H_ 9 | #define SRC_DL_HANDLER_H_ 10 | 11 | #include 12 | #include 13 | 14 | #include "ob_dialing_handler.h" 15 | 16 | /** 17 | * dl_list.status 18 | */ 19 | typedef enum _E_DL_STATUS_T 20 | { 21 | E_DL_STATUS_IDLE = 0, //!< idle 22 | E_DL_STATUS_DIALING = 1, //!< dialing 23 | E_DL_STATUS_RESERVED = 2, //!< reserved for preview dialing 24 | // E_DL_QUEUEING = 2, ///< not in used. 25 | } E_DL_STATUS_T; 26 | 27 | int ob_get_current_dialing_dl_cnt(const char* camp_uuid, const char* dl_table); 28 | int ob_get_dial_num_point(json_t* j_dl_list, json_t* j_plan); 29 | int ob_get_dial_try_cnt(json_t* j_dl_list, int dial_num_point); 30 | 31 | json_t* ob_get_dl(const char* uuid); 32 | json_t* ob_get_dls_uuid_by_dlma_count(const char* dlma_uuid, int count); 33 | json_t* ob_get_dls_by_dlma_count(const char* dlma_uuid, int count); 34 | json_t* ob_get_dls_by_count(int count); 35 | json_t* ob_get_dls_by_status(E_DL_STATUS_T status); 36 | json_t* ob_get_dls_error(void); 37 | 38 | json_t* ob_create_dl(json_t* j_dl); 39 | json_t* ob_update_dl(json_t* j_dl); 40 | json_t* ob_delete_dl(const char* uuid); 41 | bool ob_delete_dls_by_dlma_uuid(const char* dlma_uuid); 42 | bool ob_delete_dl_list(const char* uuid); 43 | bool ob_validate_dl(json_t* j_dl); 44 | 45 | int ob_get_dl_count_by_dlma_uuid(const char* dlma_uuid); 46 | int ob_get_dl_list_cnt_total(json_t* j_dlma); 47 | int ob_get_dl_list_cnt_finshed(json_t* j_dlma, json_t* j_plan); 48 | int ob_get_dl_list_cnt_available(json_t* j_dlma, json_t* j_plan); 49 | int ob_get_dl_list_cnt_dialing(json_t* j_dlma); 50 | int ob_get_dl_list_cnt_tried(json_t* j_dlma); 51 | 52 | json_t* ob_get_dl_available_for_dial(json_t* j_dlma, json_t* j_plan); 53 | bool ob_is_endable_dl_list(json_t* j_dlma, json_t* j_plan); 54 | void ob_clear_dl_list_dialing(const char* uuid); 55 | 56 | json_t* ob_create_dial_info(json_t* j_plan, json_t* j_dl_list, json_t* j_dest); 57 | json_t* ob_create_json_for_dl_result(json_t* j_dialing); 58 | 59 | bool ob_update_dl_after_originate(json_t* dialing); 60 | bool ob_update_dl_status(const char* uuid, E_DL_STATUS_T status); 61 | bool ob_update_dl_hangup( 62 | const char* uuid, 63 | int res_dial, 64 | const char* res_dial_detail, 65 | int res_hangup, 66 | const char* res_hangup_detail 67 | ); 68 | 69 | bool ob_is_dlma_exist(const char* uuid); 70 | bool ob_is_dl_exsit(const char* uuid); 71 | 72 | #endif /* SRC_DL_HANDLER_H_ */ 73 | -------------------------------------------------------------------------------- /src/main/action_handler.c: -------------------------------------------------------------------------------- 1 | /* 2 | * action_handler.c 3 | * 4 | * Created on: Feb 15, 2017 5 | * Author: pchero 6 | */ 7 | 8 | #define _GNU_SOURCE 9 | 10 | #include 11 | #include 12 | 13 | #include "common.h" 14 | #include "slog.h" 15 | #include "utils.h" 16 | #include "action_handler.h" 17 | 18 | bool action_insert(const char* id, const char* type, const json_t* j_data) 19 | { 20 | int ret; 21 | json_t* j_tmp; 22 | json_t* j_data_tmp; 23 | 24 | if((id == NULL) || (type == NULL)) { 25 | slog(LOG_WARNING, "Wrong input parameter."); 26 | return false; 27 | } 28 | 29 | j_tmp = json_pack("{s:s, s:s}", 30 | "id", id, 31 | "type", type 32 | ); 33 | if(j_tmp == NULL) { 34 | slog(LOG_ERR, "Could not create action object."); 35 | return false; 36 | } 37 | 38 | // data 39 | if(j_data != NULL) { 40 | j_data_tmp = json_deep_copy(j_data); 41 | json_object_set_new(j_tmp, "data", j_data_tmp); 42 | } 43 | 44 | ret = db_ctx_insert(g_db_memory, "action", j_tmp); 45 | json_decref(j_tmp); 46 | if(ret == false) { 47 | slog(LOG_ERR, "Could not insert action info."); 48 | return false; 49 | } 50 | 51 | return true; 52 | } 53 | 54 | json_t* action_get(const char* id) 55 | { 56 | char* sql; 57 | int ret; 58 | json_t* j_res; 59 | 60 | if(id == NULL) { 61 | slog(LOG_WARNING, "Wrong input parameter."); 62 | return NULL; 63 | } 64 | 65 | asprintf(&sql, "select * from action where id=\"%s\";", id); 66 | 67 | ret = db_ctx_query(g_db_memory, sql); 68 | sfree(sql); 69 | if(ret == false) { 70 | slog(LOG_ERR, "Could not get correct action info."); 71 | return NULL; 72 | } 73 | 74 | j_res = db_ctx_get_record(g_db_memory); 75 | db_ctx_free(g_db_memory); 76 | if(j_res == NULL) { 77 | // no result. 78 | return NULL; 79 | } 80 | 81 | return j_res; 82 | } 83 | 84 | bool action_delete(const char* id) 85 | { 86 | char* sql; 87 | int ret; 88 | 89 | if(id == NULL) { 90 | slog(LOG_WARNING, "Wrong input parameter."); 91 | return false; 92 | } 93 | 94 | asprintf(&sql, "delete from action where id=\"%s\";", id); 95 | 96 | ret = db_ctx_exec(g_db_memory, sql); 97 | sfree(sql); 98 | if(ret == false) { 99 | return false; 100 | } 101 | 102 | return true; 103 | } 104 | 105 | json_t* action_get_and_delete(const char* id) 106 | { 107 | json_t* j_res; 108 | 109 | if(id == NULL) { 110 | slog(LOG_WARNING, "Wrong parameter."); 111 | return NULL; 112 | } 113 | 114 | j_res = action_get(id); 115 | action_delete(id); 116 | 117 | return j_res; 118 | } 119 | -------------------------------------------------------------------------------- /src/includes/conf_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * configfile_handler.h 3 | * 4 | * Created on: Jan 21, 2018 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef SRC_CONF_HANDLER_H_ 9 | #define SRC_CONF_HANDLER_H_ 10 | 11 | #include 12 | #include 13 | 14 | bool conf_init_handler(void); 15 | 16 | // object 17 | json_t* conf_get_ast_current_config_info(const char* filename); 18 | bool conf_update_ast_current_config_info(const char* filename, json_t* j_conf); 19 | 20 | bool conf_create_ast_current_config_content(const char* filename, const char* section, const char* key, const char* val); 21 | bool conf_update_ast_current_config_content(const char* filename, const char* section, const char* key, const char* val); 22 | bool conf_delete_ast_current_config_content(const char* filename, const char* section, const char* key); 23 | 24 | json_t* conf_get_ast_sections_all(const char* filename); 25 | json_t* conf_get_ast_section(const char* filename, const char* name); 26 | bool conf_create_ast_section(const char* filename, const json_t* j_data); 27 | bool conf_update_ast_section(const char* filename, const json_t* j_data); 28 | bool conf_delete_ast_section(const char* filename, const char* name); 29 | 30 | bool conf_create_ast_section_data(const char* filename, const char* name, const json_t* j_data); 31 | json_t* conf_get_ast_section_data(const char* filename, const char* name); 32 | bool conf_update_ast_section_data(const char* filename, const char* name, const json_t* j_data); 33 | 34 | json_t* conf_get_ast_backup_configs_text_all(const char* filename); 35 | json_t* conf_get_ast_backup_config_info(const char* filename); 36 | bool conf_remove_ast_backup_config_info_valid(const char* filename, const char* valid); 37 | 38 | // array 39 | json_t* conf_get_ast_current_config_info_array(const char* filename); 40 | bool conf_update_ast_current_config_info_array(const char* filename, json_t* j_conf); 41 | 42 | bool conf_create_ast_section_array(const char* filename, const char* name, const json_t* j_data); 43 | bool conf_update_ast_section_array(const char* filename, const char* name, const json_t* j_data); 44 | bool conf_delete_ast_section_array(const char* filename, const char* name); 45 | 46 | // text 47 | json_t* conf_get_ast_current_config_info_text(const char* filename); 48 | bool conf_update_ast_current_config_info_text(const json_t* j_data); 49 | bool conf_update_ast_current_config_info_text_data(const char* filename, const char* data); 50 | 51 | json_t* conf_get_ast_backup_config_info_text(const char* filename); 52 | json_t* conf_get_ast_backup_config_info_text_valid(const char* filename, const char* valid); 53 | 54 | // etc 55 | bool conf_add_external_config_file(const char* filename, const char* external_filename); 56 | bool conf_is_exist_config_file(const char* filename); 57 | 58 | #endif /* SRC_CONF_HANDLER_H_ */ 59 | -------------------------------------------------------------------------------- /src/main/call_handler.c: -------------------------------------------------------------------------------- 1 | /* 2 | * call_handler.c 3 | * 4 | * Asterisk's channel resource handler. 5 | * And provide useful interface for call/channel. 6 | * Created on: Apr 13, 2018 7 | * Author: pchero 8 | */ 9 | 10 | #define _GNU_SOURCE 11 | 12 | #include 13 | #include 14 | 15 | 16 | #include "slog.h" 17 | #include "resource_handler.h" 18 | #include "publication_handler.h" 19 | #include "utils.h" 20 | #include "dialplan_handler.h" 21 | #include "ami_action_handler.h" 22 | #include "core_handler.h" 23 | 24 | #include "call_handler.h" 25 | 26 | 27 | bool call_hangup_by_unique_id(const char* unique_id) 28 | { 29 | int ret; 30 | const char* channel; 31 | json_t* j_tmp; 32 | 33 | if(unique_id == NULL) { 34 | slog(LOG_WARNING, "Wrong input parameter."); 35 | return false; 36 | } 37 | 38 | j_tmp = core_get_channel_info(unique_id); 39 | if(j_tmp == NULL) { 40 | slog(LOG_NOTICE, "Could not get channel info."); 41 | return false; 42 | } 43 | 44 | channel = json_string_value(json_object_get(j_tmp, "channel")); 45 | if(channel == NULL) { 46 | slog(LOG_NOTICE, "Could not get channel name."); 47 | json_decref(j_tmp); 48 | return false; 49 | } 50 | 51 | ret = ami_action_hangup(channel); 52 | json_decref(j_tmp); 53 | if(ret == false) { 54 | slog(LOG_NOTICE, "Could not send hangup request."); 55 | return false; 56 | } 57 | 58 | return true; 59 | } 60 | 61 | 62 | /** 63 | * Originate call from the source device to destination device. 64 | * @param source 65 | * @param destination 66 | * @return 67 | */ 68 | bool call_originate_call_to_device(const char* source, const char* destination) 69 | { 70 | int ret; 71 | char* data; 72 | char* channel; 73 | char* dpma_uuid; 74 | 75 | if((source == NULL) || (destination == NULL)) { 76 | slog(LOG_WARNING, "Wrong input parameter."); 77 | return false; 78 | } 79 | slog(LOG_DEBUG, "Fired call_originate_call_to_device. source[%s], destination[%s]", source, destination); 80 | 81 | // get default dpma for originate to device 82 | dpma_uuid = dialplan_get_default_dpma_originate_to_device(); 83 | if(dpma_uuid == NULL) { 84 | slog(LOG_ERR, "Could not get default dpma originate to device."); 85 | return false; 86 | } 87 | 88 | // create data 89 | asprintf(&data, "agi:async,%s,%s,%s", 90 | DEF_DIALPLAN_JADE_AGI_NAME, 91 | dpma_uuid, 92 | destination 93 | ); 94 | sfree(dpma_uuid); 95 | 96 | // create channel 97 | asprintf(&channel, "PJSIP/%s", source); 98 | 99 | // send request 100 | ret = ami_action_originate_application(channel, "AGI", data); 101 | sfree(channel); 102 | sfree(data); 103 | if(ret == false) { 104 | slog(LOG_ERR, "Could not send originate request to device info."); 105 | return false; 106 | } 107 | 108 | return true; 109 | } 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | -------------------------------------------------------------------------------- /doc/source/glossary.rst: -------------------------------------------------------------------------------- 1 | .. _glossary: 2 | 3 | ******** 4 | Glossary 5 | ******** 6 | 7 | Terms 8 | ===== 9 | 10 | .. _timestamp: 11 | 12 | #. Timestamp 13 | 14 | 15 | Requirement levels indicator 16 | ============================ 17 | This document strives to adhere to :rfc:`2119`. In particular should be noted tat: 18 | 19 | 20 | #. MUST This word, or the terms "REQUIRED" or "SHALL", mean that the 21 | definition is an absolute requirement of the specification. 22 | 23 | #. MUST NOT This phrase, or the phrase "SHALL NOT", mean that the 24 | definition is an absolute prohibition of the specification. 25 | 26 | #. SHOULD This word, or the adjective "RECOMMENDED", mean that there 27 | may exist valid reasons in particular circumstances to ignore a 28 | particular item, but the full implications must be understood and 29 | carefully weighed before choosing a different course. 30 | 31 | #. SHOULD NOT This phrase, or the phrase "NOT RECOMMENDED" mean that 32 | there may exist valid reasons in particular circumstances when the 33 | particular behavior is acceptable or even useful, but the full 34 | implications should be understood and the case carefully weighed 35 | before implementing any behavior described with this label. 36 | 37 | #. MAY This word, or the adjective "OPTIONAL", mean that an item is 38 | truly optional. One vendor may choose to include the item because a 39 | particular marketplace requires it or because the vendor feels that 40 | it enhances the product while another vendor may omit the same item. 41 | An implementation which does not include a particular option MUST be 42 | prepared to interoperate with another implementation which does 43 | include the option, though perhaps with reduced functionality. In the 44 | same vein an implementation which does include a particular option 45 | MUST be prepared to interoperate with another implementation which 46 | does not include the option (except, of course, for the feature the 47 | option provides.) 48 | 49 | #. Guidance in the use of these Imperatives 50 | 51 | Imperatives of the type defined in this memo must be used with care 52 | and sparingly. In particular, they MUST only be used where it is 53 | actually required for interoperation or to limit behavior which has 54 | potential for causing harm (e.g., limiting retransmisssions) For 55 | example, they must not be used to try to impose a particular method 56 | on implementors where the method is not required for 57 | interoperability. 58 | 59 | #. Security Considerations 60 | 61 | These terms are frequently used to specify behavior with security 62 | implications. The effects on security of not implementing a MUST or 63 | SHOULD, or doing something the specification says MUST NOT or SHOULD 64 | NOT be done may be very subtle. Document authors should take the time 65 | to elaborate the security implications of not following 66 | recommendations or requirements as most implementors will not have 67 | had the benefit of the experience and discussion that produced the 68 | specification. 69 | 70 | -------------------------------------------------------------------------------- /src/includes/ob_dialing_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * dialing_handler.h 3 | * 4 | * Created on: Nov 21, 2015 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef SRC_DIALING_HANDLER_H_ 9 | #define SRC_DIALING_HANDLER_H_ 10 | 11 | #include 12 | #include 13 | 14 | typedef enum _E_DIALING_STATUS_T 15 | { 16 | // normal status 17 | E_DIALING_NONE = 0, ///< None state 18 | E_DIALING_ORIGINATE_REQUESTED = 1, ///< originate request sent 19 | E_DIALING_ORIGINATE_QUEUED, ///< originate request queued 20 | E_DIALING_DIAL_BEGIN, ///< dial begin 21 | E_DIALING_CHANNEL_CREATE, ///< channel created 22 | E_DIALING_DIAL_END, ///< dial end 23 | E_DIALING_ORIGINATE_RESPONSED, ///< originate response 24 | E_DIALING_HANGUP, ///< hangup 25 | 26 | // errors 27 | E_DIALING_ERROR_UNKNOWN = 100, ///< error 28 | E_DIALING_ERROR_ORIGINATE_REQUEST_FAILED, ///< Could not send originate request 29 | E_DIALING_ERROR_ORIGINATE_QUEUED_FAILED, ///< Could not originate queued 30 | E_DIALING_ERROR_ORIGINATE_RESPONSE_FAILED, ///< originate response was wrong 31 | E_DIALING_ERROR_UPDATE_TIMEOUT, ///< update timestamp timeout 32 | } E_DIALING_STATUS_T; 33 | 34 | typedef struct _rb_dialing{ 35 | char* uuid; ///< dialing uuid(channel's unique id) 36 | char* name; ///< dialing name(channel's name) 37 | E_DIALING_STATUS_T status; ///< dialing status 38 | 39 | char* tm_create; 40 | char* tm_update; 41 | char* tm_delete; 42 | struct timespec timeptr_update; ///< timestamp for timeout 43 | 44 | json_t* j_dialing; ///< dialing info(result). 45 | json_t* j_event; ///< current channel status info(the latest event) 46 | json_t* j_events; ///< event info(json array). 47 | } rb_dialing; 48 | 49 | json_t* ob_create_dialing(const char* dialing_uuid, json_t* j_camp, json_t* j_plan, json_t* j_dlma, json_t* j_dest, json_t* j_dl_list, json_t* j_dial); 50 | bool ob_delete_dialing(const char* uuid); 51 | bool ob_insert_dialing(json_t* j_dialing); 52 | bool ob_is_exist_dialing(const char* uuid); 53 | 54 | bool ob_update_dialing_hangup(const char* uuid, int hangup, const char* hangup_detail); 55 | bool ob_update_dialing_res_dial(const char* uuid, bool success, int res_dial, const char* channel); 56 | 57 | bool ob_update_dialing_status(const char* uuid, E_DIALING_STATUS_T status); 58 | bool ob_update_dialing_timestamp(const char* uuid); 59 | 60 | json_t* ob_get_dialings_uuid_all(void); 61 | json_t* ob_get_dialings_all_uuid(void); 62 | json_t* ob_get_dialings_all(void); 63 | json_t* ob_get_dialing_by_action_id(const char* action_id); 64 | json_t* ob_get_dialing(const char* uuid); 65 | json_t* ob_get_dialings_timeout(void); 66 | json_t* ob_get_dialings_hangup(void); 67 | json_t* ob_get_dialings_error(void); 68 | int ob_get_dialing_count_by_camp_uuid(const char* camp_uuid); 69 | 70 | bool ob_send_dialing_hangup_request(const char* uuid); 71 | 72 | void ob_destroy_rb_dialing(rb_dialing* dialing); 73 | bool ob_process_dialing_finish(const char* uuid); 74 | 75 | 76 | #endif /* SRC_DIALING_HANDLER_H_ */ 77 | -------------------------------------------------------------------------------- /src/includes/user_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * user_handler.h 3 | * 4 | * Created on: Feb 1, 2018 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef SRC_MAIN_USER_HANDLER_H_ 9 | #define SRC_MAIN_USER_HANDLER_H_ 10 | 11 | #include 12 | #include 13 | #include "resource_handler.h" 14 | #include "utils.h" 15 | 16 | 17 | #define DEF_USER_CONTACT_TYPE_PEER "sip_peer" 18 | #define DEF_USER_CONTACT_TYPE_ENDPOINT "pjsip_endpoint" 19 | 20 | bool user_init_handler(void); 21 | void user_term_handler(void); 22 | bool user_reload_handler(void); 23 | 24 | // callback register 25 | bool user_register_callback_db_userinfo(bool (*func)(enum EN_RESOURCE_UPDATE_TYPES, const json_t*)); 26 | bool user_register_callback_db_permission(bool (*func)(enum EN_RESOURCE_UPDATE_TYPES, const json_t*)); 27 | bool user_reigster_callback_db_buddy(bool (*func)(enum EN_RESOURCE_UPDATE_TYPES, const json_t*)); 28 | 29 | // userinfo 30 | json_t* user_get_userinfo_info(const char* key); 31 | json_t* user_get_userinfo_info_by_username(const char* key); 32 | json_t* user_get_userinfo_info_by_username_password(const char* username, const char* pass); 33 | json_t* user_get_userinfo_by_authtoken(const char* authtoken); 34 | bool user_create_userinfo(const char* uuid, const json_t* j_data); 35 | bool user_update_userinfo_info(const char* uuid_user, const json_t* j_data); 36 | bool user_delete_userinfo_info(const char* key); 37 | bool user_delete_related_info_by_useruuid(const char* uuid_user); 38 | json_t* user_get_userinfos_all(void); 39 | 40 | // authtoken 41 | json_t* user_get_authtokens_all(void); 42 | json_t* user_get_authtokens_user_type(const char* uuid_user, const char* type); 43 | json_t* user_get_authtoken_info(const char* key); 44 | bool user_update_authtoken_tm_update(const char* uuid); 45 | bool user_delete_authtoken_info(const char* key); 46 | 47 | // permission 48 | json_t* user_get_permissions_all(void); 49 | json_t* user_get_permissions_by_useruuid(const char* uuid_user); 50 | bool user_create_permission_info(const json_t* j_data); 51 | json_t* user_get_permission_info(const char* uuid_permission); 52 | json_t* user_get_permission_info_by_useruuid_perm(const char* useruuid, const char* perm); 53 | bool user_delete_permission_info(const char* key); 54 | bool user_delete_permissions_by_useruuid(const char* uuid_user); 55 | 56 | // contact 57 | json_t* user_get_contacts_all(void); 58 | json_t* user_get_contacts_by_user_uuid(const char* user_uuid); 59 | json_t* user_get_contact_info(const char* key); 60 | bool user_create_contact_info(const json_t* j_data); 61 | bool user_update_contact_info(const char* key, const json_t* j_data); 62 | bool user_delete_contact_info(const char* key); 63 | 64 | 65 | // buddy 66 | json_t* user_get_buddies_info_by_owneruuid(const char* uuid_user); 67 | json_t* user_get_buddy_info(const char* uuid); 68 | bool user_create_buddy_info(const char* uuid, const json_t* j_data); 69 | bool user_update_buddy_info(const json_t* j_data); 70 | bool user_delete_buddy_info(const char* uuid); 71 | 72 | bool user_is_user_exist(const char* user_uuid); 73 | bool user_is_user_owned_buddy(const char* uuid_owner, const char* uuid_buddy); 74 | 75 | // authtoken 76 | char* user_create_authtoken(const char* username, const char* password, const char* type); 77 | 78 | 79 | #endif /* SRC_MAIN_USER_HANDLER_H_ */ 80 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Covenant Code of Conduct 2 | 3 | ## Our Pledge 4 | 5 | In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. 6 | 7 | ## Our Standards 8 | 9 | Examples of behavior that contributes to creating a positive environment include: 10 | 11 | * Using welcoming and inclusive language 12 | * Being respectful of differing viewpoints and experiences 13 | * Gracefully accepting constructive criticism 14 | * Focusing on what is best for the community 15 | * Showing empathy towards other community members 16 | 17 | Examples of unacceptable behavior by participants include: 18 | 19 | * The use of sexualized language or imagery and unwelcome sexual attention or advances 20 | * Trolling, insulting/derogatory comments, and personal or political attacks 21 | * Public or private harassment 22 | * Publishing others' private information, such as a physical or electronic address, without explicit permission 23 | * Other conduct which could reasonably be considered inappropriate in a professional setting 24 | 25 | ## Our Responsibilities 26 | 27 | Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. 28 | 29 | Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. 30 | 31 | ## Scope 32 | 33 | This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. 34 | 35 | ## Enforcement 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at pchero21@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. 38 | 39 | Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. 40 | 41 | ## Attribution 42 | 43 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] 44 | 45 | [homepage]: http://contributor-covenant.org 46 | [version]: http://contributor-covenant.org/version/1/4/ 47 | -------------------------------------------------------------------------------- /doc/source/installation.rst: -------------------------------------------------------------------------------- 1 | .. installation 2 | 3 | ************ 4 | Installation 5 | ************ 6 | 7 | SSL certification 8 | ================= 9 | Need to create certification file for ssl connection. 10 | :: 11 | 12 | $ sudo openssl req -subj '/CN=US/O=Jade project/C=US' -x509 -nodes -days 3650 -newkey rsa:2048 -keyout /opt/etc/server.key -out /opt/etc/server.crt 13 | $ cat /opt/etc/server.crt /opt/etc/server.key > /opt/etc/jade.pem 14 | 15 | Asterisk 16 | ======== 17 | Required Asterisk-13.6 or later 18 | 19 | Asterisk settings 20 | ----------------- 21 | 22 | chan_sip.so 23 | +++++++++++ 24 | Disable the chan_sip module. 25 | :: 26 | 27 | asterisk*CLI> module unload chan_sip.so 28 | 29 | res_pjsip.so 30 | ++++++++++++ 31 | Enable the res_pjsip module 32 | :: 33 | 34 | asterisk*CLI> module load res_pjsip.so 35 | 36 | 37 | Config manager.conf 38 | +++++++++++++++++++ 39 | Enable and set up the ami user. 40 | :: 41 | 42 | /etc/asterisk/manager.conf 43 | 44 | [general] 45 | enabled = yes 46 | port = 5038 47 | bindaddr = 0.0.0.0 48 | 49 | [admin] 50 | secret = admin ; this is not secure. need to be changed. 51 | deny = 0.0.0.0/0.0.0.0 52 | permit = 127.0.0.1/255.255.255.0 53 | read = all 54 | write = all 55 | 56 | 57 | Reload manager module 58 | :: 59 | 60 | asterisk*CLI> module reload manager 61 | Module 'manager' reloaded successfully. 62 | 63 | asterisk*CLI> manager show user admin 64 | 65 | username: admin 66 | secret: 67 | ACL: yes 68 | read perm: system,call,log,verbose,command,agent,user,config,dtmf,reporting,cdr,dialplan,originate,agi,cc,aoc,test,security,message,all 69 | write perm: system,call,log,verbose,command,agent,user,config,dtmf,reporting,cdr,dialplan,originate,agi,cc,aoc,test,security,message,all 70 | displayconnects: yes 71 | allowmultiplelogin: yes 72 | Variables: 73 | 74 | 75 | Config http.conf 76 | ++++++++++++++++ 77 | Need to configure the http.conf options. 78 | :: 79 | 80 | /etc/asterisk/http.conf 81 | 82 | [general] 83 | servername=Asterisk 84 | enabled=yes 85 | bindaddr=0.0.0.0 86 | bindport=8088 87 | tlsenable=yes 88 | tlsbindaddr=0.0.0.0:8089 89 | tlscertfile=/opt/etc/jade.pem 90 | 91 | 92 | Required libraries 93 | ================== 94 | :: 95 | 96 | libsqlite3 97 | libevent2 98 | libbsd 99 | libjansson 100 | libevhtp 101 | libssl 102 | libzmq5 103 | libonig 104 | 105 | Libevhtp 106 | -------- 107 | Insall libevhtp 108 | :: 109 | 110 | $ mkdir -p /opt/src/libevhtp 111 | $ curl -s https://codeload.github.com/criticalstack/libevhtp/tar.gz/1.2.16 | tar xz -C /opt/src/libevhtp --strip-components=1 112 | $ cd /opt/src/libevhtp/build 113 | $ cmake .. 114 | $ make 115 | $ make install 116 | 117 | Libwebsockets 118 | ------------- 119 | Install libwebsockets 120 | :: 121 | 122 | $ mkdir -p /opt/src/libwebsockets 123 | $ curl -s https://codeload.github.com/warmcat/libwebsockets/tar.gz/v2.4.2 | tar xz -C /opt/src/libwebsockets --strip-components=1 124 | $ cd /opt/src/libwebsockets/build 125 | $ cmake -DLWS_WITH_LIBEVENT=1 ../ 126 | $ make 127 | $ make install 128 | 129 | Install jade 130 | ============ 131 | 132 | :: 133 | 134 | $ cd 135 | $ cd src/ 136 | $ make 137 | $ sudo mkdir -p /opt/bin 138 | $ sudo mv jade_backend /opt/bin 139 | 140 | -------------------------------------------------------------------------------- /src/main/misc_handler.c: -------------------------------------------------------------------------------- 1 | /* 2 | * misc_handler.c 3 | * 4 | * Created on: Dec 17, 2017 5 | * Author: pchero 6 | */ 7 | 8 | #define _GNU_SOURCE 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "common.h" 18 | #include "slog.h" 19 | #include "utils.h" 20 | #include "resource_handler.h" 21 | #include "ami_action_handler.h" 22 | #include "core_handler.h" 23 | 24 | #include "misc_handler.h" 25 | 26 | extern app* g_app; 27 | 28 | static bool init_modules_info(void); 29 | 30 | 31 | bool misc_init_handler(void) 32 | { 33 | int ret; 34 | 35 | ret = init_modules_info(); 36 | if(ret == false) { 37 | slog(LOG_ERR, "Could not initiate module info."); 38 | return false; 39 | } 40 | 41 | return true; 42 | } 43 | 44 | /** 45 | * Check installed asterisk modules and update into db. 46 | * And send module check request to the Asterisk. 47 | * @return 48 | */ 49 | static bool init_modules_info(void) 50 | { 51 | json_t* j_tmp; 52 | struct dirent **namelist; 53 | int i; 54 | int cnt; 55 | const char* module_name; 56 | char* full_filename; 57 | const char* dir; 58 | struct stat file_stat; 59 | int ret; 60 | char* timestamp; 61 | 62 | 63 | dir = json_string_value(json_object_get(json_object_get(g_app->j_conf, "general"), "directory_module")); 64 | if(dir == NULL) { 65 | slog(LOG_ERR, "Could not get lib directory info."); 66 | return false; 67 | } 68 | 69 | // get directory info. 70 | cnt = scandir(dir, &namelist, NULL, versionsort); 71 | if(cnt < 0) { 72 | if(errno == ENOENT) { 73 | // just empty directory 74 | return true; 75 | } 76 | slog(LOG_ERR, "Could not get directory info. err[%d:%s]", errno, strerror(errno)); 77 | return false; 78 | } 79 | 80 | // get file info 81 | timestamp = utils_get_utc_timestamp(); 82 | for(i = 0; i < cnt; i++) { 83 | // get stat 84 | asprintf(&full_filename, "%s/%s", dir, namelist[i]->d_name); 85 | ret = stat(full_filename, &file_stat); 86 | sfree(full_filename); 87 | if(ret != 0) { 88 | slog(LOG_ERR, "Could not get file info. filename[%s], err[%d:%s]", full_filename, errno, strerror(errno)); 89 | free(namelist[i]); 90 | continue; 91 | } 92 | 93 | ret = strcmp(namelist[i]->d_name, "."); 94 | if(ret == 0) { 95 | free(namelist[i]); 96 | continue; 97 | } 98 | ret = strcmp(namelist[i]->d_name, ".."); 99 | if(ret == 0) { 100 | free(namelist[i]); 101 | continue; 102 | } 103 | 104 | // strip extension 105 | // module_name = strip_ext(namelist[i]->d_name); 106 | module_name = namelist[i]->d_name; 107 | if(module_name == NULL) { 108 | slog(LOG_ERR, "Could not strip file info."); 109 | free(namelist[i]); 110 | continue; 111 | } 112 | 113 | // create data 114 | j_tmp = json_pack("{s:s, s:i, s:s, s:s}", 115 | "name", module_name, 116 | "size", file_stat.st_size, 117 | "load", "unknown", 118 | 119 | "tm_update", timestamp 120 | ); 121 | 122 | // insert 123 | ret = core_create_module(j_tmp); 124 | json_decref(j_tmp); 125 | if(ret == true) { 126 | // send modulecheck request 127 | ami_action_modulecheck(module_name); 128 | } 129 | 130 | free(namelist[i]); 131 | } 132 | free(namelist); 133 | sfree(timestamp); 134 | 135 | return true; 136 | } 137 | 138 | 139 | -------------------------------------------------------------------------------- /doc/source/park_event.rst: -------------------------------------------------------------------------------- 1 | .. _park_event: 2 | 3 | .. _park_parkedcall: 4 | 5 | park.parkedcall 6 | =============== 7 | Notify park parkedcall event. 8 | 9 | .. _park_pakedcall_create: 10 | 11 | core.channel.create 12 | ------------------- 13 | Notify event for core channel create. 14 | 15 | Topic 16 | +++++ 17 | :: 18 | 19 | /park/parkinglots/ 20 | 21 | * ``target``: URI encoded parking lot. 22 | 23 | Event 24 | +++++ 25 | :: 26 | 27 | { 28 | "park.parkedcall.create": { 29 | ... 30 | } 31 | } 32 | 33 | * See detail at parkedcall info. 34 | 35 | Example 36 | +++++++ 37 | :: 38 | 39 | topic: /park/parkinglots/default 40 | 41 | { 42 | "park.parkedcall.create": { 43 | "parkee_unique_id": "1514424631.119", 44 | "parking_lot": "default", 45 | "parkee_caller_id_num": "pjagent-01", 46 | "parkee_exten": "s", 47 | "parkee_linked_id": "1514424631.119", 48 | "parkee_connected_line_num": "", 49 | "parkee_channel": "PJSIP/pjagent-01-00000048", 50 | "parkee_account_code": "", 51 | "parkee_caller_id_name": "pjagent-01", 52 | "parkee_channel_state_desc": "Up", 53 | "tm_update": "2017-12-28T01:30:31.382834514Z", 54 | "parkee_channel_state": "6", 55 | "parking_timeout": 45, 56 | "parkee_connected_line_name": "", 57 | "parkee_context": "sample_park", 58 | "parker_dial_string": "PJSIP/pjagent-01", 59 | "parking_duration": 0, 60 | "parkee_priority": "2", 61 | "parking_space": "701" 62 | } 63 | } 64 | 65 | 66 | .. _park_parkedcall_update: 67 | 68 | park.parkedcall.update 69 | ---------------------- 70 | Notify event for park parkedcall update. 71 | 72 | Topic 73 | +++++ 74 | :: 75 | 76 | /park/parkinglots/ 77 | 78 | * ``target``: URI encoded parking lot. 79 | 80 | Event 81 | +++++ 82 | :: 83 | 84 | { 85 | "park.parkedcall.update": { 86 | ... 87 | } 88 | } 89 | 90 | * See detail at parkedcall info. 91 | 92 | Example 93 | +++++++ 94 | :: 95 | 96 | ... 97 | 98 | 99 | .. _park_parkedcall_delete: 100 | 101 | park.parkedcall.delete 102 | ---------------------- 103 | Notify event for park parkedcall delete. 104 | 105 | Topic 106 | +++++ 107 | :: 108 | 109 | /park/parkinglots/ 110 | 111 | * ``target``: URI encoded parking lot. 112 | 113 | Event 114 | +++++ 115 | :: 116 | 117 | { 118 | "park.parkedcall.delete": { 119 | ... 120 | } 121 | } 122 | 123 | * See detail at parkedcall info. 124 | 125 | Example 126 | +++++++ 127 | :: 128 | 129 | topic: /park/parkinglots/default 130 | 131 | { 132 | "park.parkedcall.delete": { 133 | "parkee_unique_id": "1514425145.127", 134 | "parking_lot": "default", 135 | "parkee_caller_id_num": "pjagent-01", 136 | "parkee_exten": "s", 137 | "parkee_linked_id": "1514425145.127", 138 | "parkee_connected_line_num": "", 139 | "parkee_channel": "PJSIP/pjagent-01-0000004c", 140 | "parkee_account_code": "", 141 | "parkee_caller_id_name": "pjagent-01", 142 | "parkee_channel_state_desc": "Up", 143 | "tm_update": "2017-12-28T01:39:05.298799696Z", 144 | "parkee_channel_state": "6", 145 | "parking_timeout": 45, 146 | "parkee_connected_line_name": "", 147 | "parkee_context": "sample_park", 148 | "parker_dial_string": "PJSIP/pjagent-01", 149 | "parking_duration": 0, 150 | "parkee_priority": "2", 151 | "parking_space": "701" 152 | } 153 | } 154 | 155 | -------------------------------------------------------------------------------- /src/includes/resource_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * resource_handler.h 3 | * 4 | * Created on: Feb 10, 2017 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef BACKEND_SRC_RESOURCE_HANDLER_H_ 9 | #define BACKEND_SRC_RESOURCE_HANDLER_H_ 10 | 11 | #include 12 | #include 13 | 14 | enum EN_SORT_TYPES { 15 | EN_SORT_ASC, 16 | EN_SORT_DESC, 17 | }; 18 | 19 | 20 | bool resource_init_handler(void); 21 | void resource_term_handler(void); 22 | 23 | // memory 24 | bool resource_exec_mem_sql(const char* sql); 25 | bool resource_clear_mem_table(const char* table); 26 | bool resource_insert_mem_item(const char* table, const json_t* j_data); 27 | bool resource_insrep_mem_item(const char* table, const json_t* j_data); 28 | bool resource_update_mem_item(const char* table, const char* key_column, const json_t* j_data); 29 | json_t* resource_get_mem_items(const char* table, const char* item); 30 | json_t* resource_get_mem_detail_item_key_string(const char* table, const char* key, const char* val); 31 | json_t* resource_get_mem_detail_items_by_condtion(const char* table, const char* condition); 32 | json_t* resource_get_mem_detail_items_key_string(const char* table, const char* key, const char* val); 33 | bool resource_delete_mem_items_string(const char* table, const char* key, const char* val); 34 | 35 | // file 36 | bool resource_exec_file_sql(const char* sql); 37 | bool resource_insert_file_item(const char* table, const json_t* j_data); 38 | bool resource_insrep_file_item(const char* table, const json_t* j_data); 39 | bool resource_update_file_item(const char* table, const char* key_column, const json_t* j_data); 40 | bool resource_delete_file_items_string(const char* table, const char* key, const char* val); 41 | bool resource_delete_file_items_by_obj(const char* table, json_t* j_obj); 42 | json_t* resource_get_file_items(const char* table, const char* item); 43 | json_t* resource_get_file_detail_item_key_string(const char* table, const char* key, const char* val); 44 | json_t* resource_get_file_detail_item_by_obj(const char* table, json_t* j_obj); 45 | json_t* resource_get_file_detail_items_key_string(const char* table, const char* key, const char* val); 46 | json_t* resource_get_file_detail_items_by_obj(const char* table, json_t* j_obj); 47 | json_t* resource_get_file_detail_items_by_obj_order(const char* table, json_t* j_obj, const char* order); 48 | json_t* resource_get_file_detail_items_by_condtion(const char* table, const char* condition); 49 | 50 | // etc 51 | json_t* resource_sort_json_array_string(const json_t* j_data, enum EN_SORT_TYPES type); 52 | 53 | 54 | 55 | //////// agent 56 | // agent 57 | bool create_agent_agent_info(const json_t* j_data); 58 | bool update_agent_agent_info(const json_t* j_data); 59 | bool delete_agent_agent_info(const char* key); 60 | json_t* get_agent_agents_all_id(void); 61 | json_t* get_agent_agents_all(void); 62 | json_t* get_agent_agent_info(const char* id); 63 | 64 | 65 | ////// core 66 | // core_agi 67 | json_t* get_core_agis_all(void); 68 | json_t* get_core_agi_info(const char* unique_id); 69 | bool create_core_agi_info(const json_t* j_data); 70 | bool update_core_agi_info(const json_t* j_data); 71 | bool update_core_agi_info_cmd_result_done(const char* agi_uuid, const char* cmd_id, const char* result_org); 72 | 73 | bool delete_core_agi_info(const char* key); 74 | bool add_core_agi_info_cmd(const char* agi_uuid, const char* cmd_uuid, const char* command, const char* dp_uuid); 75 | // core_system 76 | // core_module 77 | 78 | 79 | 80 | // database 81 | json_t* get_databases_all_key(void); 82 | json_t* get_database_info(const char* key); 83 | 84 | 85 | // device_state 86 | json_t* get_device_states_all_device(void); 87 | json_t* get_device_state_info(const char* device); 88 | 89 | 90 | ////// voicemail 91 | 92 | // voicemail 93 | bool create_voicemail_user_info(json_t* j_tmp); 94 | json_t* get_voicemail_user_info(const char* key); 95 | json_t* get_voicemail_users_all(); 96 | 97 | 98 | #endif /* BACKEND_SRC_RESOURCE_HANDLER_H_ */ 99 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Jade 2 | ==== 3 | [![Travis Build Status](https://travis-ci.org/pchero/jade.svg)](https://travis-ci.org/pchero/jade) 4 | 5 | The jade is a free and open source unified communication system, which can fulfill a variety of roles for a range of industries and organizations who wish to contact to large numbers of people by phone or else in a short space of time. 6 | 7 | The jade has been built using an Asterisk so that it can support almost everything about the Asterisk's features. 8 | 9 | The jade can be used by anyone who has a need for mass outbound/inbound calling, voicemail system, agent call distributing, call recording and IVR service. 10 | Or may be used by other companies who wish to make calls on their own behalf, or by SaaS (Software as a Service) companies that want to provide bulk dialling and SMS broadcasting facilities to their own customers. 11 | 12 | ## Features 13 | - Restful API 14 | - Event subscription via ZeroMQ and Websocket 15 | - Strategical inbound/outbound call distributing 16 | - Asterisk resource control 17 | - Chatting 18 | - Buddy managing 19 | - WebRTC Call 20 | - Dialplan 21 | - Trunk 22 | - SMS(WIP) 23 | - Mail(WIP) 24 | - Video call(WIP) 25 | - Conference call(WIP) 26 | - XMPP(WIP) 27 | 28 | ## Manual 29 | * https://jade-asterisk.readthedocs.io/en/latest/index.html 30 | 31 | ## Docker 32 | * All pre-setting Asterisk and jade project on a docker is ready. 33 | * $ docker pull pchero/jade-asterisk 34 | * https://github.com/pchero/jade-asterisk 35 | * https://hub.docker.com/r/pchero/jade-asterisk/ 36 | 37 | ## Demo 38 | * jade 39 | * You can try apis to here. 40 | * http://project.pchero21.com:8081 41 | 42 | * jade-me 43 | * https://github.com/pchero/jade-me 44 | * Simple user tool for jade. 45 | * You can try jade-me web application at here. 46 | * ID/Password 47 | * test1/test1, test2/test2, ... 48 | * https://project.pchero21.com:8202 49 | 50 | ## Related project 51 | * jade-me(https://github.com/pchero/jade-me) 52 | * ![Alt Text](https://raw.githubusercontent.com/pchero/jade-me/master/jade-me.gif) 53 | * Angular based simple web application for jade user. 54 | * Chat, Voice call, Buddy services. 55 | 56 | * jade-manager(https://github.com/pchero/jade-manager) 57 | * ![Screen Preview](https://raw.githubusercontent.com/pchero/jade-manager/master/jade-manager.png) 58 | * Angular based simple web application for jade manager. 59 | * Provide simplized of resource handling. 60 | * Easy to add/modify/delete the resources such as user, trunk. 61 | 62 | * jade-admin(https://github.com/pchero/jade-admin) 63 | * ![Screen Preview](https://raw.githubusercontent.com/pchero/jade-admin/master/jade-admin.png) 64 | * Angular based simple web application for jade adminstrator. 65 | * Provide micro level of resource handling. 66 | 67 | * jade-agent(https://github.com/pchero/jade-agent) 68 | * Angular based simple web application for jade. 69 | * Agent tools for jade. 70 | 71 | ## Library issue 72 | * libevent 73 | * libevent-2.0.x has memory curruption problem. It's fixed in libevent-2.1.x. 74 | * It causes core crash the jade. 75 | * Need to use the libevnet-2.1.x or higher. 76 | * https://github.com/libevent/libevent/issues/335 77 | 78 | * libwebsocket 79 | * Required libevent option. 80 | * $ cd build 81 | * $ cmake -DLWS_WITH_LIBEVENT=1 ../ 82 | * $ make && sudo make install 83 | * v2.4.1 has memory leak problem(https://github.com/warmcat/libwebsockets/pull/1155) 84 | * Fixed in master branch. 85 | 86 | * libevhtp 87 | * The libevhtp repository has been changed(https://github.com/criticalstack/libevhtp). 88 | * The libevhtp-v1.2.10, v1.2.11, v1.2.11n has memory leak problem(https://github.com/ellzey/libevhtp/issues/177). 89 | * It was fixed in develop branch. Recommand use the newst develop branch(https://github.com/ellzey/libevhtp.git). 90 | 91 | ## License 92 | * BSD License 93 | 94 | ## Remember 2014.04.16 95 | * Still remember 2014.04.16 96 | * Rest in peace.. 97 | * https://en.wikipedia.org/wiki/Sinking_of_MV_Sewol 98 | -------------------------------------------------------------------------------- /src/includes/pjsip_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * pjsip_handler.h 3 | * 4 | * Created on: Dec 13, 2017 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef SRC_PJSIP_HANDLER_H_ 9 | #define SRC_PJSIP_HANDLER_H_ 10 | 11 | #include 12 | 13 | 14 | bool pjsip_init_handler(void); 15 | bool pjsip_reload_handler(void); 16 | bool pjsip_term_handler(void); 17 | 18 | bool pjsip_register_callback_module(bool (*func)(enum EN_RESOURCE_UPDATE_TYPES, const json_t*)); 19 | bool pjsip_register_callback_db_registration_outbound(bool (*func)(enum EN_RESOURCE_UPDATE_TYPES, const json_t*)); 20 | bool pjsip_register_callback_cfg_endpoint(bool (*func)(enum EN_RESOURCE_UPDATE_TYPES, const json_t*)); 21 | 22 | // endpoint 23 | bool pjsip_create_endpoint_info(const json_t* j_data); 24 | bool pjsip_update_endpoint_info(const json_t* j_data); 25 | bool pjsip_delete_endpoint_info(const char* key); 26 | json_t* pjsip_get_endpoints_all(void); 27 | json_t* pjsip_get_endpoint_info(const char* name); 28 | 29 | // auth 30 | bool pjsip_create_auth_info(const json_t* j_data); 31 | bool pjsip_update_auth_info(const json_t* j_data); 32 | bool pjsip_delete_auth_info(const char* key); 33 | json_t* pjsip_get_auths_all(void); 34 | json_t* pjsip_get_auth_info(const char* key); 35 | 36 | // aor 37 | bool pjsip_create_aor_info(const json_t* j_data); 38 | bool pjsip_update_aor_info(const json_t* j_data); 39 | bool pjsip_delete_aor_info(const char* key); 40 | json_t* pjsip_get_aors_all(void); 41 | json_t* pjsip_get_aor_info(const char* key); 42 | 43 | // contact 44 | bool pjsip_create_contact_info(const json_t* j_data); 45 | bool pjsip_update_contact_info(const json_t* j_data); 46 | bool pjsip_delete_contact_info(const char* key); 47 | json_t* pjsip_get_contacts_all(void); 48 | json_t* pjsip_get_contact_info(const char* key); 49 | 50 | // registration_inbound 51 | bool pjsip_create_registration_inbound_info(const json_t* j_data); 52 | bool pjsip_update_registration_inbound_info(const json_t* j_data); 53 | bool pjsip_delete_registration_inbound_info(const char* key); 54 | 55 | // registration outbound 56 | json_t* pjsip_get_registration_outbounds_all(void); 57 | json_t* pjsip_get_registration_outbound_info(const char* key); 58 | bool pjsip_create_registration_outbound_info(const json_t* j_data); 59 | bool pjsip_update_registration_outbound_info(const json_t* j_data); 60 | bool pjsip_delete_registration_outbound_info(const char* key); 61 | 62 | // account(aor, auth, endpoint) 63 | bool pjsip_create_account_with_default_setting(const char* target, const char* context); 64 | bool pjsip_delete_account(const char* target_name); 65 | 66 | bool pjsip_is_exist_endpoint(const char* target); 67 | bool pjsip_reload_config(void); 68 | 69 | json_t* pjsip_cfg_get_aor_info_data(const char* name); 70 | bool pjsip_cfg_create_aor_info(const char* name, const char* contact); 71 | bool pjsip_cfg_update_aor_info_data(const char* name, const json_t* j_data); 72 | bool pjsip_cfg_delete_aor_info(const char* name); 73 | 74 | json_t* pjsip_cfg_get_auth_info_data(const char* name); 75 | bool pjsip_cfg_create_auth_info(const char* name, const char* username, const char* password); 76 | bool pjsip_cfg_update_auth_info(const char* name, const json_t* j_data); 77 | bool pjsip_cfg_delete_auth_info(const char* name); 78 | 79 | json_t* pjsip_cfg_get_contact_info_data(const char* name); 80 | bool pjsip_cfg_update_contact_info(const json_t* j_data); 81 | bool pjsip_cfg_delete_contact_info(const char* name); 82 | 83 | json_t* pjsip_cfg_get_endpoint_info_data(const char* name); 84 | bool pjsip_cfg_create_endpoint_with_default_info(const char* name, const char* context); 85 | bool pjsip_cfg_update_endpoint_info_data(const char* name, const json_t* j_data); 86 | json_t* pjsip_cfg_get_endpoint_info(const char* name); 87 | bool pjsip_cfg_delete_endpoint_info(const char* name); 88 | 89 | json_t* pjsip_cfg_get_identify_info_data(const char* name); 90 | bool pjsip_cfg_create_identify_info(const char* name, const char* match); 91 | bool pjsip_cfg_update_identify_info_data(const char* name, const json_t* j_data); 92 | bool pjsip_cfg_delete_identify_info(const char* name); 93 | 94 | json_t* pjsip_cfg_get_registrations_all(void); 95 | json_t* pjsip_cfg_get_registration_info_data(const char* name); 96 | bool pjsip_cfg_create_registration_with_default_info(const char* name, const char* server_uri, const char* client_uri); 97 | json_t* pjsip_cfg_get_registration_info(const char* name); 98 | bool pjsip_cfg_create_registration_info(const json_t* j_data); 99 | bool pjsip_cfg_update_registration_info(const json_t* j_data); 100 | bool pjsip_cfg_delete_registration_info(const char* name); 101 | 102 | json_t* pjsip_cfg_get_transport_info(const char* name); 103 | bool pjsip_cfg_create_transport_info(const json_t* j_data); 104 | bool pjsip_cfg_update_transport_info(const json_t* j_data); 105 | bool pjsip_cfg_delete_transport_info(const char* name); 106 | 107 | // configurations 108 | json_t* pjsip_get_configurations_all(void); 109 | json_t* pjsip_get_configuration_info(const char* name); 110 | bool pjsip_update_configuration_info(const json_t* j_data); 111 | bool pjsip_delete_configuration_info(const char* name); 112 | 113 | #endif /* SRC_PJSIP_HANDLER_H_ */ 114 | -------------------------------------------------------------------------------- /doc/source/ob_basic.rst: -------------------------------------------------------------------------------- 1 | .. ob_basic 2 | 3 | ************** 4 | Outbound Basic 5 | ************** 6 | 7 | Concept 8 | ======= 9 | 10 | Principle 11 | --------- 12 | The asterisk-outbound has a 5W1H principle. 13 | 14 | .. figure:: _static/Basic_concept.png 15 | :align: center 16 | 17 | Basic concept 18 | 19 | * Campaign : Determine why make a call(Why). 20 | * Plan : Determine how/when to make a call(How/When). 21 | * Destination : Determine who get a call after answer(Who). 22 | * Dial list(Dial List Master) : Determine where/what call heading for(Where/What). 23 | 24 | 25 | Features 26 | ======== 27 | 28 | Call balancing 29 | -------------- 30 | The res_outbound supports call balancing. 31 | 32 | With this feature, the res_outbound can managing the amount of outbound call depends on the destination's condition. 33 | 34 | For example, if the destination is queue, it calculate waiting agent's number and queue's performance. 35 | 36 | 37 | Stratigical retrying 38 | -------------------- 39 | The res_outbound supports the stratigical retrying. 40 | 41 | The user can set retry counts and retry delay time for each call. 42 | 43 | 44 | Customer info based dial list 45 | ----------------------------- 46 | The res_outbound supports customer based dial list. 47 | 48 | The user can set the customer's detail info such as name, detail, database key, email, ... not only for numbers 49 | And supports several types of numbers. 50 | 51 | 52 | Call capsulization 53 | ------------------ 54 | The res_outbound supports the call capsulization. 55 | 56 | When the res_outbound making a call, the call kept all the resource info itself. So, if the other resources chagned later, it doesn't affect to the existing call. 57 | 58 | It makes call-capsulization. 59 | 60 | 61 | Dynamic resource management 62 | --------------------------- 63 | The res_outbound supports the dynamic resource management. 64 | 65 | 66 | Campaign scheduling 67 | ------------------- 68 | The res_outbound supports the campaign scheduling. 69 | 70 | The user can set the auto-start, auto-end. 71 | 72 | 73 | Set variables 74 | ------------- 75 | The res_outbound supports variables setting. 76 | 77 | The user can set the variables for each resources. 78 | 79 | It can deliver to the dialplan or SIP headers. 80 | 81 | 82 | Monitoring 83 | ---------- 84 | 85 | 86 | Detail dial result 87 | ------------------ 88 | The res_outbound supports the detail dial result. 89 | 90 | In the result, the user can check the all the call info(original info, dialing info, result info). 91 | 92 | 93 | Resources 94 | ========= 95 | 96 | Campaign 97 | -------- 98 | * Set destination, plan, dial list(dlma). 99 | 100 | Destination 101 | ----------- 102 | * Call's transfer destination after customer has answered. 103 | 104 | Plan 105 | ---- 106 | Dialling stragegy. 107 | * UUI delivery. 108 | * Dial mode 109 | * Dialing control. 110 | 111 | Dial list 112 | --------- 113 | Customer info list. 114 | * Dial number. 115 | * UUI info. 116 | 117 | Campaign 118 | ======== 119 | Determine why make a call(Why). 120 | 121 | To dial to the customer, the user need to create the campaign first and need to assign the correct resources(destination, plan, dial list master). 122 | 123 | Then the resources determine where/what/who/how/when make a call to the customer. 124 | 125 | Status 126 | ------ 127 | The campaign has a status. See detail :ref:`campaign_status`. 128 | 129 | Scheduling 130 | ---------- 131 | The user can sets scheduling for campaign. See detail :ref:`scheduling`. 132 | 133 | 134 | Plan 135 | ==== 136 | Determine how/when to make a call(How/When). 137 | 138 | Dial mode 139 | --------- 140 | The user can sets the dial mode. See detail :ref:`ob_dial_mode`. 141 | 142 | Predictive 143 | ++++++++++ 144 | * Predict the number of customers to dial based on the deliver application/agent's answer rate. 145 | * Predict how many call will be answered or not answered. 146 | * Calculate possilbilties automatically. 147 | 148 | Preview 149 | +++++++ 150 | * The destination makes decision to make a call. 151 | * Developing. 152 | 153 | SMS 154 | +++ 155 | * Send an SMS messages 156 | * Developing. 157 | 158 | Fax 159 | +++ 160 | * Send a fax 161 | * Developing. 162 | 163 | 164 | Service level 165 | ------------- 166 | Service level controling the amount of dailing. 167 | 168 | 169 | .. _service_level: 170 | 171 | :: 172 | 173 | (Max available outbound call count) - (Current outbound call count) + (Service level) = (Available call count) 174 | 175 | If the (Available call count) is bigger than 0, make a call. 176 | 177 | 178 | Max available outbound call count 179 | +++++++++++++++++++++++++++++++++ 180 | 181 | The max available outbound call count is depends on the destination. 182 | 183 | See detail :ref:`destination`. 184 | 185 | 186 | .. _destination: 187 | 188 | Destination 189 | =========== 190 | Determine who get a call after answer(Who). And it determine the max available outbound call count. 191 | 192 | Normaly, the destination suppose to be an agent. But in the asterisk system, the destination could be anything. For example, it could be extension or application(queue). 193 | 194 | If the destination type is application, then the res_outbound calcaulate applciation's availablity. 195 | 196 | 197 | Result 198 | ====== 199 | Result data devided by 5 sections. 200 | 201 | Identity info, Dial info, Result info, Timestamp info, Related resources info. 202 | 203 | 204 | -------------------------------------------------------------------------------- /doc/source/manager_api.rst: -------------------------------------------------------------------------------- 1 | .. _manager_api: 2 | 3 | .. _manager_sdialplans: 4 | /manager/sdialplans 5 | =================== 6 | 7 | Methods 8 | ------- 9 | GET : Get the all static dialplans info. 10 | 11 | POST : Create static dialplan info 12 | 13 | 14 | .. _manager_sdialplans_detail: 15 | /manager/sdialplans/ 16 | ============================ 17 | 18 | Methods 19 | ------- 20 | GET : Get the given detail static dialplan info. 21 | 22 | PUT : Update the given detail static dialplan info. 23 | 24 | DELETE : Delete the given detail static dialplan info. 25 | 26 | 27 | .. _manager_trunks: 28 | /manager/trunks 29 | =============== 30 | 31 | Methods 32 | ------- 33 | GET : Get the all trunks info. 34 | 35 | POST : Create trunk info 36 | 37 | 38 | .. _manager_trunks_detail: 39 | /manager/trunks/ 40 | ======================== 41 | 42 | Methods 43 | ------- 44 | GET : Get the given detail trunk info. 45 | 46 | PUT : Update the given detail trunk info. 47 | 48 | DELETE : Delete the given detail trunk info. 49 | 50 | 51 | .. _manager_users: 52 | /manager/users 53 | ============== 54 | 55 | Methods 56 | ------- 57 | GET : Get the all users info. 58 | 59 | POST : Create user info 60 | 61 | Method: GET 62 | ----------- 63 | Get the all users info. 64 | 65 | Example 66 | +++++++ 67 | :: 68 | 69 | $ curl -k https://192.168.200.10:8081/v1/manager/users?authtoken=06d838a0-71b4-4236-8e93-b7ff59c61502 70 | 71 | { 72 | "api_ver": "0.1", 73 | "result": { 74 | "list": [ 75 | { 76 | "context": "", 77 | "name": "Test Administrator", 78 | "password": "admin", 79 | "permissions": [ 80 | { 81 | "permission": "admin" 82 | }, 83 | { 84 | "permission": "user" 85 | } 86 | ], 87 | "tm_create": "2018-04-28T05:03:36.560694725Z", 88 | "tm_update": "2018-04-28T07:10:29.116108422Z", 89 | "username": "admin", 90 | "uuid": "ed629979-802b-40f0-9098-b30b2988f9b6" 91 | }, 92 | { 93 | "context": "demo", 94 | "name": "test1", 95 | "password": "test1", 96 | "permissions": [ 97 | { 98 | "permission": "user" 99 | } 100 | ], 101 | "tm_create": "2018-04-29T07:19:00.56688782Z", 102 | "tm_update": null, 103 | "username": "test1", 104 | "uuid": "65abf0b4-9cd5-4bff-8ec9-c03c1aea22d4" 105 | } 106 | ] 107 | }, 108 | "statuscode": 200, 109 | "timestamp": "2018-05-02T13:24:50.821980931Z" 110 | } 111 | 112 | 113 | Method: POST 114 | ------------ 115 | Create user info 116 | 117 | Example 118 | +++++++ 119 | :: 120 | 121 | $ curl -k -X POST https://192.168.200.10:8081/v1/manager/users?authtoken=06d838a0-71b4-4236-8e93-b7ff59c61502 -d '{"context": "demo", "name": "test2", "username": "test2", "password": "test2", "permissions": [{"permission": "user"}]}' 122 | 123 | { 124 | "api_ver": "0.1", 125 | "statuscode": 200, 126 | "timestamp": "2018-05-02T13:28:31.201418110Z" 127 | } 128 | 129 | /manager/users/ 130 | ======================= 131 | 132 | Methods 133 | ------- 134 | GET : Get the given detail user info. 135 | 136 | PUT : Update the given detail user info. 137 | 138 | DELETE : Delete the given detail user info. 139 | 140 | .. _get_manager_users_detail: 141 | 142 | Method: GET 143 | ----------- 144 | Get the given detail user info. 145 | 146 | Example 147 | +++++++ 148 | :: 149 | 150 | $ curl -k https://192.168.200.10:8081/v1/manager/users/3305c47b-fc87-4186-b4ef-30cef0c8f5b2?authtoken=06d838a0-71b4-4236-8e93-b7ff59c61502 151 | 152 | { 153 | "api_ver": "0.1", 154 | "result": { 155 | "context": "demo", 156 | "name": "test2", 157 | "password": "test2", 158 | "permissions": [ 159 | { 160 | "permission": "user" 161 | } 162 | ], 163 | "tm_create": "2018-05-02T13:28:31.101851891Z", 164 | "tm_update": null, 165 | "username": "test2", 166 | "uuid": "3305c47b-fc87-4186-b4ef-30cef0c8f5b2" 167 | }, 168 | "statuscode": 200, 169 | "timestamp": "2018-05-02T13:30:52.782019666Z" 170 | } 171 | 172 | Method: PUT 173 | ----------- 174 | Update the given detail user info. 175 | 176 | Example 177 | +++++++ 178 | :: 179 | 180 | $ curl -k -X PUT https://192.168.200.10:8081/v1/manager/users/3305c47b-fc87-4186-b4ef-30cef0c8f5b2?authtoken=06d838a0-71b4-4236-8e93-b7ff59c61502 -d '{"context": "demo-test", "name": "test2", "username": "test2", "password": "test2", "permissions": [{"permission": "user"}]}' 181 | 182 | { 183 | "api_ver": "0.1", 184 | "statuscode": 200, 185 | "timestamp": "2018-05-02T13:38:39.731423546Z" 186 | } 187 | 188 | Method: DELETE 189 | -------------- 190 | Delete the given detail user info. 191 | 192 | Example 193 | +++++++ 194 | :: 195 | 196 | $ curl -k -X DELETE https://192.168.200.10:8081/v1/manager/users/3305c47b-fc87-4186-b4ef-30cef0c8f5b2?authtoken=06d838a0-71b4-4236-8e93-b7ff59c61502 197 | 198 | { 199 | "api_ver": "0.1", 200 | "statuscode": 200, 201 | "timestamp": "2018-05-02T13:40:24.837434999Z" 202 | } 203 | -------------------------------------------------------------------------------- /src/main/subscription_handler.c: -------------------------------------------------------------------------------- 1 | /* 2 | * subscription_handler.c 3 | * 4 | * Created on: Apr 15, 2018 5 | * Author: pchero 6 | */ 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | #include "slog.h" 13 | #include "user_handler.h" 14 | #include "me_handler.h" 15 | #include "manager_handler.h" 16 | #include "zmq_handler.h" 17 | #include "websocket_handler.h" 18 | #include "admin_handler.h" 19 | 20 | #include "subscription_handler.h" 21 | 22 | static bool subscribe_topic(void* zmq_sock, const char* topic); 23 | static bool unsubscribe_topic(void* zmq_sock, const char* topic); 24 | 25 | 26 | bool subscription_init_handler(void) 27 | { 28 | return true; 29 | } 30 | 31 | bool subscription_term_handler(void) 32 | { 33 | return true; 34 | } 35 | 36 | bool subscription_reload_handler(void) 37 | { 38 | int ret; 39 | 40 | ret = subscription_term_handler(); 41 | if(ret == false) { 42 | return false; 43 | } 44 | 45 | ret = subscription_init_handler(); 46 | if(ret == false) { 47 | return false; 48 | } 49 | 50 | return true; 51 | } 52 | 53 | /** 54 | * Add all possible subscriptionis of given authtoken user. 55 | * @param authtoken 56 | * @param zmq_sock 57 | * @return 58 | */ 59 | bool subscription_subscribe_topics_client(const char* authtoken, void* zmq_sock) 60 | { 61 | json_t* j_user; 62 | json_t* j_authtoken; 63 | json_t* j_topics; 64 | json_t* j_topic; 65 | int idx; 66 | int ret; 67 | const char* type; 68 | const char* topic; 69 | 70 | if((authtoken == NULL) || (zmq_sock == NULL)) { 71 | slog(LOG_WARNING, "Wrong input parameter."); 72 | return false; 73 | } 74 | 75 | // get userinfo 76 | j_user = user_get_userinfo_by_authtoken(authtoken); 77 | if(j_user == false) { 78 | slog(LOG_NOTICE, "Could not get user info."); 79 | return false; 80 | } 81 | 82 | j_authtoken = user_get_authtoken_info(authtoken); 83 | if(j_authtoken == NULL) { 84 | slog(LOG_NOTICE, "Could not get authtoken info."); 85 | json_decref(j_user); 86 | return false; 87 | } 88 | 89 | // get login type 90 | type = json_string_value(json_object_get(j_authtoken, "type")); 91 | if(type == NULL) { 92 | slog(LOG_NOTICE, "Could not get type info."); 93 | json_decref(j_user); 94 | json_decref(j_authtoken); 95 | return false; 96 | } 97 | 98 | // get all subscribe-able topics 99 | if(strcmp(type, "admin") == 0) { 100 | j_topics = admin_get_subscribable_topics_all(j_user); 101 | } 102 | else if(strcmp(type, "me") == 0) { 103 | j_topics = me_get_subscribable_topics_all(j_user); 104 | } 105 | else if(strcmp(type, "manager") == 0) { 106 | j_topics = manager_get_subscribable_topics_all(j_user); 107 | } 108 | 109 | if(j_topics == NULL) { 110 | slog(LOG_NOTICE, "Could not get subscribe topics."); 111 | json_decref(j_user); 112 | json_decref(j_authtoken); 113 | return false; 114 | } 115 | 116 | json_array_foreach(j_topics, idx, j_topic) { 117 | topic = json_string_value(j_topic); 118 | 119 | ret = subscribe_topic(zmq_sock, topic); 120 | if(ret == false) { 121 | slog(LOG_ERR, "Could not subscribe topic. topic[%s]", topic); 122 | continue; 123 | } 124 | } 125 | json_decref(j_topics); 126 | json_decref(j_user); 127 | json_decref(j_authtoken); 128 | 129 | return true; 130 | } 131 | 132 | static bool subscribe_topic(void* zmq_sock, const char* topic) 133 | { 134 | int ret; 135 | 136 | if((zmq_sock == NULL) || (topic == NULL)) { 137 | slog(LOG_WARNING, "Wrong input parameter."); 138 | return false; 139 | } 140 | slog(LOG_DEBUG, "Fired subscribe_topic. topic[%s]", topic); 141 | 142 | ret = zmq_setsockopt(zmq_sock, ZMQ_SUBSCRIBE, topic, strlen(topic)); 143 | if(ret != 0) { 144 | slog(LOG_ERR, "Could not subscribe topic. topic[%s], err[%d:%s]", topic, errno, strerror(errno)); 145 | return false; 146 | } 147 | 148 | return true; 149 | } 150 | 151 | static bool unsubscribe_topic(void* zmq_sock, const char* topic) 152 | { 153 | int ret; 154 | 155 | if((zmq_sock == NULL) || (topic == NULL)) { 156 | slog(LOG_WARNING, "Wrong input parameter."); 157 | return false; 158 | } 159 | slog(LOG_DEBUG, "Fired unsubscribe_topic. topic[%s]", topic); 160 | 161 | ret = zmq_setsockopt(zmq_sock, ZMQ_UNSUBSCRIBE, topic, strlen(topic)); 162 | if(ret != 0) { 163 | slog(LOG_ERR, "Could not unsubscribe topic. topic[%s], err[%d:%s]", topic, errno, strerror(errno)); 164 | return false; 165 | } 166 | 167 | return true; 168 | } 169 | 170 | bool subscription_subscribe_topic(const char* authtoken, const char* topic) 171 | { 172 | int ret; 173 | void* sock; 174 | 175 | if((authtoken == NULL) || (topic == NULL)) { 176 | slog(LOG_WARNING, "Wrong input parameter."); 177 | return false; 178 | } 179 | slog(LOG_DEBUG, "Fired subscription_subscribe_topic. authtoken[%s], topic[%s]", authtoken, topic); 180 | 181 | sock = websocket_get_subscription_socket(authtoken); 182 | if(sock == NULL) { 183 | slog(LOG_NOTICE, "Could not get subscription socket."); 184 | return false; 185 | } 186 | 187 | // subscribe topic 188 | ret = subscribe_topic(sock, topic); 189 | if(ret == false) { 190 | return false; 191 | } 192 | 193 | return true; 194 | } 195 | 196 | bool subscription_unsubscribe_topic(const char* authtoken, const char* topic) 197 | { 198 | int ret; 199 | void* sock; 200 | 201 | if((authtoken == NULL) || (topic == NULL)) { 202 | slog(LOG_WARNING, "Wrong input parameter."); 203 | return false; 204 | } 205 | slog(LOG_DEBUG, "Fired subscription_unsubscribe_topic. authtoken[%s], topic[%s]", authtoken, topic); 206 | 207 | sock = websocket_get_subscription_socket(authtoken); 208 | if(sock == NULL) { 209 | slog(LOG_NOTICE, "Could not get subscription socket."); 210 | return false; 211 | } 212 | 213 | // unsubscribe topic 214 | ret = unsubscribe_topic(sock, topic); 215 | if(ret == false) { 216 | return false; 217 | } 218 | 219 | return true; 220 | } 221 | 222 | -------------------------------------------------------------------------------- /test/test_systems.py: -------------------------------------------------------------------------------- 1 | import common 2 | import ast 3 | import json 4 | import subprocess 5 | 6 | 7 | def check_system_data_types(j_data): 8 | 9 | if j_data["id"] == None or isinstance(j_data["id"], str) != True: 10 | print("Type error. id. type[%s]" % type(j_data["id"])) 11 | return False 12 | 13 | 14 | if j_data["ami_version"] == None or isinstance(j_data["ami_version"], str) != True: 15 | print("Type error. ami_version. type[%s]" % type(j_data["ami_version"])) 16 | return False 17 | 18 | if j_data["ast_version"] == None or isinstance(j_data["ast_version"], str) != True: 19 | print("Type error. ast_version. type[%s]" % type(j_data["ast_version"])) 20 | return False 21 | 22 | if j_data["system_name"] == None or isinstance(j_data["system_name"], str) != True: 23 | print("Type error. system_name. type[%s]" % type(j_data["system_name"])) 24 | return False 25 | 26 | 27 | if j_data["startup_date"] == None or isinstance(j_data["startup_date"], str) != True: 28 | print("Type error. startup_date. type[%s]" % type(j_data["startup_date"])) 29 | return False 30 | 31 | if j_data["startup_time"] == None or isinstance(j_data["startup_time"], str) != True: 32 | print("Type error. startup_time. type[%s]" % type(j_data["startup_time"])) 33 | return False 34 | 35 | if j_data["reload_date"] == None or isinstance(j_data["reload_date"], str) != True: 36 | print("Type error. reload_date. type[%s]" % type(j_data["reload_date"])) 37 | return False 38 | 39 | if j_data["reload_time"] == None or isinstance(j_data["reload_time"], str) != True: 40 | print("Type error. reload_time. type[%s]" % type(j_data["reload_time"])) 41 | return False 42 | 43 | if isinstance(j_data["current_calls"], int) != True: 44 | print("Type error. current_calls. type[%s]" % type(j_data["current_calls"])) 45 | return False 46 | 47 | 48 | if isinstance(j_data["max_calls"], int) != True: 49 | print("Type error. max_calls. type[%s]" % type(j_data["max_calls"])) 50 | return False 51 | 52 | if isinstance(j_data["max_load_avg"], float) != True: 53 | print("Type error. max_load_avg. type[%s]" % type(j_data["max_load_avg"])) 54 | return False 55 | 56 | if isinstance(j_data["max_file_handles"], int) != True: 57 | print("Type error. max_file_handles. type[%s]" % type(j_data["max_file_handles"])) 58 | return False 59 | 60 | 61 | if j_data["run_user"] == None or isinstance(j_data["run_user"], str) != True: 62 | print("Type error. run_user. type[%s]" % type(j_data["run_user"])) 63 | return False 64 | 65 | if j_data["run_group"] == None or isinstance(j_data["run_group"], str) != True: 66 | print("Type error. run_group. type[%s]" % type(j_data["run_group"])) 67 | return False 68 | 69 | 70 | if j_data["real_time_enabled"] == None or isinstance(j_data["real_time_enabled"], str) != True: 71 | print("Type error. real_time_enabled. type[%s]" % type(j_data["real_time_enabled"])) 72 | return False 73 | 74 | if j_data["cdr_enabled"] == None or isinstance(j_data["cdr_enabled"], str) != True: 75 | print("Type error. cdr_enabled. type[%s]" % type(j_data["cdr_enabled"])) 76 | return False 77 | 78 | if j_data["http_enabled"] == None or isinstance(j_data["http_enabled"], str) != True: 79 | print("Type error. http_enabled. type[%s]" % type(j_data["http_enabled"])) 80 | return False 81 | 82 | 83 | return True 84 | 85 | 86 | def test_default_return_systems(): 87 | url = "127.0.0.1:8081/systems" 88 | ret_code, ret_data = common.http_send(url, "GET", None) 89 | ret_json = ast.literal_eval(ret_data) 90 | if ret_code != 200: 91 | print("Return value error") 92 | return False 93 | 94 | if "api_ver" not in ret_json \ 95 | or "timestamp" not in ret_json \ 96 | or "statuscode" not in ret_json \ 97 | or "result" not in ret_json: 98 | 99 | print("Return value error") 100 | return False 101 | 102 | 103 | if "list" not in ret_json["result"] : 104 | print("Return value error") 105 | return False 106 | 107 | print("Finished test_default_return_systems.") 108 | return True 109 | 110 | 111 | def test_default_return_systems(): 112 | url = "127.0.0.1:8081/systems" 113 | ret_code, ret_data = common.http_send(url, "GET", None) 114 | ret_json = ast.literal_eval(ret_data) 115 | if ret_code != 200: 116 | print("Return value error") 117 | return False 118 | 119 | if "api_ver" not in ret_json \ 120 | or "timestamp" not in ret_json \ 121 | or "statuscode" not in ret_json \ 122 | or "result" not in ret_json: 123 | 124 | print("Return value error") 125 | return False 126 | 127 | 128 | if "list" not in ret_json["result"] : 129 | print("Return value error") 130 | return False 131 | 132 | print("Finished test_default_return_systems.") 133 | return True 134 | 135 | 136 | def test_default_return_systems_detail_type_check(): 137 | 138 | # get first id 139 | cmd = ["curl", "-s", "-X", "GET", "127.0.0.1:8081/systems"] 140 | ret_data = subprocess.check_output(cmd, stderr=subprocess.STDOUT) 141 | ret_json = ast.literal_eval(ret_data) 142 | j_res = ret_json["result"]["list"][0] 143 | id = j_res["id"] 144 | 145 | # send request 146 | cmd = ["curl", "-s", "-X", "GET", "127.0.0.1:8081/systems/", "-d", "{\"id\": \"%s\"}" % id] 147 | ret_data = subprocess.check_output(cmd, stderr=subprocess.STDOUT) 148 | ret_json = ast.literal_eval(ret_data) 149 | j_res = ret_json["result"] 150 | 151 | ret = check_system_data_types(j_res) 152 | if ret != True: 153 | return False 154 | 155 | 156 | print("Finished test_default_return_systems_detail_type_check.") 157 | 158 | return True 159 | 160 | 161 | #### Test 162 | 163 | 164 | print("test_systems") 165 | ret = test_default_return_systems() 166 | if ret != True: 167 | raise 168 | 169 | ret = test_default_return_systems_detail_type_check() 170 | if ret != True: 171 | raise 172 | 173 | 174 | 175 | 176 | -------------------------------------------------------------------------------- /src/includes/minIni.h: -------------------------------------------------------------------------------- 1 | /* minIni - Multi-Platform INI file parser, suitable for embedded systems 2 | * 3 | * Copyright (c) CompuPhase, 2008-2017 4 | * 5 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not 6 | * use this file except in compliance with the License. You may obtain a copy 7 | * of the License at 8 | * 9 | * http://www.apache.org/licenses/LICENSE-2.0 10 | * 11 | * Unless required by applicable law or agreed to in writing, software 12 | * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 13 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 14 | * License for the specific language governing permissions and limitations 15 | * under the License. 16 | * 17 | * Version: $Id: minIni.h 53 2015-01-18 13:35:11Z thiadmer.riemersma@gmail.com $ 18 | */ 19 | #ifndef MININI_H 20 | #define MININI_H 21 | 22 | #include "minGlue.h" 23 | 24 | #if (defined _UNICODE || defined __UNICODE__ || defined UNICODE) && !defined INI_ANSIONLY 25 | #include 26 | #define mTCHAR TCHAR 27 | #else 28 | /* force TCHAR to be "char", but only for minIni */ 29 | #define mTCHAR char 30 | #endif 31 | 32 | #if !defined INI_BUFFERSIZE 33 | #define INI_BUFFERSIZE 512 34 | #endif 35 | 36 | #if defined __cplusplus 37 | extern "C" { 38 | #endif 39 | 40 | int ini_getbool(const mTCHAR *Section, const mTCHAR *Key, int DefValue, const mTCHAR *Filename); 41 | long ini_getl(const mTCHAR *Section, const mTCHAR *Key, long DefValue, const mTCHAR *Filename); 42 | int ini_gets(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *DefValue, mTCHAR *Buffer, int BufferSize, const mTCHAR *Filename); 43 | int ini_getsection(int idx, mTCHAR *Buffer, int BufferSize, const mTCHAR *Filename); 44 | int ini_getkey(const mTCHAR *Section, int idx, mTCHAR *Buffer, int BufferSize, const mTCHAR *Filename); 45 | 46 | #if defined INI_REAL 47 | INI_REAL ini_getf(const mTCHAR *Section, const mTCHAR *Key, INI_REAL DefValue, const mTCHAR *Filename); 48 | #endif 49 | 50 | #if !defined INI_READONLY 51 | int ini_putl(const mTCHAR *Section, const mTCHAR *Key, long Value, const mTCHAR *Filename); 52 | int ini_puts(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *Value, const mTCHAR *Filename); 53 | #if defined INI_REAL 54 | int ini_putf(const mTCHAR *Section, const mTCHAR *Key, INI_REAL Value, const mTCHAR *Filename); 55 | #endif 56 | #endif /* INI_READONLY */ 57 | 58 | #if !defined INI_NOBROWSE 59 | typedef int (*INI_CALLBACK)(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *Value, void *UserData); 60 | int ini_browse(INI_CALLBACK Callback, void *UserData, const mTCHAR *Filename); 61 | #endif /* INI_NOBROWSE */ 62 | 63 | #if defined __cplusplus 64 | } 65 | #endif 66 | 67 | 68 | #if defined __cplusplus 69 | 70 | #if defined __WXWINDOWS__ 71 | #include "wxMinIni.h" 72 | #else 73 | #include 74 | 75 | /* The C++ class in minIni.h was contributed by Steven Van Ingelgem. */ 76 | class minIni 77 | { 78 | public: 79 | minIni(const std::string& filename) : iniFilename(filename) 80 | { } 81 | 82 | bool getbool(const std::string& Section, const std::string& Key, bool DefValue=false) const 83 | { return ini_getbool(Section.c_str(), Key.c_str(), int(DefValue), iniFilename.c_str()) != 0; } 84 | 85 | long getl(const std::string& Section, const std::string& Key, long DefValue=0) const 86 | { return ini_getl(Section.c_str(), Key.c_str(), DefValue, iniFilename.c_str()); } 87 | 88 | int geti(const std::string& Section, const std::string& Key, int DefValue=0) const 89 | { return static_cast(this->getl(Section, Key, long(DefValue))); } 90 | 91 | std::string gets(const std::string& Section, const std::string& Key, const std::string& DefValue="") const 92 | { 93 | char buffer[INI_BUFFERSIZE]; 94 | ini_gets(Section.c_str(), Key.c_str(), DefValue.c_str(), buffer, INI_BUFFERSIZE, iniFilename.c_str()); 95 | return buffer; 96 | } 97 | 98 | std::string getsection(int idx) const 99 | { 100 | char buffer[INI_BUFFERSIZE]; 101 | ini_getsection(idx, buffer, INI_BUFFERSIZE, iniFilename.c_str()); 102 | return buffer; 103 | } 104 | 105 | std::string getkey(const std::string& Section, int idx) const 106 | { 107 | char buffer[INI_BUFFERSIZE]; 108 | ini_getkey(Section.c_str(), idx, buffer, INI_BUFFERSIZE, iniFilename.c_str()); 109 | return buffer; 110 | } 111 | 112 | #if defined INI_REAL 113 | INI_REAL getf(const std::string& Section, const std::string& Key, INI_REAL DefValue=0) const 114 | { return ini_getf(Section.c_str(), Key.c_str(), DefValue, iniFilename.c_str()); } 115 | #endif 116 | 117 | #if ! defined INI_READONLY 118 | bool put(const std::string& Section, const std::string& Key, long Value) const 119 | { return ini_putl(Section.c_str(), Key.c_str(), Value, iniFilename.c_str()) != 0; } 120 | 121 | bool put(const std::string& Section, const std::string& Key, int Value) const 122 | { return ini_putl(Section.c_str(), Key.c_str(), (long)Value, iniFilename.c_str()) != 0; } 123 | 124 | bool put(const std::string& Section, const std::string& Key, bool Value) const 125 | { return ini_putl(Section.c_str(), Key.c_str(), (long)Value, iniFilename.c_str()) != 0; } 126 | 127 | bool put(const std::string& Section, const std::string& Key, const std::string& Value) const 128 | { return ini_puts(Section.c_str(), Key.c_str(), Value.c_str(), iniFilename.c_str()) != 0; } 129 | 130 | bool put(const std::string& Section, const std::string& Key, const char* Value) const 131 | { return ini_puts(Section.c_str(), Key.c_str(), Value, iniFilename.c_str()) != 0; } 132 | 133 | #if defined INI_REAL 134 | bool put(const std::string& Section, const std::string& Key, INI_REAL Value) const 135 | { return ini_putf(Section.c_str(), Key.c_str(), Value, iniFilename.c_str()) != 0; } 136 | #endif 137 | 138 | bool del(const std::string& Section, const std::string& Key) const 139 | { return ini_puts(Section.c_str(), Key.c_str(), 0, iniFilename.c_str()) != 0; } 140 | 141 | bool del(const std::string& Section) const 142 | { return ini_puts(Section.c_str(), 0, 0, iniFilename.c_str()) != 0; } 143 | #endif 144 | 145 | private: 146 | std::string iniFilename; 147 | }; 148 | 149 | #endif /* __WXWINDOWS__ */ 150 | #endif /* __cplusplus */ 151 | 152 | #endif /* MININI_H */ 153 | -------------------------------------------------------------------------------- /src/main/event_handler.c: -------------------------------------------------------------------------------- 1 | /* 2 | * event_handler.c 3 | * 4 | * Created on: Feb 5, 2017 5 | * Author: pchero 6 | */ 7 | 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "common.h" 18 | #include "slog.h" 19 | #include "event_handler.h" 20 | #include "data_handler.h" 21 | #include "config.h" 22 | 23 | #define DEF_PID_FILEPATH "/var/run/jade_backend.pid" 24 | #define DEF_PID_TIMEOUT_SEC 5 25 | #define DEF_MAX_EVENT_COUNT 128 26 | 27 | extern app* g_app; 28 | struct event* g_ev_ast[DEF_MAX_EVENT_COUNT] = { NULL }; ///< asterisk events 29 | 30 | static void cb_signal_term(int sock, short which, void* arg); 31 | static void cb_signal_int(evutil_socket_t sig, short events, void *user_data); 32 | static void cb_signal_pipe(evutil_socket_t sig, short events, void *user_data); 33 | static void cb_signal_hup(evutil_socket_t sig, short events, void *user_data); 34 | 35 | static void cb_pid_update(int sock, short which, void* arg); 36 | 37 | static bool pid_update(void); 38 | 39 | 40 | bool event_init_handler(void) 41 | { 42 | struct event* ev; 43 | struct timeval tv; 44 | int ret; 45 | 46 | // initiate event base 47 | g_app->evt_base = event_base_new(); 48 | if(g_app->evt_base == NULL) { 49 | slog(LOG_ERR, "Could not initiate event_base."); 50 | return false; 51 | } 52 | 53 | //// add signal handler 54 | // sigterm 55 | ev = evsignal_new(g_app->evt_base, SIGTERM, cb_signal_term, NULL); 56 | if(ev == NULL) { 57 | slog(LOG_ERR, "Could not create event for the signal handler. signal[%s]", "SIGTERM"); 58 | return false; 59 | } 60 | ret = event_add(ev, NULL); 61 | if(ret != 0) { 62 | slog(LOG_ERR, "Could not add the signal handler. signal[%s]", "SIGTERM"); 63 | return false; 64 | } 65 | event_add_handler(ev); 66 | 67 | // sigint 68 | ev = evsignal_new(g_app->evt_base, SIGINT, cb_signal_int, NULL); 69 | if(ev == NULL) { 70 | slog(LOG_ERR, "Could not create event for the signal handler. signal[%s]", "SIGINT"); 71 | return false; 72 | } 73 | ret = event_add(ev, NULL); 74 | if(ret != 0) { 75 | slog(LOG_ERR, "Could not add the signal handler. signal[%s]", "SIGINT"); 76 | return false; 77 | } 78 | event_add_handler(ev); 79 | 80 | // sigpipe 81 | ev = evsignal_new(g_app->evt_base, SIGPIPE, cb_signal_pipe, NULL); 82 | if(ev == NULL) { 83 | slog(LOG_ERR, "Could not create event for the signal handler. signal[%s]", "SIGPIPE"); 84 | return false; 85 | } 86 | ret = event_add(ev, NULL); 87 | if(ret != 0) { 88 | slog(LOG_ERR, "Could not add the signal handler. signal[%s]", "SIGPIPE"); 89 | return false; 90 | } 91 | event_add_handler(ev); 92 | 93 | // sighup 94 | ev = evsignal_new(g_app->evt_base, SIGHUP, cb_signal_hup, NULL); 95 | if(ev == NULL) { 96 | slog(LOG_ERR, "Could not create event for the signal handler. signal[%s]", "SIGHUP"); 97 | return false; 98 | } 99 | ret = event_add(ev, NULL); 100 | if(ret != 0) { 101 | slog(LOG_ERR, "Could not add the signal handler. signal[%s]", "SIGHUP"); 102 | return false; 103 | } 104 | event_add_handler(ev); 105 | 106 | // add pid update 107 | tv.tv_sec = DEF_PID_TIMEOUT_SEC; 108 | tv.tv_usec = 0; 109 | ev = event_new(g_app->evt_base, -1, EV_TIMEOUT | EV_PERSIST, cb_pid_update, NULL); 110 | event_add(ev, &tv); 111 | event_add_handler(ev); 112 | 113 | return true; 114 | } 115 | 116 | void event_term_handler(void) 117 | { 118 | int idx; 119 | 120 | slog(LOG_NOTICE, "Fired term_event_handler."); 121 | 122 | for(idx = 0; idx < DEF_MAX_EVENT_COUNT; idx++) { 123 | if(g_ev_ast[idx] == NULL) { 124 | continue; 125 | } 126 | 127 | event_free(g_ev_ast[idx]); 128 | g_ev_ast[idx] = NULL; 129 | } 130 | } 131 | 132 | /** 133 | * Signal handler. 134 | * signal: sig_term 135 | * @param sock 136 | * @param which 137 | * @param arg 138 | */ 139 | static void cb_signal_term(int sock, short which, void* arg) 140 | { 141 | slog(LOG_INFO, "Fired cb_signal_term."); 142 | event_base_loopbreak(g_app->evt_base); 143 | 144 | return; 145 | } 146 | 147 | /** 148 | * Signal handler. 149 | * signal: sig_int 150 | * @param sock 151 | * @param which 152 | * @param arg 153 | */ 154 | static void cb_signal_int(evutil_socket_t sig, short events, void *user_data) 155 | { 156 | slog(LOG_INFO, "Fired cb_signal_int."); 157 | event_base_loopbreak(g_app->evt_base); 158 | 159 | return; 160 | } 161 | 162 | /** 163 | * Signal handler. 164 | * signal: sig_pipe 165 | * @param sock 166 | * @param which 167 | * @param arg 168 | */ 169 | static void cb_signal_pipe(evutil_socket_t sig, short events, void *user_data) 170 | { 171 | slog(LOG_INFO, "Fired cb_signal_pipe."); 172 | 173 | // terminate ami handler. 174 | data_term_handler(); 175 | 176 | return; 177 | } 178 | 179 | /** 180 | * Signal handler. 181 | * signal: sig_hup 182 | * @param sock 183 | * @param which 184 | * @param arg 185 | */ 186 | static void cb_signal_hup(evutil_socket_t sig, short events, void *user_data) 187 | { 188 | int ret; 189 | 190 | slog(LOG_INFO, "Fired cb_signal_hup."); 191 | 192 | ret = config_init(); 193 | if(ret == false) { 194 | slog(LOG_DEBUG, "Could not update configuration file."); 195 | } 196 | 197 | return; 198 | } 199 | 200 | static void cb_pid_update(int sock, short which, void* arg) 201 | { 202 | int ret; 203 | 204 | slog(LOG_INFO, "Fired cb_pid_update."); 205 | 206 | ret = pid_update(); 207 | if(ret == false) { 208 | slog(LOG_NOTICE, "Could not update pid correctly."); 209 | } 210 | } 211 | 212 | static bool pid_update(void) 213 | { 214 | struct pidfh *pfh; 215 | pid_t pid; 216 | int ret; 217 | 218 | pid = getpid(); 219 | 220 | pfh = pidfile_open(DEF_PID_FILEPATH, 0600, &pid); 221 | if(pfh == NULL) { 222 | if(errno != EEXIST) { 223 | slog(LOG_WARNING, "Could not open or create pidfile. pid[%jd], err[%d:%s].", (intmax_t)pid, errno, strerror(errno)); 224 | return false; 225 | } 226 | } 227 | 228 | ret = pidfile_write(pfh); 229 | if(ret != 0) { 230 | slog(LOG_WARNING, "Could not update pidfile. err[%d:%s]", errno, strerror(errno)); 231 | ret = pidfile_close(pfh); 232 | return false; 233 | } 234 | ret = pidfile_close(pfh); 235 | 236 | return true; 237 | } 238 | 239 | void event_add_handler(struct event* ev) 240 | { 241 | int idx; 242 | 243 | if(ev == NULL) { 244 | slog(LOG_WARNING, "Wrong input parameter."); 245 | return; 246 | } 247 | 248 | for(idx = 0; idx < DEF_MAX_EVENT_COUNT; idx++) { 249 | if(g_ev_ast[idx] != NULL) { 250 | continue; 251 | } 252 | g_ev_ast[idx] = ev; 253 | break; 254 | } 255 | 256 | return; 257 | } 258 | -------------------------------------------------------------------------------- /src/main/zmq_handler.c: -------------------------------------------------------------------------------- 1 | /* 2 | * zmq_handler.c 3 | * 4 | * Created on: Dec 20, 2017 5 | * Author: pchero 6 | */ 7 | 8 | 9 | 10 | #include 11 | #include 12 | 13 | #include "common.h" 14 | #include "slog.h" 15 | 16 | #include "zmq_handler.h" 17 | 18 | #define DEF_LOCAL_ADDR "ipc:///tmp/jade_local.pub" 19 | 20 | extern app* g_app; 21 | 22 | void* g_zmq_contxt = NULL; // zmq context for zmq_handler. 23 | void* g_zmq_sock_pub = NULL; // zmq socket for publish 24 | 25 | static bool init_zmq_context(void); 26 | 27 | static bool init_zmq_sock_pub(void); 28 | static void* get_zmq_sock_pub(void); 29 | 30 | static int s_sendmore(void* socket, const char* data); 31 | 32 | 33 | /** 34 | * @brief Initiate zmq_hanler. 35 | */ 36 | bool zmq_init_handler(void) 37 | { 38 | int ret; 39 | 40 | // initiate context 41 | ret = init_zmq_context(); 42 | if(ret == false) { 43 | slog(LOG_ERR, "Could not initiate context."); 44 | return false; 45 | } 46 | 47 | // initiate publish socket 48 | ret = init_zmq_sock_pub(); 49 | if(ret == false) { 50 | slog(LOG_ERR, "Could not initiate publish socket."); 51 | return false; 52 | } 53 | 54 | return true; 55 | } 56 | 57 | void zmq_term_handler(void) 58 | { 59 | // close sockets 60 | // close pub 61 | if(g_zmq_sock_pub != NULL) { 62 | zmq_close(g_zmq_sock_pub); 63 | } 64 | g_zmq_sock_pub = NULL; 65 | 66 | // close context 67 | if(g_zmq_contxt != NULL) { 68 | zmq_ctx_destroy(g_zmq_contxt); 69 | } 70 | g_zmq_contxt = NULL; 71 | 72 | return; 73 | } 74 | 75 | /** 76 | * Initiate zmq context. 77 | * @return 78 | */ 79 | static bool init_zmq_context(void) 80 | { 81 | // destroy it if it exists. 82 | if(g_zmq_contxt != NULL) { 83 | zmq_ctx_destroy(g_zmq_contxt); 84 | } 85 | 86 | // create new context 87 | g_zmq_contxt = zmq_ctx_new(); 88 | if(g_zmq_contxt == NULL) { 89 | slog(LOG_ERR, "Could not initiate context for zmq."); 90 | return false; 91 | } 92 | 93 | return true; 94 | } 95 | 96 | /** 97 | * @brief initiate socket for publish and bind the socket. 98 | */ 99 | static bool init_zmq_sock_pub(void) 100 | { 101 | int ret; 102 | const char* zmq_addr_pub; 103 | 104 | // close the socket if it exist. 105 | if(g_zmq_sock_pub != NULL) { 106 | zmq_close(g_zmq_sock_pub); 107 | } 108 | 109 | // create new socket 110 | g_zmq_sock_pub = zmq_socket(g_zmq_contxt, ZMQ_PUB); 111 | if(g_zmq_sock_pub == NULL) { 112 | slog(LOG_ERR, "Could not initiate socket for publish."); 113 | return false; 114 | } 115 | 116 | // get bind addr 117 | zmq_addr_pub = json_string_value(json_object_get(json_object_get(g_app->j_conf, "general"), "zmq_addr_pub")); 118 | if(zmq_addr_pub == NULL) { 119 | slog(LOG_ERR, "Could not get zmq_addr_pub info."); 120 | return false; 121 | } 122 | 123 | // bind the socket 124 | ret = zmq_bind(g_zmq_sock_pub, zmq_addr_pub); 125 | if(ret != 0) { 126 | slog(LOG_ERR, "Could not bind publish socket. err[%d:%s]", errno, strerror(errno)); 127 | return false; 128 | } 129 | 130 | // bind local 131 | ret = zmq_bind(g_zmq_sock_pub, DEF_LOCAL_ADDR); 132 | if(ret != 0) { 133 | slog(LOG_ERR, "Could not bind publish socket. err[%d:%s]", errno, strerror(errno)); 134 | return false; 135 | } 136 | 137 | return true; 138 | } 139 | 140 | static void* get_zmq_sock_pub(void) 141 | { 142 | return g_zmq_sock_pub; 143 | } 144 | 145 | /** 146 | * @brief publish the given data to the given subscribers 147 | */ 148 | bool zmq_publish_message(const char* pub_target, json_t* j_data) 149 | { 150 | char* tmp; 151 | int ret; 152 | void* sock; 153 | 154 | if((pub_target == NULL) || (j_data == NULL)) { 155 | slog(LOG_WARNING, "Wrong input parameter."); 156 | return false; 157 | } 158 | 159 | // get publish socket info 160 | sock = get_zmq_sock_pub(); 161 | if(sock == NULL) { 162 | slog(LOG_ERR, "Could not get correct socket info."); 163 | return false; 164 | } 165 | 166 | // send publish target 167 | ret = s_sendmore(sock, pub_target); 168 | if(ret < 0) { 169 | slog(LOG_ERR, "Could not send target info."); 170 | return false; 171 | } 172 | 173 | // get data string 174 | tmp = json_dumps(j_data, JSON_ENCODE_ANY); 175 | if(tmp == NULL) { 176 | slog(LOG_ERR, "Could not dump the given data."); 177 | return false; 178 | } 179 | 180 | // send data string 181 | ret = zmq_send_string(sock, tmp); 182 | free(tmp); 183 | if(ret < 0) { 184 | slog(LOG_ERR, "Could not send the data."); 185 | return false; 186 | } 187 | 188 | return true; 189 | } 190 | 191 | /** 192 | * @brief String send. 193 | * Send given string to given zmq socket. 194 | * The only string data can be sent. 195 | * @return sent length 196 | */ 197 | int zmq_send_string(void* socket, const char* data) 198 | { 199 | int size; 200 | 201 | if((socket == NULL) || (data == NULL)) { 202 | slog(LOG_WARNING, "Wrong input parameter."); 203 | return -1; 204 | } 205 | 206 | size = zmq_send(socket, data, strlen(data), 0); 207 | 208 | return size; 209 | } 210 | 211 | /** 212 | @brief Receive zmq message. 213 | Receive 0MQ string from socket and convert into C string Caller must free 214 | returned string. Returns NULL if the context is being terminated. 215 | @param socket 216 | @return 217 | */ 218 | char* zmq_recv_string(void* socket) 219 | { 220 | char buffer[40960]; 221 | int size; 222 | char* res; 223 | 224 | if(socket == NULL) { 225 | slog(LOG_WARNING, "Wrong input parameter."); 226 | return NULL; 227 | } 228 | 229 | size = zmq_recv(socket, buffer, sizeof(buffer), ZMQ_NOBLOCK); 230 | if(size == -1) { 231 | slog(LOG_ERR, "Could not receive zmq message."); 232 | return NULL; 233 | } 234 | else if(size > sizeof(buffer)) { 235 | slog(LOG_WARNING, "Over sized message received. len[%d]", size); 236 | size = sizeof(buffer); 237 | } 238 | 239 | buffer[size] = 0; 240 | res = strdup(buffer); 241 | 242 | return res; 243 | } 244 | 245 | /** 246 | * @brief Seting send more. 247 | * Sends string as 0MQ string, as multipart non-terminal 248 | * The only string data can be sent. 249 | * @return sent length 250 | */ 251 | static int s_sendmore(void* socket, const char* data) 252 | { 253 | int size; 254 | 255 | if((socket == NULL) || (data == NULL)) { 256 | slog(LOG_WARNING, "Wrong input parameter."); 257 | return -1; 258 | } 259 | 260 | size = zmq_send(socket, data, strlen(data), ZMQ_SNDMORE); 261 | return size; 262 | } 263 | 264 | /** 265 | * Return zmq context 266 | */ 267 | void* zmq_get_context(void) 268 | { 269 | return g_zmq_contxt; 270 | } 271 | 272 | /** 273 | * Return inproc address for pub 274 | * @return 275 | */ 276 | const char* zmq_get_pub_addr(void) 277 | { 278 | return DEF_LOCAL_ADDR; 279 | } 280 | -------------------------------------------------------------------------------- /src/main/ami_handler.c: -------------------------------------------------------------------------------- 1 | 2 | /*! 3 | \file ami_handler.c 4 | \brief 5 | 6 | \author Sungtae Kim 7 | \date Dec 20, 2013 8 | 9 | */ 10 | 11 | #define _GNU_SOURCE 12 | 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | 26 | #include "common.h" 27 | #include "slog.h" 28 | #include "utils.h" 29 | #include "ami_handler.h" 30 | #include "action_handler.h" 31 | #include "ob_ami_handler.h" 32 | #include "ob_dialing_handler.h" 33 | #include "ami_event_handler.h" 34 | 35 | #define DLE 0x0f // Data link escape 36 | #define DO 0xfd 37 | #define WONT 0xfc 38 | #define WILL 0xfb 39 | #define DONT 0xfe 40 | #define CMD 0xff 41 | 42 | #define CMD_ECHO 1 43 | #define CMD_WINDOW_SIZE 31 44 | 45 | #define MAX_AMI_ITEM_LEN 40960 46 | 47 | static int g_ami_socket = -1; 48 | 49 | 50 | /** 51 | * AMI command msg send handler. 52 | * send_ami_cmd 53 | * @param data 54 | */ 55 | bool ami_send_cmd(json_t* j_cmd) 56 | { 57 | int ret; 58 | json_t* j_val; 59 | const char* key; 60 | int type; 61 | char* tmp; 62 | char* cmd; 63 | char* cmd_sub; 64 | 65 | // just for log 66 | if(j_cmd == NULL) { 67 | return false; 68 | } 69 | 70 | // Get action 71 | j_val = json_object_get(j_cmd, "Action"); 72 | if(j_val == NULL) { 73 | slog(LOG_ERR, " not get the action."); 74 | return false; 75 | } 76 | 77 | asprintf(&cmd, "Action: %s\r\n", json_string_value(j_val)); 78 | slog(LOG_DEBUG, "AMI Action command. action[%s]", json_string_value(j_val)); 79 | 80 | json_object_foreach(j_cmd, key, j_val){ 81 | ret = strcmp(key, "Action"); 82 | if(ret == 0) { 83 | continue; 84 | } 85 | 86 | ret = strcmp(key, "Variables"); 87 | if(ret == 0) { 88 | cmd_sub = utils_get_variables_ami_str_from_object(j_val); 89 | asprintf(&tmp, "%s%s", cmd, cmd_sub); 90 | sfree(cmd); 91 | sfree(cmd_sub); 92 | cmd = tmp; 93 | continue; 94 | } 95 | 96 | type = json_typeof(j_val); 97 | switch(type) { 98 | case JSON_REAL: 99 | case JSON_INTEGER: 100 | { 101 | asprintf(&cmd_sub, "%s: %lld", key, json_integer_value(j_val)); 102 | } 103 | break; 104 | 105 | case JSON_FALSE: 106 | case JSON_TRUE: 107 | case JSON_STRING: 108 | { 109 | asprintf(&cmd_sub, "%s: %s", key, json_string_value(j_val)); 110 | } 111 | break; 112 | 113 | default: 114 | { 115 | slog(LOG_WARNING, "Invalid type. Set to . type[%d]", type); 116 | asprintf(&cmd_sub, "%s: %s", key, ""); 117 | } 118 | break; 119 | } 120 | 121 | asprintf(&tmp, "%s%s\r\n", cmd, cmd_sub); 122 | sfree(cmd_sub); 123 | sfree(cmd); 124 | cmd = tmp; 125 | } 126 | 127 | asprintf(&tmp, "%s\r\n", cmd); 128 | sfree(cmd); 129 | 130 | cmd = tmp; 131 | ret = ami_send_cmd_raw(cmd); 132 | sfree(cmd); 133 | if(ret < 0) { 134 | return false; 135 | } 136 | 137 | return true; 138 | } 139 | 140 | /** 141 | * Send raw format ami message. 142 | * @param cmd 143 | * @return Success: Size of sent message.\n 144 | * Fail: -1 145 | */ 146 | int ami_send_cmd_raw(const char* cmd) 147 | { 148 | int ret; 149 | 150 | if(cmd == NULL) { 151 | slog(LOG_WARNING, "Wrong input parameter."); 152 | return -1; 153 | } 154 | slog(LOG_DEBUG, "Fired send_ami_cmd_raw. cmd[%s]", cmd); 155 | 156 | ret = send(g_ami_socket, cmd, strlen(cmd), 0); 157 | if(ret < 0) { 158 | return -1; 159 | } 160 | 161 | return ret; 162 | } 163 | 164 | /** 165 | * 166 | * @param msg 167 | * @return 168 | */ 169 | json_t* ami_parse_msg(const char* msg) 170 | { 171 | json_t* j_tmp; 172 | char tmp[MAX_AMI_ITEM_LEN]; 173 | int ret; 174 | int i; 175 | int j; 176 | char* key; 177 | char* value; 178 | char* dump; 179 | int parsed; 180 | 181 | if(msg == NULL) { 182 | slog(LOG_WARNING, "Wrong input parameter."); 183 | return NULL; 184 | } 185 | 186 | j_tmp = json_object(); 187 | bzero(tmp, sizeof(tmp)); 188 | for(i = 0, j = 0; i < strlen(msg); i++) { 189 | parsed = false; 190 | 191 | if((msg[i] != '\r') || (msg[i+1] != '\n')) { 192 | tmp[j] = msg[i]; 193 | j++; 194 | continue; 195 | } 196 | 197 | // check /r/n/r/n 198 | ret = strlen(tmp); 199 | if(ret == 0) { 200 | break; 201 | } 202 | 203 | // get key/value 204 | value = strdup(tmp); 205 | dump = value; 206 | key = strsep(&value, ":"); 207 | if(key == NULL) { 208 | sfree(dump); 209 | continue; 210 | } 211 | utils_trim(key); 212 | utils_trim(value); 213 | 214 | // check Variable 215 | ret = strcasecmp(key, "Variable"); 216 | if(ret == 0) { 217 | if(json_object_get(j_tmp, "Variable") == NULL) { 218 | json_object_set_new(j_tmp, "Variable", json_array()); 219 | } 220 | json_array_append_new(json_object_get(j_tmp, "Variable"), json_string(value)); 221 | parsed = true; 222 | } 223 | 224 | // check Output 225 | ret = strcasecmp(key, "Output"); 226 | if(ret == 0) { 227 | if(json_object_get(j_tmp, "Output") == NULL) { 228 | json_object_set_new(j_tmp, "Output", json_array()); 229 | } 230 | json_array_append_new(json_object_get(j_tmp, "Output"), json_string(value)); 231 | parsed = true; 232 | } 233 | 234 | if(parsed != true) { 235 | json_object_set_new(j_tmp, key, json_string(value)); 236 | } 237 | 238 | 239 | sfree(dump); 240 | memset(tmp, 0x00, sizeof(tmp)); 241 | j = 0; 242 | i++; 243 | continue; 244 | } 245 | 246 | return j_tmp; 247 | } 248 | 249 | json_t* ami_parse_agi_env(const char* msg) 250 | { 251 | char tmp[40960]; 252 | int i; 253 | int j; 254 | char* value; 255 | char* dump; 256 | char* key; 257 | json_t* j_res; 258 | 259 | if(msg == NULL) { 260 | slog(LOG_WARNING, "Wrong input parameter.\n"); 261 | return NULL; 262 | } 263 | 264 | j = 0; 265 | bzero(tmp, sizeof(tmp)); 266 | j_res = json_object(); 267 | for(i = 0; i < strlen(msg); i++) { 268 | tmp[j] = msg[i]; 269 | j++; 270 | if(msg[i] != '\n') { 271 | continue; 272 | } 273 | 274 | // get key/value 275 | value = strdup(tmp); 276 | dump = value; 277 | key = strsep(&value, ":"); 278 | bzero(tmp, sizeof(tmp)); 279 | j = 0; 280 | 281 | if((key == NULL) || (value == NULL)) { 282 | sfree(dump); 283 | continue; 284 | } 285 | utils_trim(key); 286 | utils_trim(value); 287 | 288 | json_object_set_new(j_res, key, json_string(value)); 289 | free(dump); 290 | } 291 | 292 | return j_res; 293 | 294 | } 295 | 296 | 297 | /** 298 | * Set ami socket. 299 | * @param sock 300 | */ 301 | void ami_set_socket(int sock) 302 | { 303 | g_ami_socket = sock; 304 | } 305 | 306 | 307 | -------------------------------------------------------------------------------- /src/main/main.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "common.h" 11 | #include "slog.h" 12 | #include "config.h" 13 | #include "db_ctx_handler.h" 14 | #include "http_handler.h" 15 | #include "event_handler.h" 16 | #include "data_handler.h" 17 | #include "resource_handler.h" 18 | #include "misc_handler.h" 19 | #include "ob_event_handler.h" 20 | #include "zmq_handler.h" 21 | #include "websocket_handler.h" 22 | #include "conf_handler.h" 23 | #include "user_handler.h" 24 | #include "chat_handler.h" 25 | #include "call_handler.h" 26 | #include "core_handler.h" 27 | #include "dialplan_handler.h" 28 | 29 | #include "park_handler.h" 30 | #include "queue_handler.h" 31 | #include "pjsip_handler.h" 32 | #include "sip_handler.h" 33 | 34 | #include "me_handler.h" 35 | #include "admin_handler.h" 36 | #include "manager_handler.h" 37 | 38 | app* g_app; 39 | 40 | 41 | static bool option_parse(int argc, char** argv); 42 | static void print_help(void); 43 | 44 | /** 45 | * Initiate jade_backend 46 | * @return 47 | */ 48 | bool init(void) 49 | { 50 | int ret; 51 | 52 | g_app = calloc(sizeof(app), 1); 53 | g_app->j_conf = NULL; 54 | g_app->evt_base = NULL; 55 | 56 | ret = slog_init_handler(); 57 | if(ret == false) { 58 | printf("Failed initiate log."); 59 | return false; 60 | } 61 | slog(LOG_NOTICE, "Finished init_log."); 62 | 63 | ret = config_init(); 64 | if(ret == false) { 65 | printf("Could not initiate config."); 66 | return false; 67 | } 68 | slog(LOG_NOTICE, "Finished init_config."); 69 | 70 | ret = event_init_handler(); 71 | if(ret == false) { 72 | slog(LOG_ERR, "Could not initiate event_handler."); 73 | return false; 74 | } 75 | slog(LOG_DEBUG, "Finished init_event_handler."); 76 | 77 | ret = resource_init_handler(); 78 | if(ret == false) { 79 | slog(LOG_ERR, "Could not initiate resource."); 80 | return false; 81 | } 82 | slog(LOG_NOTICE, "Finished resource_init."); 83 | 84 | ret = zmq_init_handler(); 85 | if(ret == false) { 86 | slog(LOG_ERR, "Coudl not initiate zmq_handler."); 87 | return false; 88 | } 89 | 90 | ret = data_init_handler(); 91 | if(ret == false) { 92 | slog(LOG_ERR, "Could not initiate ami_handle."); 93 | return false; 94 | } 95 | slog(LOG_DEBUG, "Finished init_ami_handler."); 96 | 97 | ret = http_init_handler(); 98 | if(ret == false) { 99 | slog(LOG_ERR, "Could not initiate http_handler."); 100 | return false; 101 | } 102 | slog(LOG_DEBUG, "Finished init_http_handler."); 103 | 104 | ret = websocket_init_handler(); 105 | if(ret == false) { 106 | slog(LOG_ERR, "Could not initiate websocket_handler."); 107 | return false; 108 | } 109 | slog(LOG_DEBUG, "Finished init_websocket_handler."); 110 | 111 | // ret = ob_init_handler(); 112 | // if(ret == false) { 113 | // slog(LOG_ERR, "Could not initiate ob_handler."); 114 | // return false; 115 | // } 116 | // slog(LOG_DEBUG, "Finished init_outbound."); 117 | 118 | ret = conf_init_handler(); 119 | if(ret == false) { 120 | slog(LOG_ERR, "Could not initiate conf_handler."); 121 | return false; 122 | } 123 | slog(LOG_DEBUG, "Finished init_conf_handler."); 124 | 125 | ret = core_init_handler(); 126 | if(ret == false) { 127 | slog(LOG_ERR, "Could not initiate call_handler."); 128 | return false; 129 | } 130 | 131 | ret = user_init_handler(); 132 | if(ret == false) { 133 | slog(LOG_ERR, "Could not initiate user_handler"); 134 | return false; 135 | } 136 | 137 | ret = misc_init_handler(); 138 | if(ret == false) { 139 | slog(LOG_ERR, "Could not initiate misc_handler."); 140 | return false; 141 | } 142 | 143 | // other module handlers 144 | ret = park_init_handler(); 145 | if(ret == false) { 146 | slog(LOG_ERR, "Could not initiate park_handler."); 147 | return false; 148 | } 149 | 150 | ret = queue_init_handler(); 151 | if(ret == false) { 152 | slog(LOG_ERR, "Could not initiate queue_handler."); 153 | return false; 154 | } 155 | 156 | ret = pjsip_init_handler(); 157 | if(ret == false) { 158 | slog(LOG_ERR, "Could not initate pjsip_handler."); 159 | return false; 160 | } 161 | 162 | ret = sip_init_handler(); 163 | if(ret == false) { 164 | slog(LOG_ERR, "Could not initiate sip_handler."); 165 | return false; 166 | } 167 | 168 | ret = chat_init_handler(); 169 | if(ret == false) { 170 | slog(LOG_ERR, "Could not initiate chat_handler."); 171 | return false; 172 | } 173 | 174 | ret = dialplan_init_handler(); 175 | if(ret == false) { 176 | slog(LOG_ERR, "Could not initiate dialplan_handler."); 177 | return false; 178 | } 179 | 180 | ret = me_init_handler(); 181 | if(ret == false) { 182 | slog(LOG_ERR, "Could not initiate me_handler."); 183 | return false; 184 | } 185 | 186 | ret = admin_init_handler(); 187 | if(ret == false) { 188 | slog(LOG_ERR, "Could not initiate admin_handler."); 189 | return false; 190 | } 191 | 192 | ret = manager_init_handler(); 193 | if(ret == false) { 194 | slog(LOG_ERR, "Could not initiate manager_handler."); 195 | return false; 196 | } 197 | 198 | return true; 199 | } 200 | 201 | bool terminate(void) 202 | { 203 | slog(LOG_INFO, "Terminating.."); 204 | 205 | http_term_handler(); 206 | 207 | // terminate event handler 208 | event_term_handler(); 209 | 210 | // terminate outbound module. 211 | ob_term_handler(); 212 | 213 | // terminate zmq 214 | zmq_term_handler(); 215 | 216 | websocket_term_handler(); 217 | 218 | resource_term_handler(); 219 | 220 | // terminate modules 221 | me_term_handler(); 222 | admin_term_handler(); 223 | manager_term_handler(); 224 | 225 | event_base_free(g_app->evt_base); 226 | g_app->evt_base = NULL; 227 | 228 | return true; 229 | } 230 | 231 | int main(int argc, char** argv) 232 | { 233 | int ret; 234 | 235 | // parse options 236 | ret = option_parse(argc, argv); 237 | if(ret == false) { 238 | return 1; 239 | } 240 | 241 | // initiate 242 | ret = init(); 243 | if(ret == false) { 244 | printf("Could not initiate.\n"); 245 | return 1; 246 | } 247 | slog(LOG_INFO, "Started backend service."); 248 | 249 | event_base_loop(g_app->evt_base, 0); 250 | 251 | terminate(); 252 | 253 | return 0; 254 | } 255 | 256 | static void print_help(void) 257 | { 258 | printf("Usage: jade_backend [OPTIONS]\n"); 259 | printf("Valid options:\n"); 260 | printf(" -h : This help screen.\n"); 261 | printf(" -f : Use an alternate configuration file.\n"); 262 | printf("\n"); 263 | return; 264 | } 265 | 266 | /** 267 | * Parse option. 268 | * @param argc 269 | * @param argv 270 | * @return 271 | */ 272 | static bool option_parse(int argc, char** argv) 273 | { 274 | char opt; 275 | 276 | if(argc > 1) { 277 | opt = getopt(argc, argv, "hc:"); 278 | if(opt == -1) { 279 | print_help(); 280 | return false; 281 | } 282 | 283 | switch(opt) { 284 | case 'f': 285 | { 286 | config_update_filename(optarg); 287 | } 288 | break; 289 | 290 | case 'h': 291 | default: 292 | { 293 | print_help(); 294 | return false; 295 | } 296 | } 297 | } 298 | return true; 299 | } 300 | -------------------------------------------------------------------------------- /doc/source/queue_event.rst: -------------------------------------------------------------------------------- 1 | .. _queue_event: 2 | 3 | .. _queue_entry: 4 | 5 | queue.entry 6 | =========== 7 | Queue enty event. 8 | 9 | .. _queue.entry.delete: 10 | 11 | queue.entry.delete 12 | ------------------ 13 | Event for queue entry delete. 14 | 15 | Topic 16 | +++++ 17 | :: 18 | 19 | /queue/statuses/ 20 | 21 | * ``target``: URI encoded queue name. 22 | 23 | Event 24 | +++++ 25 | :: 26 | 27 | { 28 | "queue.entry.delete": { 29 | "unique_id": "", 30 | 31 | "queue_name": "", 32 | "channel": "", 33 | 34 | "caller_id_name": "", 35 | "caller_id_num": "", 36 | "connected_line_name": "", 37 | "connected_line_num": "", 38 | 39 | "position": , 40 | "wait": , 41 | 42 | "tm_update": "" 43 | } 44 | } 45 | 46 | * See detail at Asterisk's queue info. 47 | 48 | Example 49 | +++++++ 50 | :: 51 | 52 | topic: /queue/statuses/sales%5F1 53 | 54 | { 55 | "queue.entry.delete": { 56 | "unique_id": "1513886574.11", 57 | "connected_line_num": "", 58 | "queue_name": "sales_1", 59 | "wait": null, 60 | "position": 1, 61 | "channel": "PJSIP/pjagent-01-0000000b", 62 | "caller_id_num": "pjagent-01", 63 | "caller_id_name": "pjagent-01", 64 | "connected_line_name": "", 65 | "tm_update": "2017-12-21T20:02:55.766020378Z" 66 | } 67 | } 68 | 69 | .. _queue_entry_update: 70 | 71 | queue.entry.update 72 | ------------------ 73 | Event for queue entry insert/update. 74 | 75 | Topic 76 | +++++ 77 | :: 78 | 79 | /queue/statuses/ 80 | 81 | * ``target``: URI encoded queue name. 82 | 83 | Event 84 | +++++ 85 | :: 86 | 87 | { 88 | "queue.entry.update": { 89 | "unique_id": "", 90 | 91 | "queue_name": "", 92 | "channel": "", 93 | 94 | "caller_id_name": "", 95 | "caller_id_num": "", 96 | "connected_line_name": "", 97 | "connected_line_num": "", 98 | 99 | "position": , 100 | "wait": , 101 | 102 | "tm_update": "" 103 | } 104 | } 105 | 106 | * See detail at Asterisk's queue info. 107 | 108 | Example 109 | +++++++ 110 | :: 111 | 112 | topic: /queue/statuses/sales%5F1 113 | 114 | { 115 | "queue.entry.update": { 116 | "unique_id": "1513887042.12", 117 | "caller_id_name": "pjagent-01", 118 | "connected_line_num": "", 119 | "position": 1, 120 | "tm_update": "2017-12-21T20:10:43.841799160Z", 121 | "queue_name": "sales_1", 122 | "channel": "PJSIP/pjagent-01-0000000c", 123 | "caller_id_num": "pjagent-01", 124 | "connected_line_name": "", 125 | "wait": null 126 | } 127 | } 128 | 129 | 130 | 131 | queue.member 132 | ============ 133 | Queue member event. 134 | 135 | .. _queue.member.delete: 136 | 137 | queue.member.delete 138 | ------------------- 139 | Event for queue member delete. 140 | 141 | Topic 142 | +++++ 143 | :: 144 | 145 | /queue/statuses/ 146 | 147 | * ``target``: URI encoded queue name. 148 | 149 | Event 150 | +++++ 151 | :: 152 | 153 | { 154 | "queue.entry.delete": { 155 | "id": "", 156 | "name": "", 157 | "queue_name": "", 158 | "status": , 159 | 160 | "membership": "", 161 | "state_interface": "", 162 | "location": "", 163 | 164 | "paused": , 165 | "paused_reason": "", 166 | "penalty": , 167 | 168 | "calls_taken": , 169 | "in_call": , 170 | 171 | "last_call": , 172 | "last_pause": , 173 | 174 | "ring_inuse": , 175 | 176 | "tm_update": "" 177 | } 178 | } 179 | 180 | * See detail at Asterisk's queue info. 181 | 182 | Example 183 | +++++++ 184 | :: 185 | 186 | topic: /queue/statuses/sales%5F1 187 | 188 | { 189 | "queue.member.delete": { 190 | "location": "sip/agent-01", 191 | "penalty": 0, 192 | "ring_inuse": 1, 193 | "id": "sip/agent-01@sales_1", 194 | "state_interface": "sip/agent-01", 195 | "queue_name": "sales_1", 196 | "name": "sip/agent-01", 197 | "membership": "dynamic", 198 | "calls_taken": 0, 199 | "last_call": 0, 200 | "last_pause": 0, 201 | "in_call": 0, 202 | "status": 4, 203 | "paused": 0, 204 | "paused_reason": "", 205 | "tm_update": "2017-12-21T21:35:04.605327430Z" 206 | } 207 | } 208 | 209 | .. _queue_member_update: 210 | 211 | queue.member.update 212 | ------------------- 213 | Event for queue member insert/update. 214 | 215 | Topic 216 | +++++ 217 | :: 218 | 219 | /queue/statuses/ 220 | 221 | * ``target``: URI encoded queue name. 222 | 223 | Event 224 | +++++ 225 | :: 226 | 227 | { 228 | "queue.member.update": { 229 | "id": "", 230 | 231 | "name": "", 232 | "queue_name": "", 233 | "status": , 234 | 235 | "membership": "", 236 | "state_interface": "", 237 | "location": "", 238 | 239 | "paused": , 240 | "paused_reason": "", 241 | "penalty": , 242 | 243 | "calls_taken": , 244 | "in_call": , 245 | 246 | "last_call": , 247 | "last_pause": , 248 | 249 | "ring_inuse": , 250 | 251 | "tm_update": "" 252 | } 253 | } 254 | 255 | 256 | * See detail at Asterisk's queue info. 257 | 258 | Example 259 | +++++++ 260 | :: 261 | 262 | topic: /queue/statuses/sales%5F1 263 | 264 | { 265 | "queue.member.update": { 266 | "location": "sip/agent-01", 267 | "penalty": 0, 268 | "ring_inuse": 1, 269 | "id": "sip/agent-01@sales_1", 270 | "state_interface": "sip/agent-01", 271 | "queue_name": "sales_1", 272 | "name": "sip/agent-01", 273 | "membership": "dynamic", 274 | "calls_taken": 0, 275 | "last_call": 0, 276 | "last_pause": 0, 277 | "in_call": 0, 278 | "status": 4, 279 | "paused": 0, 280 | "paused_reason": "", 281 | "tm_update": "2017-12-21T21:35:04.605327430Z" 282 | } 283 | } 284 | 285 | 286 | queue.queue 287 | =========== 288 | 289 | .. _queue.queue.update: 290 | 291 | queue.queue.update 292 | ------------------ 293 | 294 | Topic 295 | +++++ 296 | :: 297 | 298 | /queue/statuses/ 299 | 300 | * ``target``: URI encoded queue name. 301 | 302 | Event 303 | +++++ 304 | :: 305 | 306 | { 307 | "queue.queue.update": { 308 | "name": "", 309 | 310 | "strategy": "", 311 | "max": , 312 | "weight": , 313 | 314 | "calls": , 315 | "completed": , 316 | "abandoned": , 317 | 318 | "hold_time": , 319 | "talk_time": , 320 | 321 | "service_level": , 322 | "service_level_perf": , 323 | 324 | "tm_update": "" 325 | } 326 | } 327 | 328 | * See detail at Asterisk's queue info. 329 | 330 | Example 331 | +++++++ 332 | :: 333 | 334 | topic: /queue/statuses/sales%5F1 335 | 336 | { 337 | "queue.queue.update": { 338 | "weight": 0, 339 | "name": "sales_1", 340 | "service_level": 5, 341 | "abandoned": 6, 342 | "service_level_perf": 0.0, 343 | "max": 0, 344 | "hold_time": 0, 345 | "strategy": "ringall", 346 | "calls": 0, 347 | "tm_update": "2017-12-21T18:35:17.131303352Z", 348 | "talk_time": 0, 349 | "completed": 0 350 | } 351 | } 352 | -------------------------------------------------------------------------------- /src/main/config.c: -------------------------------------------------------------------------------- 1 | /* 2 | * config.c 3 | * 4 | * Created on: Feb 2, 2017 5 | * Author: pchero 6 | */ 7 | 8 | #define _GNU_SOURCE 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "common.h" 16 | #include "slog.h" 17 | #include "minIni.h" 18 | #include "utils.h" 19 | 20 | #include "config.h" 21 | 22 | #define DEF_CONF_FILENAME "/opt/etc/jade.conf" 23 | 24 | #define DEF_JADE_LIB_DIR "/opt/var/lib/jade" 25 | #define DEF_JADE_ETC_DIR "/opt/etc" 26 | 27 | #define DEF_GENERAL_AST_SERV_ADDR "127.0.0.1" 28 | #define DEF_GENERAL_AMI_SERV_ADDR "127.0.0.1" 29 | #define DEF_GENERAL_AMI_SERV_PORT "5038" 30 | #define DEF_GENERAL_AMI_USERNAME "admin" 31 | #define DEF_GENERAL_AMI_PASSWORD "admin" 32 | #define DEF_GENERAL_HTTPS_ADDR "0.0.0.0" 33 | #define DEF_GENERAL_HTTPS_PORT "8081" 34 | #define DEF_GENERAL_HTTPS_PEMFILE "/opt/bin/jade.pem" 35 | #define DEF_GENERAL_ZMQ_ADDR_PUBLISH "tcp://*:8082" // zmq address for publish 36 | #define DEF_GENERAL_WEBSOCK_ADDR "0.0.0.0" 37 | #define DEF_GENERAL_WEBSOCK_PORT "8083" 38 | #define DEF_GENERAL_LOGLEVEL "5" 39 | #define DEF_GENERAL_DATABASE_NAME_AST ":memory:" 40 | #define DEF_GENERAL_DATABASE_NAME_JADE "./jade_database.db" 41 | #define DEF_GENERAL_EVENT_TIME_FAST "100000" 42 | #define DEF_GENERAL_EVENT_TIME_SLOW "3000000" 43 | #define DEF_GENERAL_DIR_CONF "/etc/asterisk" 44 | #define DEF_GENERAL_DIR_MODULE "/usr/lib/asterisk/modules" 45 | 46 | #define DEF_VOICEMAIL_DIRECTORY "/var/spool/asterisk/voicemail" 47 | 48 | #define DEF_OB_DIALING_RESULT_FILENAME "./outbound_result.json" 49 | #define DEF_OB_DIALING_TIMEOUT "30" 50 | #define DEF_OB_DATABASE_NAME "./outbound_database.db" 51 | 52 | #define DEF_DIALPLA_DEFAULT_ORIGINATE_TO_DEVICE "72ebc4b8-ac5e-4863-a7d3-55ffdfef43ee" 53 | #define DEF_DIALPLA_DEFAULT_ORIGINATE_TO_NUMBER "a922cf23-c650-426a-9ba0-a35ebc68a464" 54 | 55 | #define DEF_PJSIP_CONTEXT "demo" 56 | #define DEF_PJSIP_DTLS_CERT_FILE "/opt/bin/jade.pem" 57 | 58 | extern app* g_app; 59 | static char g_config_filename[1024] = ""; 60 | 61 | static bool load_config(void); 62 | static bool write_config(void); 63 | static bool init_directories(void); 64 | 65 | 66 | /** 67 | * Initiate configuration 68 | * @return 69 | */ 70 | bool config_init(void) 71 | { 72 | int ret; 73 | 74 | if((g_config_filename == NULL) || (strlen(g_config_filename) == 0)) { 75 | snprintf(g_config_filename, sizeof(g_config_filename), DEF_CONF_FILENAME); 76 | } 77 | 78 | ret = init_directories(); 79 | if(ret == false) { 80 | return false; 81 | } 82 | 83 | ret = load_config(); 84 | if(ret == false) { 85 | return false; 86 | } 87 | 88 | return true; 89 | } 90 | 91 | /** 92 | * Initiate jade's default directories. 93 | * @return 94 | */ 95 | static bool init_directories(void) 96 | { 97 | int ret; 98 | char* cmd; 99 | 100 | // /opt/etc 101 | asprintf(&cmd, "mkdir -p %s", DEF_JADE_ETC_DIR); 102 | ret = system(cmd); 103 | sfree(cmd); 104 | if(ret != EXIT_SUCCESS) { 105 | slog(LOG_ERR, "Could not create directory. dir[%s]", DEF_JADE_ETC_DIR); 106 | return false; 107 | } 108 | 109 | // /opt/var/lib 110 | asprintf(&cmd, "mkdir -p %s", DEF_JADE_LIB_DIR); 111 | ret = system(cmd); 112 | sfree(cmd); 113 | if(ret != EXIT_SUCCESS) { 114 | slog(LOG_ERR, "Could not create directory. dir[%s]", DEF_JADE_LIB_DIR); 115 | return false; 116 | } 117 | 118 | return true; 119 | } 120 | 121 | /** 122 | * Update config filename 123 | * @param filename 124 | * @return 125 | */ 126 | bool config_update_filename(const char* filename) 127 | { 128 | if(filename == NULL) { 129 | printf("Wrong input parameter."); 130 | return false; 131 | } 132 | 133 | snprintf(g_config_filename, sizeof(g_config_filename), "%s", filename); 134 | printf("Updated config filename. config_filename[%s]", g_config_filename); 135 | 136 | return true; 137 | } 138 | 139 | /** 140 | * Load configuration file and update 141 | * @return 142 | */ 143 | static bool load_config(void) 144 | { 145 | const char* tmp_const; 146 | int ret; 147 | json_t* j_conf_def; 148 | json_t* j_conf; 149 | const char* key; 150 | json_t* j_tmp; 151 | 152 | slog(LOG_INFO, "Load configuration file. filename[%s]", g_config_filename); 153 | 154 | // create default conf 155 | j_conf_def = json_pack("{" 156 | "s:{" 157 | "s:s, s:s, s:s, s:s, s:s, s:s, " 158 | "s:s, s:s, " 159 | "s:s, s:s, s:s, " 160 | "s:s, s:s, s:s, " 161 | "s:s, s:s, " 162 | "s:s, s:s " 163 | "}," // general 164 | "s:{s:s}, " // voicemail 165 | "s:{s:s, s:s, s:s}," // ob 166 | "s:{s:s, s:s}," // pjsip 167 | "s:{s:s, s:s}" // dialplan 168 | "}", 169 | "general", 170 | "ast_serv_addr", DEF_GENERAL_AST_SERV_ADDR, 171 | "ami_serv_addr", DEF_GENERAL_AMI_SERV_ADDR, 172 | "ami_serv_port", DEF_GENERAL_AMI_SERV_PORT, 173 | "ami_username", DEF_GENERAL_AMI_USERNAME, 174 | "ami_password", DEF_GENERAL_AMI_PASSWORD, 175 | "loglevel", DEF_GENERAL_LOGLEVEL, 176 | 177 | "database_name_ast", DEF_GENERAL_DATABASE_NAME_AST, 178 | "database_name_jade", DEF_GENERAL_DATABASE_NAME_JADE, 179 | 180 | "https_addr", DEF_GENERAL_HTTPS_ADDR, 181 | "https_port", DEF_GENERAL_HTTPS_PORT, 182 | "https_pemfile", DEF_GENERAL_HTTPS_PEMFILE, 183 | 184 | "zmq_addr_pub", DEF_GENERAL_ZMQ_ADDR_PUBLISH, 185 | "websock_addr", DEF_GENERAL_WEBSOCK_ADDR, 186 | "websock_port", DEF_GENERAL_WEBSOCK_PORT, 187 | 188 | "event_time_fast", DEF_GENERAL_EVENT_TIME_FAST, 189 | "event_time_slow", DEF_GENERAL_EVENT_TIME_SLOW, 190 | 191 | "directory_conf", DEF_GENERAL_DIR_CONF, 192 | "directory_module", DEF_GENERAL_DIR_MODULE, 193 | 194 | "voicemail", 195 | "dicretory", DEF_VOICEMAIL_DIRECTORY, 196 | 197 | "ob", 198 | "dialing_result_filename", DEF_OB_DIALING_RESULT_FILENAME, 199 | "dialing_timeout", DEF_OB_DIALING_TIMEOUT, 200 | "database_name", DEF_OB_DATABASE_NAME, 201 | 202 | "pjsip", 203 | "context", DEF_PJSIP_CONTEXT, 204 | "dtls_cert_file", DEF_PJSIP_DTLS_CERT_FILE, 205 | 206 | "dialplan", 207 | "default_dpma_originate_to_device", DEF_DIALPLA_DEFAULT_ORIGINATE_TO_DEVICE, 208 | "default_dpma_originate_to_number", DEF_DIALPLA_DEFAULT_ORIGINATE_TO_NUMBER 209 | ); 210 | if(j_conf_def == NULL) { 211 | printf("Could not create default config.\n"); 212 | return false; 213 | } 214 | 215 | j_conf = json_load_file(g_config_filename, JSON_DECODE_ANY, NULL); 216 | 217 | // update conf 218 | json_object_foreach(j_conf_def, key, j_tmp) { 219 | json_object_update(j_tmp, json_object_get(j_conf, key)); 220 | } 221 | json_decref(j_conf); 222 | 223 | if(g_app->j_conf != NULL) { 224 | json_decref(g_app->j_conf); 225 | } 226 | 227 | g_app->j_conf = j_conf_def; 228 | write_config(); 229 | 230 | // update log level 231 | tmp_const = json_string_value(json_object_get(json_object_get(g_app->j_conf, "general"), "loglevel")); 232 | ret = atoi(tmp_const); 233 | slog_update_log_level(ret); 234 | 235 | slog(LOG_DEBUG, "load_config end."); 236 | return true; 237 | } 238 | 239 | /** 240 | * Write current config optin to the file. 241 | * @return 242 | */ 243 | static bool write_config(void) 244 | { 245 | if(g_app->j_conf == NULL) { 246 | slog(LOG_WARNING, "Wrong input parameter."); 247 | return false; 248 | } 249 | slog(LOG_DEBUG, "Fired write_config."); 250 | 251 | utils_create_empty_file(g_config_filename); 252 | 253 | json_dump_file(g_app->j_conf, g_config_filename, JSON_INDENT(4)); 254 | 255 | return true; 256 | } 257 | 258 | 259 | 260 | 261 | 262 | -------------------------------------------------------------------------------- /test/test_ob_plan.py: -------------------------------------------------------------------------------- 1 | import common 2 | import ast 3 | import json 4 | 5 | 6 | def test_ob_plan_data_types(j_plan): 7 | if j_plan["uuid"] != None and isinstance(j_plan["uuid"], unicode) != True: 8 | print("Type error. uuid. type[%s]" % type(j_plan["uuid"])) 9 | return False 10 | 11 | if j_plan["name"] != None and isinstance(j_plan["name"], unicode) != True: 12 | print("Type error. name. type[%s]" % type(j_plan["name"])) 13 | return False 14 | 15 | if j_plan["detail"] != None and isinstance(j_plan["detail"], unicode) != True: 16 | print("Type error. detail. type[%s]" % type(j_plan["detail"])) 17 | return False 18 | 19 | 20 | if j_plan["tech_name"] != None and isinstance(j_plan["tech_name"], unicode) != True: 21 | print("Type error. tech_name. type[%s]" % type(j_plan["tech_name"])) 22 | return False 23 | 24 | if j_plan["trunk_name"] != None and isinstance(j_plan["trunk_name"], unicode) != True: 25 | print("Type error. trunk_name. type[%s]" % type(j_plan["trunk_name"])) 26 | return False 27 | 28 | 29 | if isinstance(j_plan["dial_mode"], int) != True: 30 | print("Type error. dial_mode. type[%s]" % type(j_plan["dial_mode"])) 31 | return False 32 | 33 | if isinstance(j_plan["dial_timeout"], int) != True: 34 | print("Type error. dial_timeout. type[%s]" % type(j_plan["dial_timeout"])) 35 | return False 36 | 37 | if isinstance(j_plan["dl_end_handle"], int) != True: 38 | print("Type error. dl_end_handle. type[%s]" % type(j_plan["dl_end_handle"])) 39 | return False 40 | 41 | if isinstance(j_plan["retry_delay"], int) != True: 42 | print("Type error. retry_delay. type[%s]" % type(j_plan["retry_delay"])) 43 | return False 44 | 45 | 46 | if j_plan["caller_id"] != None and isinstance(j_plan["caller_id"], unicode) != True: 47 | print("Type error. caller_id. type[%s]" % type(j_plan["caller_id"])) 48 | return False 49 | 50 | if isinstance(j_plan["service_level"], int) != True: 51 | print("Type error. service_level. type[%s]" % type(j_plan["service_level"])) 52 | return False 53 | 54 | if j_plan["early_media"] != None and isinstance(j_plan["early_media"], unicode) != True: 55 | print("Type error. early_media. type[%s]" % type(j_plan["early_media"])) 56 | return False 57 | 58 | if j_plan["codecs"] != None and isinstance(j_plan["codecs"], unicode) != True: 59 | print("Type error. codecs. type[%s]" % type(j_plan["codecs"])) 60 | return False 61 | 62 | if j_plan["variables"] != None and isinstance(j_plan["variables"], dict) != True: 63 | print("Type error. variables. type[%s]" % type(j_plan["variables"])) 64 | return False 65 | 66 | 67 | if isinstance(j_plan["max_retry_cnt_1"], int) != True: 68 | print("Type error. max_retry_cnt_1. type[%s]" % type(j_plan["max_retry_cnt_1"])) 69 | return False 70 | 71 | if isinstance(j_plan["max_retry_cnt_2"], int) != True: 72 | print("Type error. max_retry_cnt_2. type[%s]" % type(j_plan["max_retry_cnt_2"])) 73 | return False 74 | 75 | if isinstance(j_plan["max_retry_cnt_3"], int) != True: 76 | print("Type error. max_retry_cnt_3. type[%s]" % type(j_plan["max_retry_cnt_3"])) 77 | return False 78 | 79 | if isinstance(j_plan["max_retry_cnt_4"], int) != True: 80 | print("Type error. max_retry_cnt_4. type[%s]" % type(j_plan["max_retry_cnt_4"])) 81 | return False 82 | 83 | if isinstance(j_plan["max_retry_cnt_5"], int) != True: 84 | print("Type error. max_retry_cnt_5. type[%s]" % type(j_plan["max_retry_cnt_5"])) 85 | return False 86 | 87 | if isinstance(j_plan["max_retry_cnt_6"], int) != True: 88 | print("Type error. max_retry_cnt_6. type[%s]" % type(j_plan["max_retry_cnt_6"])) 89 | return False 90 | 91 | if isinstance(j_plan["max_retry_cnt_7"], int) != True: 92 | print("Type error. max_retry_cnt_7. type[%s]" % type(j_plan["max_retry_cnt_7"])) 93 | return False 94 | 95 | if isinstance(j_plan["max_retry_cnt_8"], int) != True: 96 | print("Type error. max_retry_cnt_8. type[%s]" % type(j_plan["max_retry_cnt_8"])) 97 | return False 98 | 99 | 100 | if j_plan["tm_create"] != None and isinstance(j_plan["tm_create"], unicode) != True: 101 | print("Type error. tm_create. type[%s]" % type(j_plan["tm_create"])) 102 | return False 103 | 104 | if j_plan["tm_update"] != None and isinstance(j_plan["tm_update"], unicode) != True: 105 | print("Type error. tm_update. type[%s]" % type(j_plan["tm_update"])) 106 | return False 107 | 108 | if j_plan["tm_delete"] != None and isinstance(j_plan["tm_delete"], unicode) != True: 109 | print("Type error. tm_delete. type[%s]" % type(j_plan["tm_delete"])) 110 | return False 111 | 112 | return True 113 | 114 | 115 | 116 | def test_default_return_ob_plans(): 117 | url = "127.0.0.1:8081/ob/plans" 118 | ret_code, ret_data = common.http_send(url, "GET", None) 119 | ret_json = ast.literal_eval(ret_data) 120 | if ret_code != 200: 121 | print("Return value error") 122 | return False 123 | 124 | if "api_ver" not in ret_json \ 125 | or "timestamp" not in ret_json \ 126 | or "statuscode" not in ret_json \ 127 | or "result" not in ret_json: 128 | 129 | print("Return value error") 130 | return False 131 | 132 | 133 | if "list" not in ret_json["result"] : 134 | print("Return value error") 135 | return False 136 | 137 | print("Finished test_default_return_ob_plans.") 138 | return True 139 | 140 | 141 | def test_default_create_and_delete_ob_plans(): 142 | # create new plan 143 | url = "127.0.0.1:8081/ob/plans" 144 | ret_code, ret_data = common.http_send(url, "POST", "{}") 145 | if ret_code != 200: 146 | print("Return value error") 147 | return False 148 | 149 | j_res = json.loads(ret_data) 150 | ret = test_ob_plan_data_types(j_res["result"]) 151 | if ret == False: 152 | print("Could not pass type check.") 153 | return False 154 | 155 | # get created plan uuid 156 | uuid = j_res["result"]["uuid"] 157 | if uuid == None: 158 | print("Could not get created uuid.") 159 | return False 160 | 161 | # delete plan 162 | url = "127.0.0.1:8081/ob/plans/%s" % uuid 163 | ret_code, ret_data = common.http_send(url, "DELETE", None) 164 | if ret_code != 200: 165 | print("Return value error.") 166 | return False 167 | 168 | print("Finished test_default_create_and_delete_ob_plans.") 169 | 170 | return True 171 | 172 | 173 | def test_ob_plan_create_item_check(): 174 | url = "127.0.0.1:8081/ob/plans" 175 | ret_code, ret_data = common.http_send(url, "POST", "{}") 176 | if ret_code != 200: 177 | print("Return value error") 178 | return False 179 | 180 | # json load 181 | j_res = json.loads(ret_data) 182 | 183 | if "api_ver" not in j_res \ 184 | or "result" not in j_res \ 185 | or "statuscode" not in j_res \ 186 | or "timestamp" not in j_res : 187 | print("Return value error.") 188 | return False 189 | 190 | # delete created plan 191 | url = "127.0.0.1:8081/ob/plans/%s" % j_res["result"]["uuid"] 192 | ret_code, ret_data = common.http_send(url, "DELETE", None) 193 | if ret_code != 200: 194 | print("Return value error.") 195 | return False 196 | 197 | ret = test_ob_plan_data_types(j_res["result"]) 198 | return ret 199 | 200 | 201 | #### Test 202 | 203 | print("test_ob_plan") 204 | ret = test_default_return_ob_plans() 205 | if ret != True: 206 | raise 207 | 208 | ret = test_default_create_and_delete_ob_plans() 209 | if ret != True: 210 | raise 211 | 212 | ret = test_ob_plan_create_item_check() 213 | if ret != True: 214 | raise 215 | -------------------------------------------------------------------------------- /doc/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source 10 | set I18NSPHINXOPTS=%SPHINXOPTS% source 11 | if NOT "%PAPER%" == "" ( 12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 14 | ) 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "help" ( 19 | :help 20 | echo.Please use `make ^` where ^ is one of 21 | echo. html to make standalone HTML files 22 | echo. dirhtml to make HTML files named index.html in directories 23 | echo. singlehtml to make a single large HTML file 24 | echo. pickle to make pickle files 25 | echo. json to make JSON files 26 | echo. htmlhelp to make HTML files and a HTML help project 27 | echo. qthelp to make HTML files and a qthelp project 28 | echo. devhelp to make HTML files and a Devhelp project 29 | echo. epub to make an epub 30 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 31 | echo. text to make text files 32 | echo. man to make manual pages 33 | echo. texinfo to make Texinfo files 34 | echo. gettext to make PO message catalogs 35 | echo. changes to make an overview over all changed/added/deprecated items 36 | echo. xml to make Docutils-native XML files 37 | echo. pseudoxml to make pseudoxml-XML files for display purposes 38 | echo. linkcheck to check all external links for integrity 39 | echo. doctest to run all doctests embedded in the documentation if enabled 40 | echo. coverage to run coverage check of the documentation if enabled 41 | goto end 42 | ) 43 | 44 | if "%1" == "clean" ( 45 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 46 | del /q /s %BUILDDIR%\* 47 | goto end 48 | ) 49 | 50 | 51 | REM Check if sphinx-build is available and fallback to Python version if any 52 | %SPHINXBUILD% 1>NUL 2>NUL 53 | if errorlevel 9009 goto sphinx_python 54 | goto sphinx_ok 55 | 56 | :sphinx_python 57 | 58 | set SPHINXBUILD=python -m sphinx.__init__ 59 | %SPHINXBUILD% 2> nul 60 | if errorlevel 9009 ( 61 | echo. 62 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 63 | echo.installed, then set the SPHINXBUILD environment variable to point 64 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 65 | echo.may add the Sphinx directory to PATH. 66 | echo. 67 | echo.If you don't have Sphinx installed, grab it from 68 | echo.http://sphinx-doc.org/ 69 | exit /b 1 70 | ) 71 | 72 | :sphinx_ok 73 | 74 | 75 | if "%1" == "html" ( 76 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 77 | if errorlevel 1 exit /b 1 78 | echo. 79 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 80 | goto end 81 | ) 82 | 83 | if "%1" == "dirhtml" ( 84 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 85 | if errorlevel 1 exit /b 1 86 | echo. 87 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 88 | goto end 89 | ) 90 | 91 | if "%1" == "singlehtml" ( 92 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 93 | if errorlevel 1 exit /b 1 94 | echo. 95 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 96 | goto end 97 | ) 98 | 99 | if "%1" == "pickle" ( 100 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 101 | if errorlevel 1 exit /b 1 102 | echo. 103 | echo.Build finished; now you can process the pickle files. 104 | goto end 105 | ) 106 | 107 | if "%1" == "json" ( 108 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 109 | if errorlevel 1 exit /b 1 110 | echo. 111 | echo.Build finished; now you can process the JSON files. 112 | goto end 113 | ) 114 | 115 | if "%1" == "htmlhelp" ( 116 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 117 | if errorlevel 1 exit /b 1 118 | echo. 119 | echo.Build finished; now you can run HTML Help Workshop with the ^ 120 | .hhp project file in %BUILDDIR%/htmlhelp. 121 | goto end 122 | ) 123 | 124 | if "%1" == "qthelp" ( 125 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 126 | if errorlevel 1 exit /b 1 127 | echo. 128 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 129 | .qhcp project file in %BUILDDIR%/qthelp, like this: 130 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\jade.qhcp 131 | echo.To view the help file: 132 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\jade.ghc 133 | goto end 134 | ) 135 | 136 | if "%1" == "devhelp" ( 137 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 138 | if errorlevel 1 exit /b 1 139 | echo. 140 | echo.Build finished. 141 | goto end 142 | ) 143 | 144 | if "%1" == "epub" ( 145 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 146 | if errorlevel 1 exit /b 1 147 | echo. 148 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 149 | goto end 150 | ) 151 | 152 | if "%1" == "latex" ( 153 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 154 | if errorlevel 1 exit /b 1 155 | echo. 156 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 157 | goto end 158 | ) 159 | 160 | if "%1" == "latexpdf" ( 161 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 162 | cd %BUILDDIR%/latex 163 | make all-pdf 164 | cd %~dp0 165 | echo. 166 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 167 | goto end 168 | ) 169 | 170 | if "%1" == "latexpdfja" ( 171 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 172 | cd %BUILDDIR%/latex 173 | make all-pdf-ja 174 | cd %~dp0 175 | echo. 176 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 177 | goto end 178 | ) 179 | 180 | if "%1" == "text" ( 181 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 182 | if errorlevel 1 exit /b 1 183 | echo. 184 | echo.Build finished. The text files are in %BUILDDIR%/text. 185 | goto end 186 | ) 187 | 188 | if "%1" == "man" ( 189 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 190 | if errorlevel 1 exit /b 1 191 | echo. 192 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 193 | goto end 194 | ) 195 | 196 | if "%1" == "texinfo" ( 197 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 198 | if errorlevel 1 exit /b 1 199 | echo. 200 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 201 | goto end 202 | ) 203 | 204 | if "%1" == "gettext" ( 205 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 206 | if errorlevel 1 exit /b 1 207 | echo. 208 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 209 | goto end 210 | ) 211 | 212 | if "%1" == "changes" ( 213 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 214 | if errorlevel 1 exit /b 1 215 | echo. 216 | echo.The overview file is in %BUILDDIR%/changes. 217 | goto end 218 | ) 219 | 220 | if "%1" == "linkcheck" ( 221 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 222 | if errorlevel 1 exit /b 1 223 | echo. 224 | echo.Link check complete; look for any errors in the above output ^ 225 | or in %BUILDDIR%/linkcheck/output.txt. 226 | goto end 227 | ) 228 | 229 | if "%1" == "doctest" ( 230 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 231 | if errorlevel 1 exit /b 1 232 | echo. 233 | echo.Testing of doctests in the sources finished, look at the ^ 234 | results in %BUILDDIR%/doctest/output.txt. 235 | goto end 236 | ) 237 | 238 | if "%1" == "coverage" ( 239 | %SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage 240 | if errorlevel 1 exit /b 1 241 | echo. 242 | echo.Testing of coverage in the sources finished, look at the ^ 243 | results in %BUILDDIR%/coverage/python.txt. 244 | goto end 245 | ) 246 | 247 | if "%1" == "xml" ( 248 | %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml 249 | if errorlevel 1 exit /b 1 250 | echo. 251 | echo.Build finished. The XML files are in %BUILDDIR%/xml. 252 | goto end 253 | ) 254 | 255 | if "%1" == "pseudoxml" ( 256 | %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml 257 | if errorlevel 1 exit /b 1 258 | echo. 259 | echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. 260 | goto end 261 | ) 262 | 263 | :end 264 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = build 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 21 | 22 | .PHONY: help 23 | help: 24 | @echo "Please use \`make ' where is one of" 25 | @echo " html to make standalone HTML files" 26 | @echo " dirhtml to make HTML files named index.html in directories" 27 | @echo " singlehtml to make a single large HTML file" 28 | @echo " pickle to make pickle files" 29 | @echo " json to make JSON files" 30 | @echo " htmlhelp to make HTML files and a HTML help project" 31 | @echo " qthelp to make HTML files and a qthelp project" 32 | @echo " applehelp to make an Apple Help Book" 33 | @echo " devhelp to make HTML files and a Devhelp project" 34 | @echo " epub to make an epub" 35 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 36 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 37 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 38 | @echo " text to make text files" 39 | @echo " man to make manual pages" 40 | @echo " texinfo to make Texinfo files" 41 | @echo " info to make Texinfo files and run them through makeinfo" 42 | @echo " gettext to make PO message catalogs" 43 | @echo " changes to make an overview of all changed/added/deprecated items" 44 | @echo " xml to make Docutils-native XML files" 45 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 46 | @echo " linkcheck to check all external links for integrity" 47 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 48 | @echo " coverage to run coverage check of the documentation (if enabled)" 49 | 50 | .PHONY: clean 51 | clean: 52 | rm -rf $(BUILDDIR)/* 53 | 54 | .PHONY: html 55 | html: 56 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 57 | @echo 58 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 59 | 60 | .PHONY: dirhtml 61 | dirhtml: 62 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 63 | @echo 64 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 65 | 66 | .PHONY: singlehtml 67 | singlehtml: 68 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 69 | @echo 70 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 71 | 72 | .PHONY: pickle 73 | pickle: 74 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 75 | @echo 76 | @echo "Build finished; now you can process the pickle files." 77 | 78 | .PHONY: json 79 | json: 80 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 81 | @echo 82 | @echo "Build finished; now you can process the JSON files." 83 | 84 | .PHONY: htmlhelp 85 | htmlhelp: 86 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 87 | @echo 88 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 89 | ".hhp project file in $(BUILDDIR)/htmlhelp." 90 | 91 | .PHONY: qthelp 92 | qthelp: 93 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 94 | @echo 95 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 96 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 97 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/jade.qhcp" 98 | @echo "To view the help file:" 99 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/jade.qhc" 100 | 101 | .PHONY: applehelp 102 | applehelp: 103 | $(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp 104 | @echo 105 | @echo "Build finished. The help book is in $(BUILDDIR)/applehelp." 106 | @echo "N.B. You won't be able to view it unless you put it in" \ 107 | "~/Library/Documentation/Help or install it in your application" \ 108 | "bundle." 109 | 110 | .PHONY: devhelp 111 | devhelp: 112 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 113 | @echo 114 | @echo "Build finished." 115 | @echo "To view the help file:" 116 | @echo "# mkdir -p $$HOME/.local/share/devhelp/jade" 117 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/jade" 118 | @echo "# devhelp" 119 | 120 | .PHONY: epub 121 | epub: 122 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 123 | @echo 124 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 125 | 126 | .PHONY: latex 127 | latex: 128 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 129 | @echo 130 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 131 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 132 | "(use \`make latexpdf' here to do that automatically)." 133 | 134 | .PHONY: latexpdf 135 | latexpdf: 136 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 137 | @echo "Running LaTeX files through pdflatex..." 138 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 139 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 140 | 141 | .PHONY: latexpdfja 142 | latexpdfja: 143 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 144 | @echo "Running LaTeX files through platex and dvipdfmx..." 145 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 146 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 147 | 148 | .PHONY: text 149 | text: 150 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 151 | @echo 152 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 153 | 154 | .PHONY: man 155 | man: 156 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 157 | @echo 158 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 159 | 160 | .PHONY: texinfo 161 | texinfo: 162 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 163 | @echo 164 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 165 | @echo "Run \`make' in that directory to run these through makeinfo" \ 166 | "(use \`make info' here to do that automatically)." 167 | 168 | .PHONY: info 169 | info: 170 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 171 | @echo "Running Texinfo files through makeinfo..." 172 | make -C $(BUILDDIR)/texinfo info 173 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 174 | 175 | .PHONY: gettext 176 | gettext: 177 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 178 | @echo 179 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 180 | 181 | .PHONY: changes 182 | changes: 183 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 184 | @echo 185 | @echo "The overview file is in $(BUILDDIR)/changes." 186 | 187 | .PHONY: linkcheck 188 | linkcheck: 189 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 190 | @echo 191 | @echo "Link check complete; look for any errors in the above output " \ 192 | "or in $(BUILDDIR)/linkcheck/output.txt." 193 | 194 | .PHONY: doctest 195 | doctest: 196 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 197 | @echo "Testing of doctests in the sources finished, look at the " \ 198 | "results in $(BUILDDIR)/doctest/output.txt." 199 | 200 | .PHONY: coverage 201 | coverage: 202 | $(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage 203 | @echo "Testing of coverage in the sources finished, look at the " \ 204 | "results in $(BUILDDIR)/coverage/python.txt." 205 | 206 | .PHONY: xml 207 | xml: 208 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 209 | @echo 210 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 211 | 212 | .PHONY: pseudoxml 213 | pseudoxml: 214 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 215 | @echo 216 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 217 | -------------------------------------------------------------------------------- /src/includes/admin_handler.h: -------------------------------------------------------------------------------- 1 | /* 2 | * admin_handler.h 3 | * 4 | * Created on: Apr 19, 2018 5 | * Author: pchero 6 | */ 7 | 8 | #ifndef SRC_INCLUDES_ADMIN_HANDLER_H_ 9 | #define SRC_INCLUDES_ADMIN_HANDLER_H_ 10 | 11 | #include 12 | 13 | bool admin_init_handler(void); 14 | bool admin_term_handler(void); 15 | bool admin_reload_handler(void); 16 | 17 | json_t* admin_get_subscribable_topics_all(const json_t* j_user); 18 | 19 | // http handlers 20 | 21 | 22 | //// ^/admin/core 23 | void admin_htp_get_admin_core_channels(evhtp_request_t *req, void *data); 24 | void admin_htp_get_admin_core_channels_detail(evhtp_request_t *req, void *data); 25 | void admin_htp_delete_admin_core_channels_detail(evhtp_request_t *req, void *data); 26 | void admin_htp_get_admin_core_modules(evhtp_request_t *req, void *data); 27 | void admin_htp_get_admin_core_modules_detail(evhtp_request_t *req, void *data); 28 | void admin_htp_post_admin_core_modules_detail(evhtp_request_t *req, void *data); 29 | void admin_htp_put_admin_core_modules_detail(evhtp_request_t *req, void *data); 30 | void admin_htp_delete_admin_core_modules_detail(evhtp_request_t *req, void *data); 31 | void admin_htp_get_admin_core_systems(evhtp_request_t *req, void *data); 32 | void admin_htp_get_admin_core_systems_detail(evhtp_request_t *req, void *data); 33 | 34 | 35 | //// ^/admin/dialplan/adps 36 | void admin_htp_get_admin_dialplan_adps(evhtp_request_t *req, void *data); 37 | void admin_htp_post_admin_dialplan_adps(evhtp_request_t *req, void *data); 38 | 39 | void admin_htp_get_admin_dialplan_adps_detail(evhtp_request_t *req, void *data); 40 | void admin_htp_put_admin_dialplan_adps_detail(evhtp_request_t *req, void *data); 41 | void admin_htp_delete_admin_dialplan_adps_detail(evhtp_request_t *req, void *data); 42 | 43 | 44 | //// ^/admin/dialplan/adpmas 45 | void admin_htp_get_admin_dialplan_adpmas(evhtp_request_t *req, void *data); 46 | void admin_htp_post_admin_dialplan_adpmas(evhtp_request_t *req, void *data); 47 | 48 | void admin_htp_get_admin_dialplan_adpmas_detail(evhtp_request_t *req, void *data); 49 | void admin_htp_put_admin_dialplan_adpmas_detail(evhtp_request_t *req, void *data); 50 | void admin_htp_delete_admin_dialplan_adpmas_detail(evhtp_request_t *req, void *data); 51 | 52 | 53 | //// ^/admin/dialplan/configurations 54 | void admin_htp_delete_admin_dialplan_sdps_detail(evhtp_request_t *req, void *data); 55 | void admin_htp_get_admin_dialplan_configurations(evhtp_request_t *req, void *data); 56 | void admin_htp_get_admin_dialplan_configurations_detail(evhtp_request_t *req, void *data); 57 | void admin_htp_put_admin_dialplan_configurations_detail(evhtp_request_t *req, void *data); 58 | void admin_htp_delete_admin_dialplan_configurations_detail(evhtp_request_t *req, void *data); 59 | 60 | 61 | //// ^/admin/dialplan/sdps 62 | void admin_htp_get_admin_dialplan_sdps(evhtp_request_t *req, void *data); 63 | void admin_htp_post_admin_dialplan_sdps(evhtp_request_t *req, void *data); 64 | 65 | void admin_htp_get_admin_dialplan_sdps_detail(evhtp_request_t *req, void *data); 66 | void admin_htp_put_admin_dialplan_sdps_detail(evhtp_request_t *req, void *data); 67 | void admin_htp_delete_admin_dialplan_sdps_detail(evhtp_request_t *req, void *data); 68 | 69 | 70 | //// ^/admin/login 71 | void admin_htp_post_admin_login(evhtp_request_t *req, void *data); 72 | void admin_htp_delete_admin_login(evhtp_request_t *req, void *data); 73 | 74 | 75 | //// ^/admin/info 76 | void admin_htp_get_admin_info(evhtp_request_t *req, void *data); 77 | void admin_htp_put_admin_info(evhtp_request_t *req, void *data); 78 | 79 | 80 | 81 | 82 | //// ^/admin/park 83 | void admin_htp_get_admin_park_parkedcalls(evhtp_request_t *req, void *data); 84 | void admin_htp_get_admin_park_parkedcalls_detail(evhtp_request_t *req, void *data); 85 | void admin_htp_delete_admin_park_parkinglots_detail(evhtp_request_t *req, void *data); 86 | 87 | void admin_htp_get_admin_park_parkinglots(evhtp_request_t *req, void *data); 88 | void admin_htp_get_admin_park_parkinglots_detail(evhtp_request_t *req, void *data); 89 | 90 | void admin_htp_get_admin_park_cfg_parkinglots(evhtp_request_t *req, void *data); 91 | void admin_htp_post_admin_park_cfg_parkinglots(evhtp_request_t *req, void *data); 92 | 93 | void admin_htp_get_admin_park_cfg_parkinglots_detail(evhtp_request_t *req, void *data); 94 | void admin_htp_put_admin_park_cfg_parkinglots_detail(evhtp_request_t *req, void *data); 95 | void admin_htp_delete_admin_park_cfg_parkinglots_detail(evhtp_request_t *req, void *data); 96 | 97 | void admin_htp_get_admin_park_configurations(evhtp_request_t *req, void *data); 98 | 99 | void admin_htp_get_admin_park_configurations_detail(evhtp_request_t *req, void *data); 100 | void admin_htp_put_admin_park_configurations_detail(evhtp_request_t *req, void *data); 101 | void admin_htp_delete_admin_park_configurations_detail(evhtp_request_t *req, void *data); 102 | 103 | 104 | 105 | //// ^/admin/pjsip 106 | void admin_htp_get_admin_pjsip_aors(evhtp_request_t *req, void *data); 107 | void admin_htp_get_admin_pjsip_aors_detail(evhtp_request_t *req, void *data); 108 | 109 | void admin_htp_get_admin_pjsip_auths(evhtp_request_t *req, void *data); 110 | void admin_htp_get_admin_pjsip_auths_detail(evhtp_request_t *req, void *data); 111 | 112 | void admin_htp_get_admin_pjsip_configurations(evhtp_request_t *req, void *data); 113 | 114 | void admin_htp_get_admin_pjsip_configurations_detail(evhtp_request_t *req, void *data); 115 | void admin_htp_put_admin_pjsip_configurations_detail(evhtp_request_t *req, void *data); 116 | void admin_htp_delete_admin_pjsip_configurations_detail(evhtp_request_t *req, void *data); 117 | 118 | void admin_htp_get_admin_pjsip_contacts(evhtp_request_t *req, void *data); 119 | void admin_htp_get_admin_pjsip_contacts_detail(evhtp_request_t *req, void *data); 120 | 121 | void admin_htp_get_admin_pjsip_endpoints(evhtp_request_t *req, void *data); 122 | void admin_htp_get_admin_pjsip_endpoints_detail(evhtp_request_t *req, void *data); 123 | 124 | void admin_htp_get_admin_pjsip_registration_outbounds(evhtp_request_t *req, void *data); 125 | void admin_htp_get_admin_pjsip_registration_outbounds_detail(evhtp_request_t *req, void *data); 126 | 127 | 128 | //// ^/admin/queue 129 | void admin_htp_get_admin_queue_entries(evhtp_request_t *req, void *data); 130 | void admin_htp_get_admin_queue_entries_detail(evhtp_request_t *req, void *data); 131 | void admin_htp_delete_admin_queue_entries_detail(evhtp_request_t *req, void *data); 132 | 133 | void admin_htp_get_admin_queue_queues(evhtp_request_t *req, void *data); 134 | void admin_htp_get_admin_queue_queues_detail(evhtp_request_t *req, void *data); 135 | 136 | void admin_htp_get_admin_queue_members(evhtp_request_t *req, void *data); 137 | void admin_htp_post_admin_queue_members(evhtp_request_t *req, void *data); 138 | 139 | void admin_htp_get_admin_queue_members_detail(evhtp_request_t *req, void *data); 140 | void admin_htp_put_admin_queue_members_detail(evhtp_request_t *req, void *data); 141 | void admin_htp_delete_admin_queue_member_detail(evhtp_request_t *req, void *data); 142 | 143 | void admin_htp_get_admin_queue_cfg_queues(evhtp_request_t *req, void *data); 144 | void admin_htp_post_admin_queue_cfg_queues(evhtp_request_t *req, void *data); 145 | 146 | void admin_htp_get_admin_queue_cfg_queues_detail(evhtp_request_t *req, void *data); 147 | void admin_htp_put_admin_queue_cfg_queues_detail(evhtp_request_t *req, void *data); 148 | void admin_htp_delete_admin_queue_cfg_queues_detail(evhtp_request_t *req, void *data); 149 | 150 | void admin_htp_get_admin_queue_configurations(evhtp_request_t *req, void *data); 151 | 152 | void admin_htp_get_admin_queue_configurations_detail(evhtp_request_t *req, void *data); 153 | void admin_htp_put_admin_queue_configurations_detail(evhtp_request_t *req, void *data); 154 | void admin_htp_delete_admin_queue_configurations_detail(evhtp_request_t *req, void *data); 155 | 156 | 157 | 158 | //// ^/admin/user 159 | 160 | // users 161 | void admin_htp_get_admin_user_users(evhtp_request_t *req, void *data); 162 | void admin_htp_post_admin_user_users(evhtp_request_t *req, void *data); 163 | 164 | void admin_htp_get_admin_user_users_detail(evhtp_request_t *req, void *data); 165 | void admin_htp_put_admin_user_users_detail(evhtp_request_t *req, void *data); 166 | void admin_htp_delete_admin_user_users_detail(evhtp_request_t *req, void *data); 167 | 168 | // contacts 169 | void admin_htp_get_admin_user_contacts(evhtp_request_t *req, void *data); 170 | void admin_htp_post_admin_user_contacts(evhtp_request_t *req, void *data); 171 | 172 | void admin_htp_get_admin_user_contacts_detail(evhtp_request_t *req, void *data); 173 | void admin_htp_put_admin_user_contacts_detail(evhtp_request_t *req, void *data); 174 | void admin_htp_delete_admin_user_contacts_detail(evhtp_request_t *req, void *data); 175 | 176 | // permissions 177 | void admin_htp_get_admin_user_permissions(evhtp_request_t *req, void *data); 178 | void admin_htp_post_admin_user_permissions(evhtp_request_t *req, void *data); 179 | 180 | void admin_htp_get_admin_user_permissions_detail(evhtp_request_t *req, void *data); 181 | void admin_htp_delete_admin_user_permissions_detail(evhtp_request_t *req, void *data); 182 | 183 | 184 | 185 | 186 | #endif /* SRC_INCLUDES_ADMIN_HANDLER_H_ */ 187 | --------------------------------------------------------------------------------