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

manager.c

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

Generated on Thu Nov 29 22:50:23 2007 for Asterisk by  doxygen 1.4.2