Index: pbx.c =================================================================== RCS file: /usr/cvsroot/asterisk/pbx.c,v retrieving revision 1.220 diff -u -r1.220 pbx.c --- pbx.c 1 Apr 2005 19:56:35 -0000 1.220 +++ pbx.c 3 Apr 2005 19:52:32 -0000 @@ -3209,6 +3209,7 @@ int total_context; int total_exten; int total_prio; + int total_items; int context_existence; int extension_existence; }; @@ -3445,6 +3446,254 @@ return RESULT_SUCCESS; } +/*--- manager_dpsendack: Send ack once */ +static void manager_dpsendack(struct mansession *s, struct message *m, int *sentack) +{ + if (*sentack) + return; + astman_send_listack(s, m, "DialPlan list will follow", "start"); + *sentack = 1; + return; +} + +/*--- manager_show_dialplan_helper: Show dialplan extensions */ +static int manager_show_dialplan_helper(struct mansession *s, struct message *m, char *actionidtext, char *context, char *exten, struct dialplan_counters *dpc, struct ast_include *rinclude) +{ + struct ast_context *c; + int res=0, old_total_exten = dpc->total_exten; + int sentpositivemanagerack = 0; + + if (ast_strlen_zero(exten)) + exten = NULL; + if (ast_strlen_zero(context)) + context = NULL; + + if (option_debug > 2) + ast_log(LOG_DEBUG, "manager_show_dialplan: Context: -%s- Extension: -%s-\n", context, exten); + + /* try to lock contexts */ + if (ast_lock_contexts()) { + astman_send_error(s, m, "Failed to lock contexts\r\n"); + ast_log(LOG_WARNING, "Failed to lock contexts list for manager: listdialplan\n"); + return -1; + } + + /* walk all contexts ... */ + for (c = ast_walk_contexts(NULL); c ; c = ast_walk_contexts(c)) { + /* show this context? */ + if (!context || + !strcmp(ast_get_context_name(c), context)) { + dpc->context_existence = 1; + + if (option_debug > 2) + ast_log(LOG_DEBUG, "manager_show_dialplan: Found Context: %s \n", ast_get_context_name(c)); + + /* try to lock context before walking in ... */ + if (!ast_lock_context(c)) { + struct ast_exten *e; + struct ast_include *i; + struct ast_ignorepat *ip; + struct ast_sw *sw; + char buf[256], buf2[256]; + + /* walk extensions in context */ + for (e = ast_walk_context_extensions(c, NULL); e; e = ast_walk_context_extensions(c, e)) { + struct ast_exten *p; + int prio; + + /* looking for extension? is this our extension? */ + if (exten && + !ast_extension_match(ast_get_extension_name(e), exten)) + { + if (option_debug > 2) + ast_log(LOG_DEBUG, "manager_show_dialplan: Skipping extension %s\n", ast_get_extension_name(e)); + /* we are looking for extension and it's not our + * extension, so skip to next extension */ + continue; + } + if (option_debug > 2) + ast_log(LOG_DEBUG, "manager_show_dialplan: Found Extension: %s \n", ast_get_extension_name(e)); + + dpc->extension_existence = 1; + + /* may we print context info? */ + dpc->total_context++; + dpc->total_prio++; + + /* write extension name and first peer */ + bzero(buf, sizeof(buf)); + + dpc->total_items++; + manager_dpsendack(s, m, &sentpositivemanagerack); + ast_mutex_lock(&s->lock); + ast_cli(s->fd, "Event: ListDialplan\r\n%s", actionidtext); + ast_cli(s->fd, "Context: %s\r\nExtension: %s\r\n", ast_get_context_name(c), ast_get_extension_name(e) ); + + prio = ast_get_extension_priority(e); + if (prio == PRIORITY_HINT) { + ast_cli(s->fd, "Priority: hint\r\nApplication: %s\r\n", ast_get_extension_app(e)); + } else { + ast_cli(s->fd, "Priority: %d\r\nApplication: %s\r\nAppData: %s\r\n", prio, ast_get_extension_app(e), (char *) ast_get_extension_app_data(e)); + } + ast_cli(s->fd, "Registrar: %s\r\n\r\n", ast_get_extension_registrar(e)); + ast_mutex_unlock(&s->lock); + + dpc->total_exten++; + + /* walk next extension peers */ + for (p=ast_walk_extension_priorities(e, e); p; p=ast_walk_extension_priorities(e, p)) { + dpc->total_prio++; + bzero((void *)buf2, sizeof(buf2)); + bzero((void *)buf, sizeof(buf)); + dpc->total_items++; + manager_dpsendack(s, m, &sentpositivemanagerack); + ast_mutex_lock(&s->lock); + ast_cli(s->fd, "Event: ListDialplan\r\n%s", actionidtext); + ast_cli(s->fd, "Context: %s\r\nExtension: %s\r\n", ast_get_context_name(c), ast_get_extension_name(e) ); + + if (ast_get_extension_label(p)) + ast_cli(s->fd, "ExtensionLabel: %s\r\n", ast_get_extension_label(p)); + prio = ast_get_extension_priority(p); + if (prio == PRIORITY_HINT) { + ast_cli(s->fd, "Priority: hint\r\nApplication: %s\r\n", ast_get_extension_app(p)); + } else { + ast_cli(s->fd, "Priority: %d\r\nApplication: %s\r\nAppData: %s\r\n", prio, ast_get_extension_app(p), (char *) ast_get_extension_app_data(p)); + } + ast_cli(s->fd, "Registrar: %s\r\n\r\n", ast_get_extension_registrar(e)); + ast_mutex_unlock(&s->lock); + } + } + + /* walk included and write info ... */ + for (i = ast_walk_context_includes(c, NULL); i; i = ast_walk_context_includes(c, i)) { + if (exten) { + /* Check all includes for the requested extension */ + manager_show_dialplan_helper(s, m, actionidtext, (char *)ast_get_include_name(i), exten, dpc, i); + } else { + dpc->total_items++; + manager_dpsendack(s, m, &sentpositivemanagerack); + ast_mutex_lock(&s->lock); + ast_cli(s->fd, "Event: ListDialplan\r\n%s", actionidtext); + ast_cli(s->fd, "Context: %s\r\nIncludeContext: %s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ast_get_include_name(i), ast_get_include_registrar(i)); + ast_cli(s->fd, "\r\n"); + ast_mutex_unlock(&s->lock); + if (option_debug > 2) + ast_log(LOG_DEBUG, "manager_show_dialplan: Found Included context: %s \n", buf); + } + } + + /* walk ignore patterns and write info ... */ + for (ip=ast_walk_context_ignorepats(c, NULL); ip; ip=ast_walk_context_ignorepats(c, ip)) { + const char *ipname = ast_get_ignorepat_name(ip); + char ignorepat[AST_MAX_EXTENSION]; + snprintf(ignorepat, sizeof(ignorepat), "_%s.", ipname); + if ((!exten) || ast_extension_match(ignorepat, exten)) { + dpc->total_items++; + manager_dpsendack(s, m, &sentpositivemanagerack); + ast_mutex_lock(&s->lock); + ast_cli(s->fd, "Event: ListDialplan\r\n%s", actionidtext); + ast_cli(s->fd, "Context: %s\r\nIgnorePattern: %s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ipname, ast_get_ignorepat_registrar(ip)); + ast_cli(s->fd, "\r\n"); + ast_mutex_unlock(&s->lock); + } + } + if (!rinclude) { + for (sw = ast_walk_context_switches(c, NULL); sw; sw = ast_walk_context_switches(c, sw)) { + dpc->total_items++; + manager_dpsendack(s, m, &sentpositivemanagerack); + ast_mutex_lock(&s->lock); + ast_cli(s->fd, "Event: ListDialplan\r\n%s", actionidtext); + ast_cli(s->fd, "Context: %s\r\nSwitch: %s/%s\r\nRegistrar: %s\r\n", ast_get_context_name(c), ast_get_switch_name(sw), ast_get_switch_data(sw), ast_get_switch_registrar(sw)); + ast_cli(s->fd, "\r\n"); + ast_mutex_unlock(&s->lock); + if (option_debug > 2) + ast_log(LOG_DEBUG, "manager_show_dialplan: Found Switch : %s \n", buf); + } + } + + ast_unlock_context(c); + + } else if (option_debug > 2) { + ast_log(LOG_DEBUG, "manager_show_dialplan: Failed to lock context\n"); + } + } + } + ast_unlock_contexts(); + + if (dpc->total_exten == old_total_exten) { + if (option_debug > 2) + ast_log(LOG_DEBUG, "manager_show_dialplan: Found nothing new\n"); + /* Nothing new under the sun */ + return -1; + } else { + return res; + } +} + +/* manager_show_dialplan: Manager listing of dial plan */ +static int manager_show_dialplan(struct mansession *s, struct message *m) +{ + char *exten = NULL, *context = NULL; + char *id = astman_get_header(m, "ActionID"); + char idtext[256]; + int res; + + /* Variables used for different counters */ + struct dialplan_counters counters; + + if (id && !ast_strlen_zero(id)) + snprintf(idtext, sizeof(idtext), "ActionID: %s\r\n", id); + + + memset(&counters, 0, sizeof(counters)); + + exten = astman_get_header(m, "Extension"); + context = astman_get_header(m, "Context"); + + res = manager_show_dialplan_helper(s, m, idtext, context, exten, &counters, NULL); + + if (context && !counters.context_existence) { + char errorbuf[BUFSIZ]; + + snprintf(errorbuf, sizeof(errorbuf), "Did not find context %s\r\n", context); + astman_send_error(s, m, errorbuf); + return 0; + } + if (exten && !counters.extension_existence) { + char errorbuf[BUFSIZ]; + + if (context) + snprintf(errorbuf, sizeof(errorbuf), "Did not find extension %s@%s\r\n", exten, context); + else + snprintf(errorbuf, sizeof(errorbuf), "Did not find extension %s in any context\r\n", exten); + astman_send_error(s, m, errorbuf); + return 0; + } + + ast_mutex_lock(&s->lock); + ast_cli(s->fd, "Event: ShowDialPlanComplete\r\n" + "EventList: Complete\r\n" + "ListItems: %d\r\n" + "ListExtensions: %d\r\n" + "ListPrios: %d\r\n" + "ListContexts: %d\r\n" + "%s" + "\r\n", counters.total_items, counters.total_exten, counters.total_prio, counters.total_context, idtext); + ast_mutex_unlock(&s->lock); + + /* everything ok */ + return 0; +} + +static char mandescr_show_dialplan[] = +"Description: Show dialplan contexts and extensions.\n" +"Variables: \n" +" ActionID: Action ID for this AMI transaction (optional)\n" +" Extension: Extension (Optional)\n" +" Context: Context (Optional)\n" +"\n"; + + /* custom commands */ @@ -5892,6 +6141,7 @@ ast_custom_function_register(&env_function); ast_custom_function_register(&len_function); ast_custom_function_register(&cdr_function); + ast_manager_register2("ListDialPlan", EVENT_FLAG_SYSTEM, manager_show_dialplan, "List dialplan entries", mandescr_show_dialplan); /* Register builtin applications */ for (x=0; xaction, authority_to_str(cur->authority, authority, sizeof(authority) -1), cur->synopsis); cur = cur->next; @@ -278,7 +280,7 @@ ast_mutex_unlock(&s->lock); } -void astman_send_response(struct mansession *s, struct message *m, char *resp, char *msg) +void astman_send_response_full(struct mansession *s, struct message *m, char *resp, char *msg, char *listflag) { char *id = astman_get_header(m,"ActionID"); ast_mutex_lock(&s->lock); @@ -286,15 +288,26 @@ if (id && !ast_strlen_zero(id)) ast_cli(s->fd, "ActionID: %s\r\n",id); if (msg) - ast_cli(s->fd, "Message: %s\r\n\r\n", msg); - else - ast_cli(s->fd, "\r\n"); + ast_cli(s->fd, "Message: %s\r\n", msg); + if (listflag) + ast_cli(s->fd, "EventList: %s", listflag); /* start, complete, canceled */ + ast_cli(s->fd, "\r\n"); ast_mutex_unlock(&s->lock); } +void astman_send_response(struct mansession *s, struct message *m, char *resp, char *msg) +{ + astman_send_response_full(s, m, resp, msg, NULL); +} + void astman_send_ack(struct mansession *s, struct message *m, char *msg) { - astman_send_response(s, m, "Success", msg); + astman_send_response_full(s, m, "Success", msg, NULL); +} + +void astman_send_listack(struct mansession *s, struct message *m, char *msg, char *listflag) +{ + astman_send_response_full(s, m, "Success", msg, listflag); } /* Tells you if smallstr exists inside bigstr @@ -484,7 +497,7 @@ static int action_ping(struct mansession *s, struct message *m) { - astman_send_response(s, m, "Pong", NULL); + astman_send_response_full(s, m, "Pong", NULL, NULL); return 0; } @@ -497,6 +510,7 @@ { struct manager_action *cur = first_action; char idText[256] = ""; + char temp[BUFSIZ]; char *id = astman_get_header(m,"ActionID"); if (id && !ast_strlen_zero(id)) @@ -506,7 +520,7 @@ ast_mutex_lock(&actionlock); while (cur) { /* Walk the list of actions */ if ((s->writeperm & cur->authority) == cur->authority) - ast_cli(s->fd, "%s: %s\r\n", cur->action, cur->synopsis); + ast_cli(s->fd, "%s|%s|%s\r\n", cur->action, authority_to_str(cur->authority, temp, sizeof(temp)), cur->synopsis); cur = cur->next; } ast_mutex_unlock(&actionlock); @@ -531,7 +545,7 @@ res = set_eventmask(s, mask); if (res > 0) - astman_send_response(s, m, "Events On", NULL); + astman_send_response_full(s, m, "Events On", NULL, NULL); else if (res == 0) astman_send_response(s, m, "Events Off", NULL); @@ -678,6 +692,7 @@ } +/*--- action_status: the STATUS command */ static int action_status(struct mansession *s, struct message *m) { char *id = astman_get_header(m,"ActionID"); @@ -687,9 +702,10 @@ char bridge[256]; struct timeval now; long elapsed_seconds=0; + int count = 0; gettimeofday(&now, NULL); - astman_send_ack(s, m, "Channel status will follow"); + astman_send_listack(s, m, "Channel status will follow", "start"); c = ast_channel_walk_locked(NULL); if (id && !ast_strlen_zero(id)) snprintf(idText,256,"ActionID: %s\r\n",id); @@ -713,6 +729,7 @@ bridge[0] = '\0'; ast_mutex_lock(&s->lock); if (c->pbx) { + count++; if (c->cdr) { elapsed_seconds = now.tv_sec - c->cdr->start.tv_sec; } @@ -765,8 +782,10 @@ ast_mutex_lock(&s->lock); ast_cli(s->fd, "Event: StatusComplete\r\n" + "EventList: Complete\r\n" + "ListItems: %d\r\n" "%s" - "\r\n",idText); + "\r\n", count, idText); ast_mutex_unlock(&s->lock); return 0; } @@ -892,7 +911,7 @@ "Description: Generates an outgoing call to a Extension/Context/Priority or\n" " Application/Data\n" "Variables: (Names marked with * are required)\n" -" *Channel: Channel name to call\n" +" *Channel: Dial string to call\n" " Exten: Extension to use (requires 'Context' and 'Priority')\n" " Context: Context to use (requires 'Exten' and 'Priority')\n" " Priority: Priority to use (requires 'Exten' and 'Context')\n" @@ -1375,6 +1394,7 @@ return NULL; } +/*--- manager_event: Send AMI event to client */ int manager_event(int category, char *event, char *fmt, ...) { struct mansession *s; @@ -1388,6 +1408,7 @@ ast_mutex_lock(&s->lock); if (!s->blocking) { ast_cli(s->fd, "Event: %s\r\n", event); + ast_cli(s->fd, "Privilege: %s\r\n", authority_to_str(category, tmp, sizeof(tmp))); va_start(ap, fmt); vsnprintf(tmp, sizeof(tmp), fmt, ap); va_end(ap); @@ -1503,16 +1524,16 @@ int x = 1; if (!registered) { /* Register default actions */ - ast_manager_register2("Ping", 0, action_ping, "Ping", mandescr_ping); - ast_manager_register2("Events", 0, action_events, "Contol Event Flow", mandescr_events); + ast_manager_register2("Ping", 0, action_ping, "Keepalive command", mandescr_ping); + ast_manager_register2("Events", 0, action_events, "Control Event Flow", mandescr_events); ast_manager_register2("Logoff", 0, action_logoff, "Logoff Manager", mandescr_logoff); ast_manager_register2("Hangup", EVENT_FLAG_CALL, action_hangup, "Hangup Channel", mandescr_hangup); - ast_manager_register( "Status", EVENT_FLAG_CALL, action_status, "Status" ); + ast_manager_register( "Status", EVENT_FLAG_CALL, action_status, "Lists channel status" ); ast_manager_register2( "Setvar", EVENT_FLAG_CALL, action_setvar, "Set Channel Variable", mandescr_setvar ); ast_manager_register2( "Getvar", EVENT_FLAG_CALL, action_getvar, "Gets a Channel Variable", mandescr_getvar ); - ast_manager_register( "Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect" ); + ast_manager_register( "Redirect", EVENT_FLAG_CALL, action_redirect, "Redirect (transfer) a call" ); ast_manager_register2("Originate", EVENT_FLAG_CALL, action_originate, "Originate Call", mandescr_originate); - ast_manager_register2( "Command", EVENT_FLAG_COMMAND, action_command, "Execute Command", mandescr_command ); + ast_manager_register2( "Command", EVENT_FLAG_COMMAND, action_command, "Execute Asterisk CLI Command", mandescr_command ); ast_manager_register2( "ExtensionState", EVENT_FLAG_CALL, action_extensionstate, "Check Extension Status", mandescr_extensionstate ); ast_manager_register2( "AbsoluteTimeout", EVENT_FLAG_CALL, action_timeout, "Set Absolute Timeout", mandescr_timeout ); ast_manager_register2( "MailboxStatus", EVENT_FLAG_CALL, action_mailboxstatus, "Check Mailbox", mandescr_mailboxstatus ); Index: include/asterisk/manager.h =================================================================== RCS file: /usr/cvsroot/asterisk/include/asterisk/manager.h,v retrieving revision 1.13 diff -u -r1.13 manager.h --- include/asterisk/manager.h 22 Mar 2005 19:09:12 -0000 1.13 +++ include/asterisk/manager.h 3 Apr 2005 19:52:32 -0000 @@ -144,7 +144,9 @@ /*! Send error in manager transaction */ extern void astman_send_error(struct mansession *s, struct message *m, char *error); extern void astman_send_response(struct mansession *s, struct message *m, char *resp, char *msg); +extern void astman_send_response_full(struct mansession *s, struct message *m, char *resp, char *msg, char *listflag); extern void astman_send_ack(struct mansession *s, struct message *m, char *msg); +extern void astman_send_listack(struct mansession *s, struct message *m, char *msg, char *listflag); /*! Called by Asterisk initialization */ extern int init_manager(void);