Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals

manager.c

Go to the documentation of this file.
00001 /* 00002 * Asterisk -- A telephony toolkit for Linux. 00003 * 00004 * Channel Management and more 00005 * 00006 * Copyright (C) 1999, Mark Spencer 00007 * 00008 * Mark Spencer <markster@linux-support.net> 00009 * 00010 * This program is free software, distributed under the terms of 00011 * the GNU General Public License 00012 */ 00013 00014 #include <stdio.h> 00015 #include <stdlib.h> 00016 #include <string.h> 00017 #include <sys/time.h> 00018 #include <sys/types.h> 00019 #include <netdb.h> 00020 #include <sys/socket.h> 00021 #include <netinet/in.h> 00022 #include <netinet/tcp.h> 00023 #include <arpa/inet.h> 00024 #include <signal.h> 00025 #include <errno.h> 00026 #include <unistd.h> 00027 #include <sys/poll.h> 00028 #include <asterisk/channel.h> 00029 #include <asterisk/file.h> 00030 #include <asterisk/manager.h> 00031 #include <asterisk/config.h> 00032 #include <asterisk/lock.h> 00033 #include <asterisk/logger.h> 00034 #include <asterisk/options.h> 00035 #include <asterisk/cli.h> 00036 #include <asterisk/app.h> 00037 #include <asterisk/pbx.h> 00038 #include <asterisk/md5.h> 00039 #include <asterisk/acl.h> 00040 #include <asterisk/utils.h> 00041 00042 struct fast_originate_helper 00043 { 00044 char tech[256]; 00045 char data[256]; 00046 int timeout; 00047 char app[256]; 00048 char appdata[256]; 00049 char callerid[256]; 00050 char variable[256]; 00051 char account[256]; 00052 char context[256]; 00053 char exten[256]; 00054 int priority; 00055 }; 00056 00057 static int enabled = 0; 00058 static int portno = DEFAULT_MANAGER_PORT; 00059 static int asock = -1; 00060 static pthread_t t; 00061 AST_MUTEX_DEFINE_STATIC(sessionlock); 00062 static int block_sockets = 0; 00063 00064 static struct permalias { 00065 int num; 00066 char *label; 00067 } perms[] = { 00068 { EVENT_FLAG_SYSTEM, "system" }, 00069 { EVENT_FLAG_CALL, "call" }, 00070 { EVENT_FLAG_LOG, "log" }, 00071 { EVENT_FLAG_VERBOSE, "verbose" }, 00072 { EVENT_FLAG_COMMAND, "command" }, 00073 { EVENT_FLAG_AGENT, "agent" }, 00074 { EVENT_FLAG_USER, "user" }, 00075 { -1, "all" }, 00076 }; 00077 00078 static struct mansession *sessions = NULL; 00079 static struct manager_action *first_action = NULL; 00080 AST_MUTEX_DEFINE_STATIC(actionlock); 00081 00082 int ast_carefulwrite(int fd, char *s, int len, int timeoutms) 00083 { 00084 /* Try to write string, but wait no more than ms milliseconds 00085 before timing out */ 00086 int res=0; 00087 struct pollfd fds[1]; 00088 while(len) { 00089 res = write(fd, s, len); 00090 if ((res < 0) && (errno != EAGAIN)) { 00091 return -1; 00092 } 00093 if (res < 0) res = 0; 00094 len -= res; 00095 s += res; 00096 fds[0].fd = fd; 00097 fds[0].events = POLLOUT; 00098 /* Wait until writable again */ 00099 res = poll(fds, 1, timeoutms); 00100 if (res < 1) 00101 return -1; 00102 } 00103 return res; 00104 } 00105 00106 static char *complete_show_mancmd(char *line, char *word, int pos, int state) 00107 { 00108 struct manager_action *cur = first_action; 00109 int which = 0; 00110 00111 ast_mutex_lock(&actionlock); 00112 while (cur) { /* Walk the list of actions */ 00113 if (!strncasecmp(word, cur->action, strlen(word))) { 00114 if (++which > state) { 00115 char *ret = strdup(cur->action); 00116 ast_mutex_unlock(&actionlock); 00117 return ret; 00118 } 00119 } 00120 cur = cur->next; 00121 } 00122 ast_mutex_unlock(&actionlock); 00123 return NULL; 00124 } 00125 00126 static int handle_showmancmd(int fd, int argc, char *argv[]) 00127 { 00128 struct manager_action *cur = first_action; 00129 int num; 00130 00131 if (argc != 4) 00132 return RESULT_SHOWUSAGE; 00133 ast_mutex_lock(&actionlock); 00134 while (cur) { /* Walk the list of actions */ 00135 for (num = 3; num < argc; num++) { 00136 if (!strcasecmp(cur->action, argv[num])) { 00137 ast_cli(fd, "Action: %s\nSynopsis: %s\n%s\n", cur->action, cur->synopsis, cur->description ? cur->description : ""); 00138 } 00139 } 00140 cur = cur->next; 00141 } 00142 00143 ast_mutex_unlock(&actionlock); 00144 return RESULT_SUCCESS; 00145 } 00146 00147 static int handle_showmancmds(int fd, int argc, char *argv[]) 00148 { 00149 struct manager_action *cur = first_action; 00150 char *format = " %-15.15s %-45.45s\n"; 00151 00152 ast_mutex_lock(&actionlock); 00153 ast_cli(fd, format, "Action", "Synopsis"); 00154 while (cur) { /* Walk the list of actions */ 00155 ast_cli(fd, format, cur->action, cur->synopsis); 00156 cur = cur->next; 00157 } 00158 00159 ast_mutex_unlock(&actionlock); 00160 return RESULT_SUCCESS; 00161 } 00162 00163 static int handle_showmanconn(int fd, int argc, char *argv[]) 00164 { 00165 struct mansession *s; 00166 char iabuf[INET_ADDRSTRLEN]; 00167 char *format = " %-15.15s %-15.15s\n"; 00168 ast_mutex_lock(&sessionlock); 00169 s = sessions; 00170 ast_cli(fd, format, "Username", "IP Address"); 00171 while (s) { 00172 ast_cli(fd, format,s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr)); 00173 s = s->next; 00174 } 00175 00176 ast_mutex_unlock(&sessionlock); 00177 return RESULT_SUCCESS; 00178 } 00179 00180 static char showmancmd_help[] = 00181 "Usage: show manager command <actionname>\n" 00182 " Shows the detailed description for a specific manager command.\n"; 00183 00184 static char showmancmds_help[] = 00185 "Usage: show manager commands\n" 00186 " Prints a listing of all the available manager commands.\n"; 00187 00188 static char showmanconn_help[] = 00189 "Usage: show manager connected\n" 00190 " Prints a listing of the users that are connected to the\n" 00191 "manager interface.\n"; 00192 00193 static struct ast_cli_entry show_mancmd_cli = 00194 { { "show", "manager", "command", NULL }, 00195 handle_showmancmd, "Show manager command", showmancmd_help, complete_show_mancmd }; 00196 00197 static struct ast_cli_entry show_mancmds_cli = 00198 { { "show", "manager", "commands", NULL }, 00199 handle_showmancmds, "Show manager commands", showmancmds_help }; 00200 00201 static struct ast_cli_entry show_manconn_cli = 00202 { { "show", "manager", "connected", NULL }, 00203 handle_showmanconn, "Show connected manager users", showmanconn_help }; 00204 00205 static void destroy_session(struct mansession *s) 00206 { 00207 struct mansession *cur, *prev = NULL; 00208 ast_mutex_lock(&sessionlock); 00209 cur = sessions; 00210 while(cur) { 00211 if (cur == s) 00212 break; 00213 prev = cur; 00214 cur = cur->next; 00215 } 00216 if (cur) { 00217 if (prev) 00218 prev->next = cur->next; 00219 else 00220 sessions = cur->next; 00221 if (s->fd > -1) 00222 close(s->fd); 00223 ast_mutex_destroy(&s->lock); 00224 free(s); 00225 } else 00226 ast_log(LOG_WARNING, "Trying to delete non-existant session %p?\n", s); 00227 ast_mutex_unlock(&sessionlock); 00228 00229 } 00230 00231 char *astman_get_header(struct message *m, char *var) 00232 { 00233 char cmp[80]; 00234 int x; 00235 snprintf(cmp, sizeof(cmp), "%s: ", var); 00236 for (x=0;x<m->hdrcount;x++) 00237 if (!strncasecmp(cmp, m->headers[x], strlen(cmp))) 00238 return m->headers[x] + strlen(cmp); 00239 return ""; 00240 } 00241 00242 void astman_send_error(struct mansession *s, struct message *m, char *error) 00243 { 00244 char *id = astman_get_header(m,"ActionID"); 00245 ast_mutex_lock(&s->lock); 00246 ast_cli(s->fd, "Response: Error\r\n"); 00247 if (id && !ast_strlen_zero(id)) 00248 ast_cli(s->fd, "ActionID: %s\r\n",id); 00249 ast_cli(s->fd, "Message: %s\r\n\r\n", error); 00250 ast_mutex_unlock(&s->lock); 00251 } 00252 00253 void astman_send_response(struct mansession *s, struct message *m, char *resp, char *msg) 00254 { 00255 char *id = astman_get_header(m,"ActionID"); 00256 ast_mutex_lock(&s->lock); 00257 ast_cli(s->fd, "Response: %s\r\n", resp); 00258 if (id && !ast_strlen_zero(id)) 00259 ast_cli(s->fd, "ActionID: %s\r\n",id); 00260 if (msg) 00261 ast_cli(s->fd, "Message: %s\r\n\r\n", msg); 00262 else 00263 ast_cli(s->fd, "\r\n"); 00264 ast_mutex_unlock(&s->lock); 00265 } 00266 00267 void astman_send_ack(struct mansession *s, struct message *m, char *msg) 00268 { 00269 astman_send_response(s, m, "Success", msg); 00270 } 00271 00272 /* Tells you if smallstr exists inside bigstr 00273 which is delim by delim and uses no buf or stringsep 00274 ast_instring("this|that|more","this",',') == 1; 00275 00276 feel free to move this to app.c -anthm */ 00277 static int ast_instring(char *bigstr, char *smallstr, char delim) 00278 { 00279 char *val = bigstr, *next; 00280 00281 do { 00282 if ((next = strchr(val, delim))) { 00283 if (!strncmp(val, smallstr, (next - val))) 00284 return 1; 00285 else 00286 continue; 00287 } else 00288 return !strcmp(smallstr, val); 00289 00290 } while (*(val = (next + 1))); 00291 00292 return 0; 00293 } 00294 00295 static int get_perm(char *instr) 00296 { 00297 int x = 0, ret = 0; 00298 00299 if (!instr) 00300 return 0; 00301 00302 for (x=0; x<sizeof(perms) / sizeof(perms[0]); x++) 00303 if (ast_instring(instr, perms[x].label, ',')) 00304 ret |= perms[x].num; 00305 00306 return ret; 00307 } 00308 00309 static int ast_is_number(char *string) 00310 { 00311 int ret = 1, x = 0; 00312 00313 if (!string) 00314 return 0; 00315 00316 for (x=0; x < strlen(string); x++) { 00317 if (!(string[x] >= 48 && string[x] <= 57)) { 00318 ret = 0; 00319 break; 00320 } 00321 } 00322 00323 return ret ? atoi(string) : 0; 00324 } 00325 00326 static int ast_strings_to_mask(char *string) 00327 { 00328 int x = 0, ret = -1; 00329 00330 x = ast_is_number(string); 00331 00332 if (x) 00333 ret = x; 00334 else if (!string || ast_strlen_zero(string)) 00335 ret = -1; 00336 else if (!strcasecmp(string, "off") || ast_false(string)) 00337 ret = 0; 00338 else if (!strcasecmp(string, "on") || ast_true(string)) 00339 ret = -1; 00340 else { 00341 ret = 0; 00342 for (x=0; x<sizeof(perms) / sizeof(perms[0]); x++) { 00343 if (ast_instring(string, perms[x].label, ',')) 00344 ret |= perms[x].num; 00345 } 00346 } 00347 00348 return ret; 00349 } 00350 00351 /* 00352 Rather than braindead on,off this now can also accept a specific int mask value 00353 or a ',' delim list of mask strings (the same as manager.conf) -anthm 00354 */ 00355 00356 static int set_eventmask(struct mansession *s, char *eventmask) 00357 { 00358 int maskint = ast_strings_to_mask(eventmask); 00359 00360 ast_mutex_lock(&s->lock); 00361 s->send_events = maskint; 00362 ast_mutex_unlock(&s->lock); 00363 00364 return s->send_events; 00365 } 00366 00367 static int authenticate(struct mansession *s, struct message *m) 00368 { 00369 struct ast_config *cfg; 00370 char iabuf[INET_ADDRSTRLEN]; 00371 char *cat; 00372 char *user = astman_get_header(m, "Username"); 00373 char *pass = astman_get_header(m, "Secret"); 00374 char *authtype = astman_get_header(m, "AuthType"); 00375 char *key = astman_get_header(m, "Key"); 00376 char *events = astman_get_header(m, "Events"); 00377 00378 cfg = ast_load("manager.conf"); 00379 if (!cfg) 00380 return -1; 00381 cat = ast_category_browse(cfg, NULL); 00382 while(cat) { 00383 if (strcasecmp(cat, "general")) { 00384 /* This is a user */ 00385 if (!strcasecmp(cat, user)) { 00386 struct ast_variable *v; 00387 struct ast_ha *ha = NULL; 00388 char *password = NULL; 00389 v = ast_variable_browse(cfg, cat); 00390 while (v) { 00391 if (!strcasecmp(v->name, "secret")) { 00392 password = v->value; 00393 } else if (!strcasecmp(v->name, "permit") || 00394 !strcasecmp(v->name, "deny")) { 00395 ha = ast_append_ha(v->name, v->value, ha); 00396 } 00397 v = v->next; 00398 } 00399 if (ha && !ast_apply_ha(ha, &(s->sin))) { 00400 ast_log(LOG_NOTICE, "%s failed to pass IP ACL as '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), user); 00401 ast_free_ha(ha); 00402 ast_destroy(cfg); 00403 return -1; 00404 } else if (ha) 00405 ast_free_ha(ha); 00406 if (!strcasecmp(authtype, "MD5")) { 00407 if (key && !ast_strlen_zero(key) && s->challenge) { 00408 int x; 00409 int len=0; 00410 char md5key[256] = ""; 00411 struct MD5Context md5; 00412 unsigned char digest[16]; 00413 MD5Init(&md5); 00414 MD5Update(&md5, s->challenge, strlen(s->challenge)); 00415 MD5Update(&md5, password, strlen(password)); 00416 MD5Final(digest, &md5); 00417 for (x=0;x<16;x++) 00418 len += sprintf(md5key + len, "%2.2x", digest[x]); 00419 if (!strcmp(md5key, key)) 00420 break; 00421 else { 00422 ast_destroy(cfg); 00423 return -1; 00424 } 00425 } 00426 } else if (password && !strcasecmp(password, pass)) { 00427 break; 00428 } else { 00429 ast_log(LOG_NOTICE, "%s failed to authenticate as '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), user); 00430 ast_destroy(cfg); 00431 return -1; 00432 } 00433 } 00434 } 00435 cat = ast_category_browse(cfg, cat); 00436 } 00437 if (cat) { 00438 strncpy(s->username, cat, sizeof(s->username) - 1); 00439 s->readperm = get_perm(ast_variable_retrieve(cfg, cat, "read")); 00440 s->writeperm = get_perm(ast_variable_retrieve(cfg, cat, "write")); 00441 ast_destroy(cfg); 00442 if (events) 00443 set_eventmask(s, events); 00444 return 0; 00445 } 00446 ast_log(LOG_NOTICE, "%s tried to authenticate with non-existant user '%s'\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), user); 00447 ast_destroy(cfg); 00448 return -1; 00449 } 00450 00451 static char mandescr_ping[] = 00452 "Description: A 'Ping' action will ellicit a 'Pong' response. Used to keep the " 00453 " manager connection open.\n" 00454 "Variables: NONE\n"; 00455 00456 static int action_ping(struct mansession *s, struct message *m) 00457 { 00458 astman_send_response(s, m, "Pong", NULL); 00459 return 0; 00460 } 00461 00462 static char mandescr_listcommands[] = 00463 "Description: Returns the action name and synopsis for every\n" 00464 " action that is available to the user\n" 00465 "Variables: NONE\n"; 00466 00467 static int action_listcommands(struct mansession *s, struct message *m) 00468 { 00469 struct manager_action *cur = first_action; 00470 char idText[256] = ""; 00471 char *id = astman_get_header(m,"ActionID"); 00472 00473 if (id && !ast_strlen_zero(id)) 00474 snprintf(idText,256,"ActionID: %s\r\n",id); 00475 ast_cli(s->fd, "Response: Success\r\n%s", idText); 00476 ast_mutex_lock(&actionlock); 00477 while (cur) { /* Walk the list of actions */ 00478 if ((s->writeperm & cur->authority) == cur->authority) 00479 ast_cli(s->fd, "%s: %s\r\n", cur->action, cur->synopsis); 00480 cur = cur->next; 00481 } 00482 ast_mutex_unlock(&actionlock); 00483 ast_cli(s->fd, "\r\n"); 00484 00485 return 0; 00486 } 00487 00488 static char mandescr_events[] = 00489 "Description: Enable/Disable sending of events to this manager\n" 00490 " client.\n" 00491 "Variables:\n" 00492 " EventMask: 'on' if all events should be sent,\n" 00493 " 'off' if no events should be sent,\n" 00494 " 'system,call,log' to select which flags events should have to be sent.\n"; 00495 00496 static int action_events(struct mansession *s, struct message *m) 00497 { 00498 char *mask = astman_get_header(m, "EventMask"); 00499 int res; 00500 00501 res = set_eventmask(s, mask); 00502 if (res > 0) 00503 astman_send_response(s, m, "Events On", NULL); 00504 else if (res == 0) 00505 astman_send_response(s, m, "Events Off", NULL); 00506 00507 return 0; 00508 } 00509 00510 static char mandescr_logoff[] = 00511 "Description: Logoff this manager session\n" 00512 "Variables: NONE\n"; 00513 00514 static int action_logoff(struct mansession *s, struct message *m) 00515 { 00516 astman_send_response(s, m, "Goodbye", "Thanks for all the fish."); 00517 return -1; 00518 } 00519 00520 static char mandescr_hangup[] = 00521 "Description: Hangup a channel\n" 00522 "Variables: \n" 00523 " Channel: The channel name to be hungup\n"; 00524 00525 static int action_hangup(struct mansession *s, struct message *m) 00526 { 00527 struct ast_channel *c = NULL; 00528 char *name = astman_get_header(m, "Channel"); 00529 if (ast_strlen_zero(name)) { 00530 astman_send_error(s, m, "No channel specified"); 00531 return 0; 00532 } 00533 c = ast_channel_walk_locked(NULL); 00534 while(c) { 00535 if (!strcasecmp(c->name, name)) { 00536 break; 00537 } 00538 ast_mutex_unlock(&c->lock); 00539 c = ast_channel_walk_locked(c); 00540 } 00541 if (!c) { 00542 astman_send_error(s, m, "No such channel"); 00543 return 0; 00544 } 00545 ast_softhangup(c, AST_SOFTHANGUP_EXPLICIT); 00546 ast_mutex_unlock(&c->lock); 00547 astman_send_ack(s, m, "Channel Hungup"); 00548 return 0; 00549 } 00550 00551 static int action_setvar(struct mansession *s, struct message *m) 00552 { 00553 struct ast_channel *c = NULL; 00554 char *name = astman_get_header(m, "Channel"); 00555 char *varname = astman_get_header(m, "Variable"); 00556 char *varval = astman_get_header(m, "Value"); 00557 00558 if (!strlen(name)) { 00559 astman_send_error(s, m, "No channel specified"); 00560 return 0; 00561 } 00562 if (!strlen(varname)) { 00563 astman_send_error(s, m, "No variable specified"); 00564 return 0; 00565 } 00566 00567 c = ast_channel_walk_locked(NULL); 00568 while(c) { 00569 if (!strcasecmp(c->name, name)) { 00570 break; 00571 } 00572 ast_mutex_unlock(&c->lock); 00573 c = ast_channel_walk_locked(c); 00574 } 00575 if (!c) { 00576 astman_send_error(s, m, "No such channel"); 00577 return 0; 00578 } 00579 00580 pbx_builtin_setvar_helper(c,varname,varval); 00581 00582 ast_mutex_unlock(&c->lock); 00583 astman_send_ack(s, m, "Variable Set"); 00584 return 0; 00585 } 00586 00587 static int action_getvar(struct mansession *s, struct message *m) 00588 { 00589 struct ast_channel *c = NULL; 00590 char *name = astman_get_header(m, "Channel"); 00591 char *varname = astman_get_header(m, "Variable"); 00592 char *varval; 00593 00594 if (!strlen(name)) { 00595 astman_send_error(s, m, "No channel specified"); 00596 return 0; 00597 } 00598 if (!strlen(varname)) { 00599 astman_send_error(s, m, "No variable specified"); 00600 return 0; 00601 } 00602 00603 c = ast_channel_walk_locked(NULL); 00604 while(c) { 00605 if (!strcasecmp(c->name, name)) { 00606 break; 00607 } 00608 ast_mutex_unlock(&c->lock); 00609 c = ast_channel_walk_locked(c); 00610 } 00611 if (!c) { 00612 astman_send_error(s, m, "No such channel"); 00613 return 0; 00614 } 00615 00616 varval=pbx_builtin_getvar_helper(c,varname); 00617 00618 ast_mutex_unlock(&c->lock); 00619 ast_cli(s->fd, "Response: Success\r\n" 00620 "%s: %s",varname,varval); 00621 00622 return 0; 00623 } 00624 00625 00626 static int action_status(struct mansession *s, struct message *m) 00627 { 00628 char *id = astman_get_header(m,"ActionID"); 00629 char *name = astman_get_header(m,"Channel"); 00630 char idText[256] = ""; 00631 struct ast_channel *c; 00632 char bridge[256]; 00633 astman_send_ack(s, m, "Channel status will follow"); 00634 c = ast_channel_walk_locked(NULL); 00635 if (id && !ast_strlen_zero(id)) 00636 snprintf(idText,256,"ActionID: %s\r\n",id); 00637 if (name && !ast_strlen_zero(name)) { 00638 while (c) { 00639 if (!strcasecmp(c->name, name)) { 00640 break; 00641 } 00642 ast_mutex_unlock(&c->lock); 00643 c = ast_channel_walk_locked(c); 00644 } 00645 if (!c) { 00646 astman_send_error(s, m, "No such channel"); 00647 return 0; 00648 } 00649 } 00650 while(c) { 00651 if (c->bridge) 00652 snprintf(bridge, sizeof(bridge), "Link: %s\r\n", c->bridge->name); 00653 else 00654 bridge[0] = '\0'; 00655 if (c->pbx) { 00656 ast_cli(s->fd, 00657 "Event: Status\r\n" 00658 "Channel: %s\r\n" 00659 "CallerID: %s\r\n" 00660 "Account: %s\r\n" 00661 "State: %s\r\n" 00662 "Context: %s\r\n" 00663 "Extension: %s\r\n" 00664 "Priority: %d\r\n" 00665 "%s" 00666 "Uniqueid: %s\r\n" 00667 "%s" 00668 "\r\n", 00669 c->name, c->callerid ? c->callerid : "<unknown>", 00670 c->accountcode, 00671 ast_state2str(c->_state), c->context, 00672 c->exten, c->priority, bridge, c->uniqueid, idText); 00673 } else { 00674 ast_cli(s->fd, 00675 "Event: Status\r\n" 00676 "Channel: %s\r\n" 00677 "CallerID: %s\r\n" 00678 "Account: %s\r\n" 00679 "State: %s\r\n" 00680 "%s" 00681 "Uniqueid: %s\r\n" 00682 "%s" 00683 "\r\n", 00684 c->name, c->callerid ? c->callerid : "<unknown>", 00685 c->accountcode, 00686 ast_state2str(c->_state), bridge, c->uniqueid, idText); 00687 } 00688 ast_mutex_unlock(&c->lock); 00689 if (name && !ast_strlen_zero(name)) { 00690 break; 00691 } 00692 c = ast_channel_walk_locked(c); 00693 } 00694 ast_cli(s->fd, 00695 "Event: StatusComplete\r\n" 00696 "%s" 00697 "\r\n",idText); 00698 return 0; 00699 } 00700 00701 static int action_redirect(struct mansession *s, struct message *m) 00702 { 00703 char *name = astman_get_header(m, "Channel"); 00704 char *name2 = astman_get_header(m, "ExtraChannel"); 00705 char *exten = astman_get_header(m, "Exten"); 00706 char *context = astman_get_header(m, "Context"); 00707 char *priority = astman_get_header(m, "Priority"); 00708 struct ast_channel *chan, *chan2 = NULL; 00709 int pi = 0; 00710 int res; 00711 if (!name || ast_strlen_zero(name)) { 00712 astman_send_error(s, m, "Channel not specified"); 00713 return 0; 00714 } 00715 if (!ast_strlen_zero(priority) && (sscanf(priority, "%d", &pi) != 1)) { 00716 astman_send_error(s, m, "Invalid priority\n"); 00717 return 0; 00718 } 00719 chan = ast_get_channel_by_name_locked(name); 00720 if (!chan) { 00721 astman_send_error(s, m, "Channel not existant"); 00722 return 0; 00723 } 00724 if (!ast_strlen_zero(name2)) 00725 chan2 = ast_get_channel_by_name_locked(name2); 00726 res = ast_async_goto(chan, context, exten, pi); 00727 if (!res) { 00728 if (!ast_strlen_zero(name2)) { 00729 if (chan2) 00730 res = ast_async_goto(chan2, context, exten, pi); 00731 else 00732 res = -1; 00733 if (!res) 00734 astman_send_ack(s, m, "Dual Redirect successful"); 00735 else 00736 astman_send_error(s, m, "Secondary redirect failed"); 00737 } else 00738 astman_send_ack(s, m, "Redirect successful"); 00739 } else 00740 astman_send_error(s, m, "Redirect failed"); 00741 if (chan) 00742 ast_mutex_unlock(&chan->lock); 00743 if (chan2) 00744 ast_mutex_unlock(&chan2->lock); 00745 return 0; 00746 } 00747 00748 static int action_command(struct mansession *s, struct message *m) 00749 { 00750 char *cmd = astman_get_header(m, "Command"); 00751 char *id = astman_get_header(m, "ActionID"); 00752 ast_mutex_lock(&s->lock); 00753 s->blocking = 1; 00754 ast_mutex_unlock(&s->lock); 00755 ast_cli(s->fd, "Response: Follows\r\n"); 00756 if (id && !ast_strlen_zero(id)) 00757 ast_cli(s->fd, "ActionID: %s\r\n", id); 00758 /* FIXME: Wedge a ActionID response in here, waiting for later changes */ 00759 ast_cli_command(s->fd, cmd); 00760 ast_cli(s->fd, "--END COMMAND--\r\n\r\n"); 00761 ast_mutex_lock(&s->lock); 00762 s->blocking = 0; 00763 ast_mutex_unlock(&s->lock); 00764 return 0; 00765 } 00766 00767 static void *fast_originate(void *data) 00768 { 00769 struct fast_originate_helper *in = data; 00770 int res; 00771 int reason = 0; 00772 if (!ast_strlen_zero(in->app)) { 00773 res = ast_pbx_outgoing_app(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->app, in->appdata, &reason, 1, !ast_strlen_zero(in->callerid) ? in->callerid : NULL, in->variable, in->account); 00774 } else { 00775 res = ast_pbx_outgoing_exten(in->tech, AST_FORMAT_SLINEAR, in->data, in->timeout, in->context, in->exten, in->priority, &reason, 1, !ast_strlen_zero(in->callerid) ? in->callerid : NULL, in->variable, in->account); 00776 } 00777 free(in); 00778 return NULL; 00779 } 00780 00781 static char mandescr_originate[] = 00782 "Description: Generates an outgoing call to a Extension/Context/Priority or\n" 00783 " Application/Data\n" 00784 "Variables: (Names marked with * are required)\n" 00785 " *Channel: Channel name to call\n" 00786 " Exten: Extension to use (requires 'Context' and 'Priority')\n" 00787 " Context: Context to use (requires 'Exten' and 'Priority')\n" 00788 " Priority: Priority to use (requires 'Exten' and 'Context')\n" 00789 " Application: Application to use\n" 00790 " Data: Data to use (requires 'Application')\n" 00791 " Timeout: How long to wait for call to be answered (in ms)\n" 00792 " CallerID: Caller ID to be set on the outgoing channel\n" 00793 " Variable: Channel variable to set (VAR1=value1|VAR2=value2)\n" 00794 " Account: Account code\n" 00795 " Async: Set to 'true' for fast origination\n"; 00796 00797 static int action_originate(struct mansession *s, struct message *m) 00798 { 00799 char *name = astman_get_header(m, "Channel"); 00800 char *exten = astman_get_header(m, "Exten"); 00801 char *context = astman_get_header(m, "Context"); 00802 char *priority = astman_get_header(m, "Priority"); 00803 char *timeout = astman_get_header(m, "Timeout"); 00804 char *callerid = astman_get_header(m, "CallerID"); 00805 char *variable = astman_get_header(m, "Variable"); 00806 char *account = astman_get_header(m, "Account"); 00807 char *app = astman_get_header(m, "Application"); 00808 char *appdata = astman_get_header(m, "Data"); 00809 char *async = astman_get_header(m, "Async"); 00810 char *tech, *data; 00811 int pi = 0; 00812 int res; 00813 int to = 30000; 00814 int reason = 0; 00815 char tmp[256]; 00816 pthread_t th; 00817 pthread_attr_t attr; 00818 if (!name) { 00819 astman_send_error(s, m, "Channel not specified"); 00820 return 0; 00821 } 00822 if (!ast_strlen_zero(priority) && (sscanf(priority, "%d", &pi) != 1)) { 00823 astman_send_error(s, m, "Invalid priority\n"); 00824 return 0; 00825 } 00826 if (!ast_strlen_zero(timeout) && (sscanf(timeout, "%d", &to) != 1)) { 00827 astman_send_error(s, m, "Invalid timeout\n"); 00828 return 0; 00829 } 00830 strncpy(tmp, name, sizeof(tmp) - 1); 00831 tech = tmp; 00832 data = strchr(tmp, '/'); 00833 if (!data) { 00834 astman_send_error(s, m, "Invalid channel\n"); 00835 return 0; 00836 } 00837 *data = '\0'; 00838 data++; 00839 if (ast_true(async)) 00840 { 00841 struct fast_originate_helper *fast = malloc(sizeof(struct fast_originate_helper)); 00842 if (!fast) 00843 { 00844 res = -1; 00845 } 00846 else 00847 { 00848 memset(fast, 0, sizeof(struct fast_originate_helper)); 00849 strncpy(fast->tech, tech, sizeof(fast->tech) - 1); 00850 strncpy(fast->data, data, sizeof(fast->data) - 1); 00851 strncpy(fast->app, app, sizeof(fast->app) - 1); 00852 strncpy(fast->appdata, appdata, sizeof(fast->appdata) - 1); 00853 strncpy(fast->callerid, callerid, sizeof(fast->callerid) - 1); 00854 strncpy(fast->variable, variable, sizeof(fast->variable) - 1); 00855 strncpy(fast->account, account, sizeof(fast->account) - 1); 00856 strncpy(fast->context, context, sizeof(fast->context) - 1); 00857 strncpy(fast->exten, exten, sizeof(fast->exten) - 1); 00858 fast->timeout = to; 00859 fast->priority = pi; 00860 pthread_attr_init(&attr); 00861 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 00862 if (pthread_create(&th, &attr, fast_originate, fast)) 00863 { 00864 res = -1; 00865 } 00866 else 00867 { 00868 res = 0; 00869 } 00870 } 00871 } else if (!ast_strlen_zero(app)) { 00872 res = ast_pbx_outgoing_app(tech, AST_FORMAT_SLINEAR, data, to, app, appdata, &reason, 0, !ast_strlen_zero(callerid) ? callerid : NULL, variable, account); 00873 } else { 00874 if (exten && context && pi) 00875 res = ast_pbx_outgoing_exten(tech, AST_FORMAT_SLINEAR, data, to, context, exten, pi, &reason, 0, !ast_strlen_zero(callerid) ? callerid : NULL, variable, account); 00876 else { 00877 astman_send_error(s, m, "Originate with 'Exten' requires 'Context' and 'Priority'"); 00878 return 0; 00879 } 00880 } 00881 if (!res) 00882 astman_send_ack(s, m, "Originate successfully queued"); 00883 else 00884 astman_send_error(s, m, "Originate failed"); 00885 return 0; 00886 } 00887 00888 static int action_mailboxstatus(struct mansession *s, struct message *m) 00889 { 00890 char *mailbox = astman_get_header(m, "Mailbox"); 00891 char *id = astman_get_header(m,"ActionID"); 00892 char idText[256] = ""; 00893 if (!mailbox || ast_strlen_zero(mailbox)) { 00894 astman_send_error(s, m, "Mailbox not specified"); 00895 return 0; 00896 } 00897 if (id && !ast_strlen_zero(id)) 00898 snprintf(idText,256,"ActionID: %s\r\n",id); 00899 ast_cli(s->fd, "Response: Success\r\n" 00900 "%s" 00901 "Message: Mailbox Status\r\n" 00902 "Mailbox: %s\r\n" 00903 "Waiting: %d\r\n\r\n", idText, mailbox, ast_app_has_voicemail(mailbox)); 00904 return 0; 00905 } 00906 00907 static int action_mailboxcount(struct mansession *s, struct message *m) 00908 { 00909 char *mailbox = astman_get_header(m, "Mailbox"); 00910 char *id = astman_get_header(m,"ActionID"); 00911 char idText[256] = ""; 00912 int newmsgs = 0, oldmsgs = 0; 00913 if (!mailbox || ast_strlen_zero(mailbox)) { 00914 astman_send_error(s, m, "Mailbox not specified"); 00915 return 0; 00916 } 00917 ast_app_messagecount(mailbox, &newmsgs, &oldmsgs); 00918 if (id && !ast_strlen_zero(id)) { 00919 snprintf(idText,256,"ActionID: %s\r\n",id); 00920 } 00921 ast_cli(s->fd, "Response: Success\r\n" 00922 "%s" 00923 "Message: Mailbox Message Count\r\n" 00924 "Mailbox: %s\r\n" 00925 "NewMessages: %d\r\n" 00926 "OldMessages: %d\r\n" 00927 "\r\n", 00928 idText,mailbox, newmsgs, oldmsgs); 00929 return 0; 00930 } 00931 00932 static int action_extensionstate(struct mansession *s, struct message *m) 00933 { 00934 char *exten = astman_get_header(m, "Exten"); 00935 char *context = astman_get_header(m, "Context"); 00936 char *id = astman_get_header(m,"ActionID"); 00937 char idText[256] = ""; 00938 char hint[256] = ""; 00939 int status; 00940 if (!exten || ast_strlen_zero(exten)) { 00941 astman_send_error(s, m, "Extension not specified"); 00942 return 0; 00943 } 00944 if (!context || ast_strlen_zero(context)) 00945 context = "default"; 00946 status = ast_extension_state(NULL, context, exten); 00947 ast_get_hint(hint, sizeof(hint) - 1, NULL, context, exten); 00948 if (id && !ast_strlen_zero(id)) { 00949 snprintf(idText,256,"ActionID: %s\r\n",id); 00950 } 00951 ast_cli(s->fd, "Response: Success\r\n" 00952 "%s" 00953 "Message: Extension Status\r\n" 00954 "Exten: %s\r\n" 00955 "Context: %s\r\n" 00956 "Hint: %s\r\n" 00957 "Status: %d\r\n\r\n", 00958 idText,exten, context, hint, status); 00959 return 0; 00960 } 00961 00962 static int action_timeout(struct mansession *s, struct message *m) 00963 { 00964 struct ast_channel *c = NULL; 00965 char *name = astman_get_header(m, "Channel"); 00966 int timeout = atoi(astman_get_header(m, "Timeout")); 00967 if (ast_strlen_zero(name)) { 00968 astman_send_error(s, m, "No channel specified"); 00969 return 0; 00970 } 00971 if (!timeout) { 00972 astman_send_error(s, m, "No timeout specified"); 00973 return 0; 00974 } 00975 c = ast_channel_walk_locked(NULL); 00976 while(c) { 00977 if (!strcasecmp(c->name, name)) { 00978 break; 00979 } 00980 ast_mutex_unlock(&c->lock); 00981 c = ast_channel_walk_locked(c); 00982 } 00983 if (!c) { 00984 astman_send_error(s, m, "No such channel"); 00985 return 0; 00986 } 00987 ast_channel_setwhentohangup(c, timeout); 00988 ast_mutex_unlock(&c->lock); 00989 astman_send_ack(s, m, "Timeout Set"); 00990 return 0; 00991 } 00992 00993 static int process_message(struct mansession *s, struct message *m) 00994 { 00995 char action[80] = ""; 00996 struct manager_action *tmp = first_action; 00997 char *id = astman_get_header(m,"ActionID"); 00998 char idText[256] = ""; 00999 char iabuf[INET_ADDRSTRLEN]; 01000 01001 strncpy(action, astman_get_header(m, "Action"), sizeof(action) - 1); 01002 ast_log( LOG_DEBUG, "Manager received command '%s'\n", action ); 01003 01004 if (ast_strlen_zero(action)) { 01005 astman_send_error(s, m, "Missing action in request"); 01006 return 0; 01007 } 01008 if (id && !ast_strlen_zero(id)) { 01009 snprintf(idText,256,"ActionID: %s\r\n",id); 01010 } 01011 if (!s->authenticated) { 01012 if (!strcasecmp(action, "Challenge")) { 01013 char *authtype; 01014 authtype = astman_get_header(m, "AuthType"); 01015 if (!strcasecmp(authtype, "MD5")) { 01016 if (!s->challenge || ast_strlen_zero(s->challenge)) { 01017 ast_mutex_lock(&s->lock); 01018 snprintf(s->challenge, sizeof(s->challenge), "%d", rand()); 01019 ast_mutex_unlock(&s->lock); 01020 } 01021 ast_cli(s->fd, "Response: Success\r\n" 01022 "%s" 01023 "Challenge: %s\r\n\r\n", 01024 idText,s->challenge); 01025 return 0; 01026 } else { 01027 astman_send_error(s, m, "Must specify AuthType"); 01028 return 0; 01029 } 01030 } else if (!strcasecmp(action, "Login")) { 01031 if (authenticate(s, m)) { 01032 sleep(1); 01033 astman_send_error(s, m, "Authentication failed"); 01034 return -1; 01035 } else { 01036 s->authenticated = 1; 01037 if (option_verbose > 1) 01038 ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged on from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr)); 01039 ast_log(LOG_EVENT, "Manager '%s' logged on from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr)); 01040 astman_send_ack(s, m, "Authentication accepted"); 01041 } 01042 } else if (!strcasecmp(action, "Logoff")) { 01043 astman_send_ack(s, m, "See ya"); 01044 return -1; 01045 } else 01046 astman_send_error(s, m, "Authentication Required"); 01047 } else { 01048 while( tmp ) { 01049 if (!strcasecmp(action, tmp->action)) { 01050 if ((s->writeperm & tmp->authority) == tmp->authority) { 01051 if (tmp->func(s, m)) 01052 return -1; 01053 } else { 01054 astman_send_error(s, m, "Permission denied"); 01055 } 01056 return 0; 01057 } 01058 tmp = tmp->next; 01059 } 01060 astman_send_error(s, m, "Invalid/unknown command"); 01061 } 01062 return 0; 01063 } 01064 01065 static int get_input(struct mansession *s, char *output) 01066 { 01067 /* output must have at least sizeof(s->inbuf) space */ 01068 int res; 01069 int x; 01070 struct pollfd fds[1]; 01071 char iabuf[INET_ADDRSTRLEN]; 01072 for (x=1;x<s->inlen;x++) { 01073 if ((s->inbuf[x] == '\n') && (s->inbuf[x-1] == '\r')) { 01074 /* Copy output data up to and including \r\n */ 01075 memcpy(output, s->inbuf, x + 1); 01076 /* Add trailing \0 */ 01077 output[x+1] = '\0'; 01078 /* Move remaining data back to the front */ 01079 memmove(s->inbuf, s->inbuf + x + 1, s->inlen - x); 01080 s->inlen -= (x + 1); 01081 return 1; 01082 } 01083 } 01084 if (s->inlen >= sizeof(s->inbuf) - 1) { 01085 ast_log(LOG_WARNING, "Dumping long line with no return from %s: %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr), s->inbuf); 01086 s->inlen = 0; 01087 } 01088 fds[0].fd = s->fd; 01089 fds[0].events = POLLIN; 01090 res = poll(fds, 1, -1); 01091 if (res < 0) { 01092 ast_log(LOG_WARNING, "Select returned error: %s\n", strerror(errno)); 01093 } else if (res > 0) { 01094 ast_mutex_lock(&s->lock); 01095 res = read(s->fd, s->inbuf + s->inlen, sizeof(s->inbuf) - 1 - s->inlen); 01096 ast_mutex_unlock(&s->lock); 01097 if (res < 1) 01098 return -1; 01099 } 01100 s->inlen += res; 01101 s->inbuf[s->inlen] = '\0'; 01102 return 0; 01103 } 01104 01105 static void *session_do(void *data) 01106 { 01107 struct mansession *s = data; 01108 struct message m; 01109 char iabuf[INET_ADDRSTRLEN]; 01110 int res; 01111 01112 ast_mutex_lock(&s->lock); 01113 ast_cli(s->fd, "Asterisk Call Manager/1.0\r\n"); 01114 ast_mutex_unlock(&s->lock); 01115 memset(&m, 0, sizeof(&m)); 01116 for (;;) { 01117 res = get_input(s, m.headers[m.hdrcount]); 01118 if (res > 0) { 01119 /* Strip trailing \r\n */ 01120 if (strlen(m.headers[m.hdrcount]) < 2) 01121 continue; 01122 m.headers[m.hdrcount][strlen(m.headers[m.hdrcount]) - 2] = '\0'; 01123 if (ast_strlen_zero(m.headers[m.hdrcount])) { 01124 if (process_message(s, &m)) 01125 break; 01126 memset(&m, 0, sizeof(&m)); 01127 } else if (m.hdrcount < MAX_HEADERS - 1) 01128 m.hdrcount++; 01129 } else if (res < 0) 01130 break; 01131 } 01132 if (s->authenticated) { 01133 if (option_verbose > 1) 01134 ast_verbose(VERBOSE_PREFIX_2 "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr)); 01135 ast_log(LOG_EVENT, "Manager '%s' logged off from %s\n", s->username, ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr)); 01136 } else { 01137 if (option_verbose > 1) 01138 ast_verbose(VERBOSE_PREFIX_2 "Connect attempt from '%s' unable to authenticate\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr)); 01139 ast_log(LOG_EVENT, "Failed attempt from %s\n", ast_inet_ntoa(iabuf, sizeof(iabuf), s->sin.sin_addr)); 01140 } 01141 destroy_session(s); 01142 return NULL; 01143 } 01144 01145 static void *accept_thread(void *ignore) 01146 { 01147 int as; 01148 struct sockaddr_in sin; 01149 int sinlen; 01150 struct mansession *s; 01151 struct protoent *p; 01152 int arg = 1; 01153 int flags; 01154 pthread_attr_t attr; 01155 01156 pthread_attr_init(&attr); 01157 pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); 01158 01159 for (;;) { 01160 sinlen = sizeof(sin); 01161 as = accept(asock, (struct sockaddr *)&sin, &sinlen); 01162 if (as < 0) { 01163 ast_log(LOG_NOTICE, "Accept returned -1: %s\n", strerror(errno)); 01164 continue; 01165 } 01166 p = getprotobyname("tcp"); 01167 if( p ) { 01168 if( setsockopt(as, p->p_proto, TCP_NODELAY, (char *)&arg, sizeof(arg) ) < 0 ) { 01169 ast_log(LOG_WARNING, "Failed to set manager tcp connection to TCP_NODELAY mode: %s\n", strerror(errno)); 01170 } 01171 } 01172 s = malloc(sizeof(struct mansession)); 01173 if (!s) { 01174 ast_log(LOG_WARNING, "Failed to allocate management session: %s\n", strerror(errno)); 01175 continue; 01176 } 01177 memset(s, 0, sizeof(struct mansession)); 01178 memcpy(&s->sin, &sin, sizeof(sin)); 01179 01180 if(! block_sockets) { 01181 /* For safety, make sure socket is non-blocking */ 01182 flags = fcntl(as, F_GETFL); 01183 fcntl(as, F_SETFL, flags | O_NONBLOCK); 01184 } 01185 ast_mutex_init(&s->lock); 01186 s->fd = as; 01187 s->send_events = -1; 01188 ast_mutex_lock(&sessionlock); 01189 s->next = sessions; 01190 sessions = s; 01191 ast_mutex_unlock(&sessionlock); 01192 if (pthread_create(&t, &attr, session_do, s)) 01193 destroy_session(s); 01194 } 01195 pthread_attr_destroy(&attr); 01196 return NULL; 01197 } 01198 01199 int manager_event(int category, char *event, char *fmt, ...) 01200 { 01201 struct mansession *s; 01202 char tmp[4096]; 01203 va_list ap; 01204 01205 ast_mutex_lock(&sessionlock); 01206 s = sessions; 01207 while(s) { 01208 if (((s->readperm & category) == category) && ((s->send_events & category) == category) ) { 01209 ast_mutex_lock(&s->lock); 01210 if (!s->blocking) { 01211 ast_cli(s->fd, "Event: %s\r\n", event); 01212 va_start(ap, fmt); 01213 vsnprintf(tmp, sizeof(tmp), fmt, ap); 01214 va_end(ap); 01215 ast_carefulwrite(s->fd,tmp,strlen(tmp),100); 01216 ast_cli(s->fd, "\r\n"); 01217 } 01218 ast_mutex_unlock(&s->lock); 01219 } 01220 s = s->next; 01221 } 01222 ast_mutex_unlock(&sessionlock); 01223 return 0; 01224 } 01225 01226 int ast_manager_unregister( char *action ) { 01227 struct manager_action *cur = first_action, *prev = first_action; 01228 01229 ast_mutex_lock(&actionlock); 01230 while( cur ) { 01231 if (!strcasecmp(action, cur->action)) { 01232 prev->next = cur->next; 01233 free(cur); 01234 if (option_verbose > 1) 01235 ast_verbose(VERBOSE_PREFIX_2 "Manager unregistered action %s\n", action); 01236 ast_mutex_unlock(&actionlock); 01237 return 0; 01238 } 01239 prev = cur; 01240 cur = cur->next; 01241 } 01242 ast_mutex_unlock(&actionlock); 01243 return 0; 01244 } 01245 01246 static int manager_state_cb(char *context, char *exten, int state, void *data) 01247 { 01248 /* Notify managers of change */ 01249 manager_event(EVENT_FLAG_CALL, "ExtensionStatus", "Exten: %s\r\nContext: %s\r\nStatus: %d\r\n", exten, context, state); 01250 return 0; 01251 } 01252 01253 static int ast_manager_register_struct(struct manager_action *act) 01254 { 01255 struct manager_action *cur = first_action, *prev = NULL; 01256 int ret; 01257 01258 ast_mutex_lock(&actionlock); 01259 while(cur) { /* Walk the list of actions */ 01260 ret = strcasecmp(cur->action, act->action); 01261 if (ret == 0) { 01262 ast_log(LOG_WARNING, "Manager: Action '%s' already registered\n", act->action); 01263 ast_mutex_unlock(&actionlock); 01264 return -1; 01265 } else if (ret > 0) { 01266 /* Insert these alphabetically */ 01267 if (prev) { 01268 act->next = prev->next; 01269 prev->next = act; 01270 } else { 01271 act->next = first_action; 01272 first_action = act; 01273 } 01274 break; 01275 } 01276 prev = cur; 01277 cur = cur->next; 01278 } 01279 01280 if (!cur) { 01281 if (prev) 01282 prev->next = act; 01283 else 01284 first_action = act; 01285 act->next = NULL; 01286 } 01287 01288 if (option_verbose > 1) 01289 ast_verbose(VERBOSE_PREFIX_2 "Manager registered action %s\n", act->action); 01290 ast_mutex_unlock(&actionlock); 01291 return 0; 01292 } 01293 01294 int ast_manager_register2(char *action, int auth, int (*func)(struct mansession *s, struct message *m), char *synopsis, char *description) 01295 { 01296 struct manager_action *cur; 01297 01298 cur = malloc(sizeof(struct manager_action)); 01299 if (!cur) { 01300 ast_log(LOG_WARNING, "Manager: out of memory trying to register action\n"); 01301 ast_mutex_unlock(&actionlock); 01302 return -1; 01303 } 01304 cur->action = action; 01305 cur->authority = auth; 01306 cur->func = func; 01307 cur->synopsis = synopsis; 01308 cur->description = description; 01309 cur->next = NULL; 01310 01311 ast_manager_register_struct(cur); 01312 01313 return 0; 01314 } 01315 01316 static int registered = 0; 01317 01318 int init_manager(void) 01319 { 01320 struct ast_config *cfg; 01321 char *val; 01322 int oldportno = portno; 01323 static struct sockaddr_in ba; 01324 int x = 1; 01325 if (!registered) { 01326 /* Register default actions */ 01327 ast_manager_register2("Ping", 0, action_ping, "Ping", mandescr_ping); 01328 ast_manager_register2("Events", 0, action_events, "Contol Event Flow", mandescr_events); 01329 ast_manager_register2("Logoff", 0, action_logoff, "Logoff Manager", mandescr_logoff); 01330 ast_manager_register2("Hangup", EVENT_FLAG_CALL, action_hangup, "Hangup Channel", mandescr_hangup); 01331 ast_manager_register( "Status", EVENT_FLAG_CALL, action_status, "Status" ); 01332 ast_manager_register( "Setvar", EVENT_FLAG_CALL, action_setvar, "Set Channel Variable" ); 01333 ast_manager_register( "Getvar", EVENT_FLAG_CALL, action_getvar, "Gets a Channel Variable" ); 01334 ast_manager_register( "Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect" ); 01335 ast_manager_register2("Originate", EVENT_FLAG_CALL, action_originate, "Originate Call", mandescr_originate); 01336 ast_manager_register( "MailboxStatus", EVENT_FLAG_CALL, action_mailboxstatus, "Check Mailbox" ); 01337 ast_manager_register( "Command", EVENT_FLAG_COMMAND, action_command, "Execute Command" ); 01338 ast_manager_register( "ExtensionState", EVENT_FLAG_CALL, action_extensionstate, "Check Extension Status" ); 01339 ast_manager_register( "AbsoluteTimeout", EVENT_FLAG_CALL, action_timeout, "Set Absolute Timeout" ); 01340 ast_manager_register( "MailboxCount", EVENT_FLAG_CALL, action_mailboxcount, "Check Mailbox Message Count" ); 01341 ast_manager_register2("ListCommands", 0, action_listcommands, "List available manager commands", mandescr_listcommands); 01342 01343 ast_cli_register(&show_mancmd_cli); 01344 ast_cli_register(&show_mancmds_cli); 01345 ast_cli_register(&show_manconn_cli); 01346 ast_extension_state_add(NULL, NULL, manager_state_cb, NULL); 01347 registered = 1; 01348 } 01349 portno = DEFAULT_MANAGER_PORT; 01350 cfg = ast_load("manager.conf"); 01351 if (!cfg) { 01352 ast_log(LOG_NOTICE, "Unable to open management configuration manager.conf. Call management disabled.\n"); 01353 return 0; 01354 } 01355 memset(&ba, 0, sizeof(ba)); 01356 val = ast_variable_retrieve(cfg, "general", "enabled"); 01357 if (val) 01358 enabled = ast_true(val); 01359 01360 val = ast_variable_retrieve(cfg, "general", "block-sockets"); 01361 if(val) 01362 block_sockets = ast_true(val); 01363 01364 if ((val = ast_variable_retrieve(cfg, "general", "port"))) { 01365 if (sscanf(val, "%d", &portno) != 1) { 01366 ast_log(LOG_WARNING, "Invalid port number '%s'\n", val); 01367 portno = DEFAULT_MANAGER_PORT; 01368 } 01369 } else if ((val = ast_variable_retrieve(cfg, "general", "portno"))) { 01370 if (sscanf(val, "%d", &portno) != 1) { 01371 ast_log(LOG_WARNING, "Invalid port number '%s'\n", val); 01372 portno = DEFAULT_MANAGER_PORT; 01373 } 01374 ast_log(LOG_NOTICE, "Use of portno in manager.conf deprecated. Please use 'port=%s' instead.\n", val); 01375 } 01376 01377 ba.sin_family = AF_INET; 01378 ba.sin_port = htons(portno); 01379 memset(&ba.sin_addr, 0, sizeof(ba.sin_addr)); 01380 01381 if ((val = ast_variable_retrieve(cfg, "general", "bindaddr"))) { 01382 if (!inet_aton(val, &ba.sin_addr)) { 01383 ast_log(LOG_WARNING, "Invalid address '%s' specified, using 0.0.0.0\n", val); 01384 memset(&ba.sin_addr, 0, sizeof(ba.sin_addr)); 01385 } 01386 } 01387 01388 if ((asock > -1) && ((portno != oldportno) || !enabled)) { 01389 #if 0 01390 /* Can't be done yet */ 01391 close(asock); 01392 asock = -1; 01393 #else 01394 ast_log(LOG_WARNING, "Unable to change management port / enabled\n"); 01395 #endif 01396 } 01397 ast_destroy(cfg); 01398 01399 /* If not enabled, do nothing */ 01400 if (!enabled) { 01401 return 0; 01402 } 01403 if (asock < 0) { 01404 asock = socket(AF_INET, SOCK_STREAM, 0); 01405 if (asock < 0) { 01406 ast_log(LOG_WARNING, "Unable to create socket: %s\n", strerror(errno)); 01407 return -1; 01408 } 01409 setsockopt(asock, SOL_SOCKET, SO_REUSEADDR, &x, sizeof(x)); 01410 if (bind(asock, (struct sockaddr *)&ba, sizeof(ba))) { 01411 ast_log(LOG_WARNING, "Unable to bind socket: %s\n", strerror(errno)); 01412 close(asock); 01413 asock = -1; 01414 return -1; 01415 } 01416 if (listen(asock, 2)) { 01417 ast_log(LOG_WARNING, "Unable to listen on socket: %s\n", strerror(errno)); 01418 close(asock); 01419 asock = -1; 01420 return -1; 01421 } 01422 if (option_verbose) 01423 ast_verbose("Asterisk Management interface listening on port %d\n", portno); 01424 pthread_create(&t, NULL, accept_thread, NULL); 01425 } 01426 return 0; 01427 } 01428 01429 int reload_manager(void) 01430 { 01431 manager_event(EVENT_FLAG_SYSTEM, "Reload", "Message: Reload Requested\r\n"); 01432 return init_manager(); 01433 }

Generated on Tue Aug 17 16:13:53 2004 for Asterisk by doxygen 1.3.8