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

Generated on Fri Sep 24 21:03:47 2004 for Asterisk by doxygen 1.3.8