diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c index fa1d62d388..2516e58b4e 100644 --- a/src/mod/applications/mod_commands/mod_commands.c +++ b/src/mod/applications/mod_commands/mod_commands.c @@ -1885,6 +1885,50 @@ static int show_callback(void *pArg, int argc, char **argv, char **columnNames) return 0; } +#define COMPLETE_SYNTAX "add |del [|all]" +SWITCH_STANDARD_API(complete_function) +{ + char *mydata = NULL, *argv[2] = {0}; + int fail = 1, argc; + char sql[1024] = ""; + + if (cmd && (mydata = strdup(cmd))) { + if ((argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) { + switch_core_db_t *db = switch_core_db_handle(); + + if (!strcasecmp(argv[0], "add")) { + switch_snprintf(sql, sizeof(sql), "delete from complete where name = '%s'", argv[1]); + switch_core_db_persistant_execute(db, sql, 1); + switch_snprintf(sql, sizeof(sql), "insert into complete values ('%s')", argv[1]); + switch_core_db_persistant_execute(db, sql, 1); + stream->write_function(stream, "+OK\n"); + fail = 0; + } else if (!strcasecmp(argv[0], "del")) { + char *what = argv[1]; + if (!strcasecmp(what, "*")) { + switch_snprintf(sql, sizeof(sql), "delete from complete"); + } else { + switch_snprintf(sql, sizeof(sql), "delete from complete where name = '%s'", what); + } + switch_core_db_persistant_execute(db, sql, 1); + stream->write_function(stream, "+OK\n"); + fail = 0; + } + + switch_core_db_close(db); + } + } + + switch_safe_free(mydata); + + if (fail) { + stream->write_function(stream, "-USAGE: %s\n", COMPLETE_SYNTAX); + } + + return SWITCH_STATUS_SUCCESS; + +} + #define SHOW_SYNTAX "codec|application|api|dialplan|file|timer|calls|channels" SWITCH_STANDARD_API(show_function) { @@ -1927,15 +1971,15 @@ SWITCH_STANDARD_API(show_function) stream->write_function(stream, "-USAGE: %s\n", SHOW_SYNTAX); return SWITCH_STATUS_SUCCESS; } else if (!strcasecmp(command, "codec") || !strcasecmp(command, "dialplan") || !strcasecmp(command, "file") || !strcasecmp(command, "timer")) { - sprintf(sql, "select type, name from interfaces where type = '%s'", command); + sprintf(sql, "select type, name from interfaces where type = '%s' order by type,name", command); } else if (!strcasecmp(command, "tasks")) { sprintf(sql, "select * from %s", command); } else if (!strcasecmp(command, "application") || !strcasecmp(command, "api")) { - sprintf(sql, "select name, description, syntax from interfaces where type = '%s' and description != ''", command); + sprintf(sql, "select name, description, syntax from interfaces where type = '%s' and description != '' order by type,name", command); } else if (!strcasecmp(command, "calls")) { - sprintf(sql, "select * from calls"); + sprintf(sql, "select * from calls order by created_epoch"); } else if (!strcasecmp(command, "channels")) { - sprintf(sql, "select * from channels"); + sprintf(sql, "select * from channels order by created_epoch"); } else if (!strncasecmp(command, "help", 4)) { char *cmdname = NULL; @@ -1943,9 +1987,9 @@ SWITCH_STANDARD_API(show_function) holder.print_title = 0; if ((cmdname = strchr(command, ' ')) != 0) { *cmdname++ = '\0'; - switch_snprintf(sql, sizeof(sql) - 1, "select name, syntax, description from interfaces where type = 'api' and name = '%s'", cmdname); + switch_snprintf(sql, sizeof(sql) - 1, "select name, syntax, description from interfaces where type = 'api' and name = '%s' order by name", cmdname); } else { - switch_snprintf(sql, sizeof(sql) - 1, "select name, syntax, description from interfaces where type = 'api'"); + switch_snprintf(sql, sizeof(sql) - 1, "select name, syntax, description from interfaces where type = 'api' order by name"); } } else { stream->write_function(stream, "-USAGE: %s\n", SHOW_SYNTAX); @@ -2264,6 +2308,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_commands_load) SWITCH_ADD_API(commands_api_interface, "pause", "Pause", pause_function, PAUSE_SYNTAX); SWITCH_ADD_API(commands_api_interface, "break", "Break", break_function, BREAK_SYNTAX); SWITCH_ADD_API(commands_api_interface, "show", "Show", show_function, SHOW_SYNTAX); + SWITCH_ADD_API(commands_api_interface, "complete", "Complete", complete_function, COMPLETE_SYNTAX); SWITCH_ADD_API(commands_api_interface, "status", "status", status_function, ""); SWITCH_ADD_API(commands_api_interface, "uuid_bridge", "uuid_bridge", uuid_bridge_function, ""); SWITCH_ADD_API(commands_api_interface, "uuid_setvar", "uuid_setvar", uuid_setvar_function, SETVAR_SYNTAX); diff --git a/src/switch_console.c b/src/switch_console.c index 984279b09f..a539040c74 100644 --- a/src/switch_console.c +++ b/src/switch_console.c @@ -346,13 +346,16 @@ static void *SWITCH_THREAD_FUNC console_thread(switch_thread_t *thread, void *ob if (!switch_strlen_zero(line)) { char *cmd = strdup(line); char *p; - + const LineInfo *lf = el_line(el); + char *foo = (char *)lf->buffer; if ((p = strrchr(cmd, '\r')) || (p = strrchr(cmd, '\n'))) { *p = '\0'; } assert(cmd != NULL); history(myhistory, &ev, H_ENTER, line); running = switch_console_process(cmd); + el_deletestr(el, strlen(foo)+1); + memset(foo, 0, strlen(foo)); free(cmd); } } @@ -364,6 +367,115 @@ static void *SWITCH_THREAD_FUNC console_thread(switch_thread_t *thread, void *ob } +struct helper { + EditLine *el; + int len; + int hits; + char last[512]; + FILE *out; +}; + +static int comp_callback(void *pArg, int argc, char **argv, char **columnNames) +{ + struct helper *h = (struct helper *) pArg; + + fprintf(h->out, "%20s\t", argv[0]); + + switch_copy_string(h->last, argv[0], sizeof(h->last)); + + if ((++h->hits % 4) == 0) { + fprintf(h->out, "\n"); + } + + return 0; +} + +static unsigned char complete(EditLine *el, int ch) +{ + switch_core_db_t *db = switch_core_db_handle(); + char *sql; + const LineInfo *lf = el_line(el); + char *dup = strdup(lf->buffer); + char *buf = dup; + char *p, *lp = NULL; + char *errmsg = NULL; + struct helper h = { el }; + int words = 0; + unsigned char ret = CC_REDISPLAY; + + h.out = switch_core_get_console(); + + if ((p = strchr(buf, '\r')) || (p = strchr(buf, '\n'))) { + *p = '\0'; + } + + while(*buf == ' ') { + buf++; + } + + for(p = buf; p && *p; p++) { + if (*p == ' ') { + lp = p; + words++; + } + } + + if (lp) { + buf = lp + 1; + } + + h.len = strlen(buf); + + fprintf(h.out, "\n\n"); + + if (words == 0) { + sql = switch_mprintf("select distinct name from interfaces where type='api' and name like '%s%%' order by name", buf); + } else { + sql = switch_mprintf("select distinct uuid from channels where uuid like '%s%%' order by uuid", buf); + } + + switch_core_db_exec(db, sql, comp_callback, &h, &errmsg); + + if (errmsg) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "error [%s][%s]\n", sql, errmsg); + free(errmsg); + ret = CC_ERROR; + goto end; + } + + if (h.hits != 1) { + switch_safe_free(sql); + sql = switch_mprintf("select distinct name from complete where name like '%s%%' order by name", buf); + switch_core_db_exec(db, sql, comp_callback, &h, &errmsg); + + if (errmsg) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "error [%s][%s]\n", sql, errmsg); + free(errmsg); + ret = CC_ERROR; + goto end; + } + } + + fprintf(h.out, "\n\n"); + + if (h.hits == 1) { + el_deletestr(el, h.len); + el_insertstr(el, h.last); + el_insertstr(el, " "); + } + + end: + + fflush(h.out); + + switch_safe_free(sql); + switch_safe_free(dup); + + switch_core_db_close(db); + + return (ret); +} + SWITCH_DECLARE(void) switch_console_loop(void) { switch_thread_t *thread; @@ -417,6 +529,10 @@ SWITCH_DECLARE(void) switch_console_loop(void) el_set(el, EL_BIND, "\033[23~", "f11-key", NULL); el_set(el, EL_BIND, "\033[24~", "f12-key", NULL); + + el_set(el, EL_ADDFN, "ed-complete", "Complete argument", complete); + el_set(el, EL_BIND, "^I", "ed-complete", NULL); + myhistory = history_init(); if (myhistory == 0) { fprintf(stderr, "history could not be initialized\n"); diff --git a/src/switch_core_sqldb.c b/src/switch_core_sqldb.c index dcc5f5351b..4fd854d24c 100644 --- a/src/switch_core_sqldb.c +++ b/src/switch_core_sqldb.c @@ -254,10 +254,12 @@ static void core_event_handler(switch_event_t *event) sql = switch_mprintf("delete from channels where uuid='%q'", switch_event_get_header(event, "unique-id")); break; case SWITCH_EVENT_CHANNEL_CREATE: - sql = switch_mprintf("insert into channels (uuid,created,name,state) values('%q','%q','%q','%q')", + sql = switch_mprintf("insert into channels (uuid,created,created_epoch, name,state) values('%q','%q','%ld','%q','%q')", switch_event_get_header(event, "unique-id"), switch_event_get_header(event, "event-date-local"), - switch_event_get_header(event, "channel-name"), switch_event_get_header(event, "channel-state") + (long)switch_timestamp(NULL), + switch_event_get_header(event, "channel-name"), + switch_event_get_header(event, "channel-state") ); break; case SWITCH_EVENT_CODEC: @@ -305,7 +307,9 @@ static void core_event_handler(switch_event_t *event) } break; case SWITCH_EVENT_CHANNEL_BRIDGE: - sql = switch_mprintf("insert into calls values ('%s','%q','%q','%q','%q','%s','%q','%q','%q','%q','%s')", + sql = switch_mprintf("insert into calls values ('%s', '%ld', '%s','%q','%q','%q','%q','%s','%q','%q','%q','%q','%s')", + switch_event_get_header(event, "event-date-local"), + (long)switch_timestamp(NULL), switch_event_get_header(event, "event-calling-function"), switch_event_get_header(event, "caller-caller-id-name"), switch_event_get_header(event, "caller-caller-id-number"), @@ -362,10 +366,16 @@ void switch_core_sqldb_start(switch_memory_pool_t *pool) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Opening DB!\n"); switch_clear_flag((&runtime), SCF_USE_SQL); } else { + char create_complete_sql[] = + "CREATE TABLE complete (\n" + " name VARCHAR(255)\n" + ");\n"; + char create_channels_sql[] = "CREATE TABLE channels (\n" " uuid VARCHAR(255),\n" " created VARCHAR(255),\n" + " created_epoch INTEGER,\n" " name VARCHAR(255),\n" " state VARCHAR(255),\n" " cid_name VARCHAR(255),\n" @@ -374,10 +384,16 @@ void switch_core_sqldb_start(switch_memory_pool_t *pool) " dest VARCHAR(255),\n" " application VARCHAR(255),\n" " application_data VARCHAR(255),\n" - " read_codec VARCHAR(255),\n" " read_rate VARCHAR(255),\n" " write_codec VARCHAR(255),\n" " write_rate VARCHAR(255)\n" ");\n"; + " read_codec VARCHAR(255),\n" + " read_rate VARCHAR(255),\n" + " write_codec VARCHAR(255),\n" + " write_rate VARCHAR(255)\n" + ");\n"; char create_calls_sql[] = "CREATE TABLE calls (\n" " function VARCHAR(255),\n" + " created VARCHAR(255),\n" + " created_epoch INTEGER,\n" " caller_cid_name VARCHAR(255),\n" " caller_cid_num VARCHAR(255),\n" " caller_dest_num VARCHAR(255),\n" @@ -385,15 +401,24 @@ void switch_core_sqldb_start(switch_memory_pool_t *pool) " caller_uuid VARCHAR(255),\n" " callee_cid_name VARCHAR(255),\n" " callee_cid_num VARCHAR(255),\n" - " callee_dest_num VARCHAR(255),\n" " callee_chan_name VARCHAR(255),\n" " callee_uuid VARCHAR(255)\n" ");\n"; + " callee_dest_num VARCHAR(255),\n" + " callee_chan_name VARCHAR(255),\n" + " callee_uuid VARCHAR(255)\n" + ");\n"; char create_interfaces_sql[] = "CREATE TABLE interfaces (\n" " type VARCHAR(255),\n" - " name VARCHAR(255),\n" " description VARCHAR(255),\n" " syntax VARCHAR(255)\n" ");\n"; + " name VARCHAR(255),\n" + " description VARCHAR(255),\n" + " syntax VARCHAR(255)\n" + ");\n"; char create_tasks_sql[] = "CREATE TABLE tasks (\n" " task_id INTEGER(4),\n" - " task_desc VARCHAR(255),\n" " task_group VARCHAR(255),\n" " task_sql_manager INTEGER(8)\n" ");\n"; + " task_desc VARCHAR(255),\n" + " task_group VARCHAR(255),\n" + " task_sql_manager INTEGER(8)\n" + ");\n"; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Opening DB\n"); switch_core_db_exec(sql_manager.db, "drop table channels", NULL, NULL, NULL); @@ -405,6 +430,7 @@ void switch_core_sqldb_start(switch_memory_pool_t *pool) switch_core_db_exec(sql_manager.db, "PRAGMA cache_size=8000", NULL, NULL, NULL); switch_core_db_exec(sql_manager.db, "PRAGMA temp_store=MEMORY;", NULL, NULL, NULL); + switch_core_db_exec(sql_manager.db, create_complete_sql, NULL, NULL, NULL); switch_core_db_exec(sql_manager.db, create_channels_sql, NULL, NULL, NULL); switch_core_db_exec(sql_manager.db, create_calls_sql, NULL, NULL, NULL); switch_core_db_exec(sql_manager.db, create_interfaces_sql, NULL, NULL, NULL);