00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
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
00086
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
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) {
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) {
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) {
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
00293
00294
00295
00296
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
00373
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
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) {
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
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
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
01138 memcpy(output,
s->inbuf, x + 1);
01139
01140 output[x+1] =
'\0';
01141
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
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
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
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) {
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
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
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
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
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 }