00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "asterisk.h"
00017
00018 #include <stdlib.h>
00019 #include <errno.h>
00020 #include <unistd.h>
00021 #include <string.h>
00022 #include <stdlib.h>
00023 #include <stdio.h>
00024 #include <sys/time.h>
00025 #include <sys/signal.h>
00026 #include <netinet/in.h>
00027 #include <sys/types.h>
00028 #include <sys/socket.h>
00029
00030 #include "asterisk/file.h"
00031 #include "asterisk/logger.h"
00032 #include "asterisk/channel.h"
00033 #include "asterisk/pbx.h"
00034 #include "asterisk/options.h"
00035 #include "asterisk/module.h"
00036 #include "asterisk/translate.h"
00037 #include "asterisk/say.h"
00038 #include "asterisk/features.h"
00039 #include "asterisk/musiconhold.h"
00040 #include "asterisk/config.h"
00041 #include "asterisk/cli.h"
00042 #include "asterisk/manager.h"
00043 #include "asterisk/utils.h"
00044 #include "asterisk/lock.h"
00045 #include "asterisk/adsi.h"
00046
00047
00048 AST_MUTEX_DEFINE_STATIC(listlock);
00049
00050 typedef struct esel_extension_state {
00051 char context[AST_MAX_EXTENSION];
00052 char exten[AST_MAX_EXTENSION];
00053 int state;
00054 char cid_num[AST_MAX_EXTENSION];
00055 char cid_name[AST_MAX_EXTENSION];
00056 char devstate[AST_MAX_EXTENSION];
00057 struct esel_extension_state *next;
00058 struct esel_extension_state *prev;
00059 } esel_extension_state;
00060
00061 typedef struct esel_export {
00062 char context[AST_MAX_EXTENSION];
00063 char exten[AST_MAX_EXTENSION];
00064 char devstate[AST_MAX_EXTENSION];
00065 struct esel_export *next;
00066 } esel_export;
00067
00068 typedef struct esel_queue {
00069 struct esel_extension_state *head;
00070 struct esel_extension_state *tail;
00071 int count;
00072 ast_cond_t cond;
00073 ast_mutex_t lock;
00074 } esel_queue;
00075
00076 typedef struct esel_pvt {
00077 char name[80];
00078 char username[80];
00079 char secret[80];
00080 char host[80];
00081 int port;
00082 struct sockaddr_in raddr;
00083 int sockfd;
00084 int connected;
00085 pthread_t esel_thread;
00086
00087
00088 struct esel_export *extensions;
00089
00090
00091 struct esel_queue queue;
00092
00093 struct esel_pvt *next;
00094 } esel_pvt;
00095
00096 static struct esel_pvt *donkeys = NULL;
00097
00098 static int esel_queue_extension_state(struct esel_queue *queue, char *context, char *exten, int state, void *data, char *cid_num, char *cid_name) {
00099 struct esel_extension_state *exstate = NULL;
00100
00101 exstate = malloc(sizeof(struct esel_extension_state));
00102 if (!exstate) {
00103 ast_log(LOG_ERROR, "Unable to malloc!\n");
00104 return 1;
00105 }
00106 memset(exstate,0,sizeof(struct esel_extension_state));
00107 exstate->next = NULL;
00108 exstate->prev = NULL;
00109
00110 ast_mutex_lock(&queue->lock);
00111 if (queue->count > 100) {
00112 ast_mutex_unlock(&queue->lock);
00113 free(exstate);
00114 if (option_verbose > 5)
00115 ast_log(LOG_WARNING, "E.S.E.L Queue too long.\n");
00116 return -1;
00117 }
00118 ast_copy_string(exstate->exten, exten, sizeof(exstate->exten));
00119 ast_copy_string(exstate->context, context, sizeof(exstate->context));
00120 ast_copy_string(exstate->cid_num, cid_num, sizeof(exstate->cid_num));
00121 ast_copy_string(exstate->cid_name, cid_name, sizeof(exstate->cid_name));
00122 exstate->state = state;
00123 if (!queue->head) {
00124
00125 queue->head = exstate;
00126 queue->tail = exstate;
00127 } else {
00128
00129 queue->tail->next = exstate;
00130 exstate->prev = queue->tail;
00131 queue->tail = exstate;
00132 }
00133 queue->count++;
00134 ast_cond_signal(&queue->cond);
00135 ast_mutex_unlock(&queue->lock);
00136 return 0;
00137 }
00138
00139 static int esel_is_exported(struct esel_export *extensions, struct esel_extension_state *exstate) {
00140 struct esel_export *export = NULL;
00141 export = extensions;
00142 while (export) {
00143 if ((!strcasecmp(export->exten, exstate->exten)) && (!strcasecmp(export->context, exstate->context))) {
00144
00145 ast_copy_string(exstate->devstate, export->devstate, sizeof(exstate->devstate));
00146 return 1;
00147 }
00148 export = export->next;
00149 }
00150 return 0;
00151 }
00152
00153 static int esel_state2devstate(int state) {
00154 switch(state) {
00155 case 1:
00156 return 2;
00157 case 8:
00158 return 6;
00159 default:
00160 return state;
00161 }
00162 }
00163
00164 static void esel_export_to_remote(struct esel_extension_state *exstate, struct esel_pvt *esel) {
00165 char msg[1024];
00166 int sent = 0;
00167 memset(msg, 0x0, sizeof(msg));
00168 snprintf(msg, sizeof(msg) - 1, "Action: Devstate\r\nDevstate: %s\r\nValue: %d\r\nCallerID: %s\r\nCallerIDName: %s\r\n\r\n", exstate->devstate, esel_state2devstate(exstate->state), exstate->cid_num, exstate->cid_name);
00169 sent = send(esel->sockfd, msg, strlen(msg), 0);
00170 if (sent == -1) {
00171 esel->connected = 0;
00172 }
00173
00174 }
00175
00176 static void *do_esel_thread(void *data) {
00177 struct esel_pvt *esel = (struct esel_pvt *)data;
00178 struct esel_queue *queue = &esel->queue;
00179 struct esel_extension_state *exstate = NULL;
00180 char msg[1024];
00181 char buf[1024];
00182 int numbytes = 0;
00183 int sent = 0;
00184 int res = 0;
00185 for (;;) {
00186 if (esel->connected) {
00187 ast_mutex_lock(&queue->lock);
00188 if (queue->count == 0)
00189 ast_cond_wait(&queue->cond, &queue->lock);
00190 exstate = queue->head;
00191 if (exstate) {
00192 if (exstate->next) {
00193 queue->head = exstate->next;
00194 } else {
00195 queue->head = NULL;
00196 queue->tail = NULL;
00197 }
00198 queue->count--;
00199 } else {
00200 ast_log(LOG_ERROR, "I SHOULD NEVER HAPPEN! EXPECT SOME MAJOR KABOOM! DUCK AND COVER!\n");
00201 }
00202 ast_mutex_unlock(&queue->lock);
00203
00204 if (exstate) {
00205 if (esel_is_exported(esel->extensions, exstate)) {
00206 esel_export_to_remote(exstate, esel);
00207 }
00208 free(exstate);
00209 exstate = NULL;
00210 }
00211 } else {
00212 if (esel->sockfd > 0)
00213 close(esel->sockfd);
00214 if ((esel->sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1) {
00215 ast_log(LOG_ERROR, "unable to request socket!\n");
00216 return NULL;
00217 }
00218
00219 res = connect(esel->sockfd, (struct sockaddr *)&esel->raddr, sizeof(struct sockaddr));
00220 if (res) {
00221 ast_log(LOG_NOTICE, "error connecting to %s:%d\n", esel->host, esel->port);
00222 } else {
00223 while (strncasecmp(buf, "Asterisk Call Manager:", 21)) {
00224 if ((numbytes=recv(esel->sockfd, buf, sizeof(buf), 0)) == -1) {
00225 esel->connected = 0;
00226 continue;
00227 }
00228 buf[numbytes] = '\0';
00229
00230 }
00231
00232 memset(msg, 0x0, sizeof(msg));
00233 snprintf(msg, sizeof(msg) - 1, "Action: Login\r\nUsername: %s\r\nSecret: %s\r\n\r\n", esel->username, esel->secret);
00234 sent = send(esel->sockfd, msg, strlen(msg), 0);
00235
00236 while (strncasecmp(buf, "Response:", 9)) {
00237 if ((numbytes=recv(esel->sockfd, buf, sizeof(buf), 0)) == -1) {
00238 continue;
00239 }
00240 buf[numbytes] = '\0';
00241
00242 }
00243
00244 if (!strncasecmp(buf, "Response: Success", 17)) {
00245 esel->connected = 1;
00246 } else {
00247 ast_log(LOG_ERROR, "error login into remote asterisk %s\n", esel->name);
00248 }
00249 }
00250
00251 sleep(10);
00252 }
00253 }
00254 return NULL;
00255 }
00256
00257 static int esel_state_cb(char *context, char *exten, int state, void *data, char *cid_num, char *cid_name) {
00258 struct esel_pvt *esel;
00259
00260 esel = donkeys;
00261 ast_mutex_lock(&listlock);
00262 while (esel) {
00263 esel_queue_extension_state(&esel->queue, context, exten, state, data, cid_num, cid_name);
00264 esel = esel->next;
00265 }
00266 ast_mutex_unlock(&listlock);
00267 return 0;
00268 }
00269
00270
00271 static int load_module(void)
00272 {
00273 int res = 0;
00274 const char *cat, *host, *port, *username, *secret, *name;
00275 struct ast_config *cfg;
00276 struct ast_variable *var;
00277 struct esel_pvt *esel = NULL;
00278 struct esel_export *export = NULL;
00279 struct hostent *he;
00280 struct ast_hostent h;
00281
00282 cfg = ast_config_load("esel.conf");
00283 if (cfg) {
00284 cat = ast_category_browse(cfg, NULL);
00285 while(cat) {
00286 name = cat;
00287 host = ast_variable_retrieve(cfg, cat, "host");
00288 username = ast_variable_retrieve(cfg, cat, "username");
00289 secret = ast_variable_retrieve(cfg, cat, "secret");
00290 port = ast_variable_retrieve(cfg, cat, "port");
00291
00292 if (name && host && username && secret && port) {
00293 esel = malloc(sizeof(struct esel_pvt));
00294 if (!esel) {
00295 ast_log(LOG_ERROR, "unable to malloc!\n");
00296 return -1;
00297 }
00298 memset(esel, 0x0, sizeof(struct esel_pvt));
00299 ast_copy_string(esel->name, name, sizeof(esel->name));
00300 ast_copy_string(esel->host, host, sizeof(esel->host));
00301 ast_copy_string(esel->username, username, sizeof(esel->username));
00302 ast_copy_string(esel->secret, secret, sizeof(esel->secret));
00303
00304 esel->port = atoi(port);
00305 if ((he=ast_gethostbyname(host, &h)) == NULL) {
00306 ast_log(LOG_ERROR, "unknown host!\n");
00307 return -1;
00308 }
00309
00310 esel->raddr.sin_family = AF_INET;
00311 esel->raddr.sin_port = htons(esel->port);
00312 esel->raddr.sin_addr = *((struct in_addr *)he->h_addr);
00313 bzero(&(esel->raddr.sin_zero), 8);
00314
00315 esel->connected = 0;
00316
00317 ast_mutex_init(&esel->queue.lock);
00318 ast_cond_init(&esel->queue.cond, NULL);
00319
00320
00321
00322 var = ast_variable_browse(cfg, cat);
00323 while (var) {
00324 if (!strcasecmp(var->name, "export")) {
00325 char *extenp = NULL, *contextp = NULL, *devstatep = NULL;
00326 extenp = var->value;
00327 devstatep = strchr(var->value, ',') + 1;
00328 contextp = strchr(var->value, '@') + 1;
00329 if (devstatep && contextp) {
00330 export = malloc(sizeof(struct esel_export));
00331 if (!export) {
00332 ast_log(LOG_ERROR, "unable to malloc!\n");
00333 return -1;
00334 }
00335 memset(export, 0x0, sizeof(struct esel_export));
00336 ast_copy_string(export->exten, extenp, contextp - extenp);
00337 ast_copy_string(export->context, contextp, devstatep - contextp);
00338 ast_copy_string(export->devstate, devstatep, sizeof(export->devstate));
00339 if (option_verbose > 2)
00340 ast_verbose(VERBOSE_PREFIX_3 "exporting %s @ %s as %s to %s\n", export->exten, export->context , export->devstate , esel->name);
00341 export->next = esel->extensions;
00342 esel->extensions = export;
00343 export = NULL;
00344 }
00345 }
00346 var = var->next;
00347 }
00348
00349
00350
00351 esel->next = donkeys;
00352 donkeys = esel;
00353
00354 ast_pthread_create(&esel->esel_thread, NULL, do_esel_thread, esel);
00355
00356 }
00357 cat = ast_category_browse(cfg, cat);
00358 }
00359 ast_config_destroy(cfg);
00360 }
00361 ast_extension_state_add(NULL, NULL, esel_state_cb, NULL);
00362 return res;
00363 }
00364
00365
00366 static int unload_module(void)
00367 {
00368 struct esel_pvt *esel, *eseln;
00369 ast_module_user_hangup_all();
00370 esel = donkeys;
00371 ast_mutex_lock(&listlock);
00372 while (esel) {
00373 pthread_cancel(esel->esel_thread);
00374 pthread_join(esel->esel_thread, NULL);
00375 ast_mutex_destroy(&esel->queue.lock);
00376 close(esel->sockfd);
00377 eseln = esel->next;
00378 free(esel);
00379 esel = eseln;
00380 }
00381 ast_mutex_unlock(&listlock);
00382 return 0;
00383 }
00384
00385 AST_MODULE_INFO(ASTERISK_GPL_KEY, AST_MODFLAG_GLOBAL_SYMBOLS, "Extension State Export Logic (E.S.E.L.) Resource",
00386 .load = load_module,
00387 .unload = unload_module,
00388 );