diff --git a/CHANGES b/CHANGES index a79d6f4ae5..b2c18fff83 100755 --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,4 @@ + -- Add NAT and dynamic support to MGCP -- Allow selection of in-band, out-of-band, or INFO based DTMF -- Add contributed "*80" support to blacklist numbers (Thanks James!) -- Add "NAT" option to sip user, peer, friend diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index 03cc83393c..a304038334 100755 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -830,7 +830,7 @@ static int match(struct sockaddr_in *sin, unsigned short callno, unsigned short static int find_callno(unsigned short callno, unsigned short dcallno, struct sockaddr_in *sin, int new) { - int res = -1; + int res = 0; int x; int start; if (new <= NEW_ALLOW) { @@ -852,7 +852,7 @@ static int find_callno(unsigned short callno, unsigned short dcallno, struct soc for (x = ((nextcallno + 1) % (AST_IAX2_MAX_CALLS - 1)) + 1; iaxs[x] && (x != start); x = (x + 1) % AST_IAX2_MAX_CALLS) if (x == start) { ast_log(LOG_WARNING, "Unable to accept more calls\n"); - return -1; + return 0; } ast_pthread_mutex_lock(&iaxsl[x]); iaxs[x] = new_iax(); @@ -873,7 +873,7 @@ static int find_callno(unsigned short callno, unsigned short dcallno, struct soc strncpy(iaxs[x]->accountcode, accountcode, sizeof(iaxs[x]->accountcode)-1); } else { ast_log(LOG_WARNING, "Out of resources\n"); - return -1; + return 0; } res = x; nextcallno = x; @@ -4270,7 +4270,7 @@ static int iax2_do_register(struct iax2_registry *reg) if (option_debug) ast_log(LOG_DEBUG, "Allocate call number\n"); reg->callno = find_callno(0, 0, ®->addr, NEW_FORCE); - if (reg->callno < 0) { + if (reg->callno < 1) { ast_log(LOG_WARNING, "Unable to create call for registration\n"); return -1; } else if (option_debug) @@ -4322,7 +4322,7 @@ static int iax2_poke_peer(struct iax2_peer *peer) iax2_destroy(peer->callno); } peer->callno = find_callno(0, 0, &peer->addr, NEW_FORCE); - if (peer->callno < 0) { + if (peer->callno < 1) { ast_log(LOG_WARNING, "Unable to allocate call for poking peer '%s'\n", peer->name); return -1; } @@ -4374,7 +4374,7 @@ static struct ast_channel *iax2_request(char *type, int format, void *data) return NULL; } callno = find_callno(0, 0, &sin, NEW_FORCE); - if (callno < 0) { + if (callno < 1) { ast_log(LOG_WARNING, "Unable to create call\n"); return NULL; } diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c index 83df5d6b71..0db0e42b2e 100755 --- a/channels/chan_mgcp.c +++ b/channels/chan_mgcp.c @@ -75,6 +75,8 @@ static char ourhost[256]; static struct in_addr __ourip; static int ourport; +static int mgcpdebug = 0; + static struct sched_context *sched; static struct io_context *io; /* The private structures of the mgcp channels are linked for @@ -141,7 +143,10 @@ struct mgcp_gateway { /* A gateway containing one or more endpoints */ char name[80]; struct sockaddr_in addr; + struct sockaddr_in defaddr; struct in_addr ourip; + int dynamic; + int expire; /* XXX Should we ever expire dynamic registrations? XXX */ struct mgcp_endpoint *endpoints; struct ast_ha *ha; struct mgcp_gateway *next; @@ -162,7 +167,10 @@ static int transmit_notify_request_with_callerid(struct mgcp_endpoint *p, char * static int __mgcp_xmit(struct mgcp_endpoint *p, char *data, int len) { int res; - res=sendto(mgcpsock, data, len, 0, (struct sockaddr *)&p->parent->addr, sizeof(struct sockaddr_in)); + if (p->parent->addr.sin_addr.s_addr) + res=sendto(mgcpsock, data, len, 0, (struct sockaddr *)&p->parent->addr, sizeof(struct sockaddr_in)); + else + res=sendto(mgcpsock, data, len, 0, (struct sockaddr *)&p->parent->defaddr, sizeof(struct sockaddr_in)); if (res != len) { ast_log(LOG_WARNING, "mgcp_xmit returned %d: %s\n", res, strerror(errno)); } @@ -172,7 +180,8 @@ static int __mgcp_xmit(struct mgcp_endpoint *p, char *data, int len) static int send_response(struct mgcp_endpoint *p, struct mgcp_request *req) { int res; - printf("Transmitting:\n%s\n to %s:%d\n", req->data, inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port)); + if (mgcpdebug) + ast_verbose("Transmitting:\n%s\n to %s:%d\n", req->data, inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port)); res = __mgcp_xmit(p, req->data, req->len); if (res > 0) res = 0; @@ -182,7 +191,8 @@ static int send_response(struct mgcp_endpoint *p, struct mgcp_request *req) static int send_request(struct mgcp_endpoint *p, struct mgcp_request *req) { int res; - printf("XXX Need to handle Retransmitting XXX:\n%s to %s:%d\n", req->data, inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port)); + if (mgcpdebug) + ast_verbose("XXX Need to handle Retransmitting XXX:\n%s to %s:%d\n", req->data, inet_ntoa(p->parent->addr.sin_addr), ntohs(p->parent->addr.sin_port)); res = __mgcp_xmit(p, req->data, req->len); return res; } @@ -291,9 +301,11 @@ static struct in_addr *myaddrfor(struct in_addr *them) #endif if (((remote_ip & mask) ^ dest) == 0) { - printf("Interface is %s\n",iface); + if (mgcpdebug) + ast_verbose("Interface is %s\n",iface); temp = lookup_iface(iface); - printf("IP Address is %s\n",inet_ntoa(*temp)); + if (mgcpdebug) + ast_verbose("IP Address is %s\n",inet_ntoa(*temp)); break; } } @@ -349,7 +361,7 @@ static int mgcp_show_endpoints(int fd, int argc, char *argv[]) g = gateways; while(g) { e = g->endpoints; - ast_cli(fd, "Gateway '%s' at %s\n", g->name, inet_ntoa(g->addr.sin_addr)); + ast_cli(fd, "Gateway '%s' at %s (%s)\n", g->name, g->addr.sin_addr.s_addr ? inet_ntoa(g->addr.sin_addr) : inet_ntoa(g->defaddr.sin_addr), g->dynamic ? "Dynamic" : "Static"); while(e) { ast_cli(fd, " -- '%s@%s in '%s' is %s\n", e->name, g->name, e->context, e->owner ? "active" : "idle"); hasendpoints = 1; @@ -634,8 +646,18 @@ static struct mgcp_endpoint *find_endpoint(char *name, int msgid, struct sockadd ast_pthread_mutex_lock(&gatelock); g = gateways; while(g) { - if (!name || !strcasecmp(g->name, at)) { - /* Found the gateway -- now for the endpoint */ + if ((!name || !strcasecmp(g->name, at)) && + (sin || g->addr.sin_addr.s_addr || g->defaddr.sin_addr.s_addr)) { + /* Found the gateway. If it's dynamic, save it's address -- now for the endpoint */ + if (sin && g->dynamic) { + if ((g->addr.sin_addr.s_addr != sin->sin_addr.s_addr) || + (g->addr.sin_port != sin->sin_port)) { + memcpy(&g->addr, sin, sizeof(g->addr)); + memcpy(&g->ourip, myaddrfor(&g->addr.sin_addr), sizeof(g->ourip)); + if (option_verbose > 2) + ast_verbose(VERBOSE_PREFIX_3 "Registered MGCP gateway '%s' at %s port %d\n", g->name, inet_ntoa(g->addr.sin_addr), ntohs(g->addr.sin_port)); + } + } p = g->endpoints; while(p) { if ((name && !strcasecmp(p->name, tmp)) || @@ -753,9 +775,11 @@ static void parse(struct mgcp_request *req) } } - printf("Verb: '%s', Identifier: '%s', Endpoint: '%s', Version: '%s'\n", + if (mgcpdebug) { + ast_verbose("Verb: '%s', Identifier: '%s', Endpoint: '%s', Version: '%s'\n", req->verb, req->identifier, req->endpoint, req->version); - printf("%d headers, %d lines\n", req->headers, req->lines); + ast_verbose("%d headers, %d lines\n", req->headers, req->lines); + } if (*c) ast_log(LOG_WARNING, "Odd content, extra stuff left over ('%s')\n", c); } @@ -817,7 +841,8 @@ static int process_sdp(struct mgcp_endpoint *p, struct mgcp_request *req) codecs += len; } p->capability = capability & peercapability; - printf("Capabilities: us - %d, them - %d, combined - %d\n", + if (mgcpdebug) + ast_verbose("Capabilities: us - %d, them - %d, combined - %d\n", capability, peercapability, p->capability); if (!p->capability) { ast_log(LOG_WARNING, "No compatible codecs!\n"); @@ -966,7 +991,8 @@ static int add_sdp(struct mgcp_request *resp, struct mgcp_endpoint *p, struct as dest.sin_port = sin.sin_port; } } - printf("We're at %s port %d\n", inet_ntoa(p->parent->ourip), ntohs(sin.sin_port)); + if (mgcpdebug) + ast_verbose("We're at %s port %d\n", inet_ntoa(p->parent->ourip), ntohs(sin.sin_port)); snprintf(v, sizeof(v), "v=0\r\n"); snprintf(o, sizeof(o), "o=root %d %d IN IP4 %s\r\n", getpid(), getpid(), inet_ntoa(dest.sin_addr)); snprintf(s, sizeof(s), "s=session\r\n"); @@ -975,7 +1001,8 @@ static int add_sdp(struct mgcp_request *resp, struct mgcp_endpoint *p, struct as snprintf(m, sizeof(m), "m=audio %d RTP/AVP", ntohs(dest.sin_port)); for (x=1;x<= AST_FORMAT_MAX_AUDIO; x <<= 1) { if (p->capability & x) { - printf("Answering with capability %d\n", x); + if (mgcpdebug) + ast_verbose("Answering with capability %d\n", x); if ((codec = ast2rtp(x)) > -1) { snprintf(costr, sizeof(costr), " %d", codec); strcat(m, costr); @@ -1192,7 +1219,8 @@ static int handle_request(struct mgcp_endpoint *p, struct mgcp_request *req, str struct ast_channel *c; pthread_t t; struct ast_frame f = { 0, }; - printf("Handling request '%s' on %s@%s\n", req->verb, p->name, p->parent->name); + if (mgcpdebug) + ast_verbose("Handling request '%s' on %s@%s\n", req->verb, p->name, p->parent->name); /* Clear out potential response */ if (!strcasecmp(req->verb, "RSIP")) { if (option_verbose > 2) @@ -1282,7 +1310,8 @@ static int mgcpsock_read(int *id, int fd, short events, void *ignore) } req.data[res] = '\0'; req.len = res; - printf("MGCP read: \n%s\n", req.data); + if (mgcpdebug) + ast_verbose("MGCP read: \n%s\nfrom %s:%d", req.data, inet_ntoa(sin.sin_addr), ntohs(sin.sin_port)); parse(&req); if (req.headers < 1) { /* Must have at least one header */ @@ -1431,6 +1460,7 @@ static struct ast_channel *mgcp_request(char *type, int format, void *data) ast_log(LOG_WARNING, "Unable to find MGCP endpoint '%s'\n", tmp); return NULL; } + /* Must be busy */ if (p->owner) return NULL; @@ -1453,10 +1483,32 @@ struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v) gw = malloc(sizeof(struct mgcp_gateway)); if (gw) { memset(gw, 0, sizeof(struct mgcp_gateway)); + gw->expire = -1; strncpy(gw->name, cat, sizeof(gw->name) - 1); while(v) { if (!strcasecmp(v->name, "host")) { - if (ast_get_ip(&gw->addr, v->value)) { + if (!strcasecmp(v->value, "dynamic")) { + /* They'll register with us */ + gw->dynamic = 1; + memset(&gw->addr.sin_addr, 0, 4); + if (gw->addr.sin_port) { + /* If we've already got a port, make it the default rather than absolute */ + gw->defaddr.sin_port = gw->addr.sin_port; + gw->addr.sin_port = 0; + } + } else { + /* Non-dynamic. Make sure we become that way if we're not */ + if (gw->expire > -1) + ast_sched_del(sched, gw->expire); + gw->expire = -1; + gw->dynamic = 0; + if (ast_get_ip(&gw->addr, v->value)) { + free(gw); + return NULL; + } + } + } else if (!strcasecmp(v->name, "defaultip")) { + if (ast_get_ip(&gw->defaddr, v->value)) { free(gw); return NULL; } @@ -1503,14 +1555,17 @@ struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v) } } - if (!ntohl(gw->addr.sin_addr.s_addr)) { - ast_log(LOG_WARNING, "Gateway '%s' lacks IP address\n", gw->name); + if (!ntohl(gw->addr.sin_addr.s_addr) && !gw->dynamic) { + ast_log(LOG_WARNING, "Gateway '%s' lacks IP address and isn't dynamic\n", gw->name); free(gw); - gw = NULL; - } else if (!ntohs(gw->addr.sin_port)) { + return NULL; + } + if (gw->defaddr.sin_addr.s_addr && !ntohs(gw->defaddr.sin_port)) + gw->defaddr.sin_port = htons(DEFAULT_MGCP_PORT); + if (gw->addr.sin_addr.s_addr && !ntohs(gw->addr.sin_port)) gw->addr.sin_port = htons(DEFAULT_MGCP_PORT); + if (gw->addr.sin_addr.s_addr) memcpy(&gw->ourip, myaddrfor(&gw->addr.sin_addr), sizeof(gw->ourip)); - } return gw; } @@ -1539,6 +1594,38 @@ static struct ast_rtp_protocol mgcp_rtp = { set_rtp_peer: mgcp_set_rtp_peer, }; +static int mgcp_do_debug(int fd, int argc, char *argv[]) +{ + if (argc != 2) + return RESULT_SHOWUSAGE; + mgcpdebug = 1; + ast_cli(fd, "MGCP Debugging Enabled\n"); + return RESULT_SUCCESS; +} + +static int mgcp_no_debug(int fd, int argc, char *argv[]) +{ + if (argc != 3) + return RESULT_SHOWUSAGE; + mgcpdebug = 0; + ast_cli(fd, "MGCP Debugging Disabled\n"); + return RESULT_SUCCESS; +} + +static char debug_usage[] = +"Usage: mgcp debug\n" +" Enables dumping of MGCP packets for debugging purposes\n"; + +static char no_debug_usage[] = +"Usage: mgcp no debug\n" +" Disables dumping of MGCP packets for debugging purposes\n"; + +static struct ast_cli_entry cli_debug = + { { "mgcp", "debug", NULL }, mgcp_do_debug, "Enable MGCP debugging", debug_usage }; +static struct ast_cli_entry cli_no_debug = + { { "mgcp", "no", "debug", NULL }, mgcp_no_debug, "Disable MGCP debugging", no_debug_usage }; + + int load_module() { struct ast_config *cfg; @@ -1649,6 +1736,8 @@ int load_module() mgcp_rtp.type = type; ast_rtp_proto_register(&mgcp_rtp); ast_cli_register(&cli_show_endpoints); + ast_cli_register(&cli_debug); + ast_cli_register(&cli_no_debug); /* And start the monitor for the first time */ restart_monitor(); return 0; diff --git a/channels/chan_sip.c b/channels/chan_sip.c index c9f9d89486..81c760bec9 100755 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -387,6 +387,11 @@ static int create_addr(struct sip_pvt *r, char *peer) if (!strcasecmp(p->name, peer)) { found++; r->capability = p->capability; + r->nat = p->nat; + if (r->rtp) { + ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", r->nat); + ast_rtp_setnat(r->rtp, r->nat); + } strncpy(r->peername, p->username, sizeof(r->peername)-1); strncpy(r->peersecret, p->secret, sizeof(r->peersecret)-1); strncpy(r->username, p->username, sizeof(r->username)-1); @@ -2550,8 +2555,10 @@ static int check_user(struct sip_pvt *p, struct sip_request *req, char *cmd, cha while(user) { if (!strcasecmp(user->name, of)) { p->nat = user->nat; - if (p->rtp) + if (p->rtp) { + ast_log(LOG_DEBUG, "Setting NAT on RTP to %d\n", p->nat); ast_rtp_setnat(p->rtp, p->nat); + } if (!(res = check_auth(p, req, p->randdata, sizeof(p->randdata), user->name, user->secret, cmd, uri))) { strncpy(p->context, user->context, sizeof(p->context) - 1); if (strlen(user->callerid) && strlen(p->callerid)) @@ -3766,6 +3773,7 @@ static struct sip_user *build_user(char *name, struct ast_variable *v) user->canreinvite = 1; /* JK02: set default context */ strcpy(user->context, context); + user->dtmfmode = SIP_DTMF_RFC2833; while(v) { if (!strcasecmp(v->name, "context")) { strncpy(user->context, v->value, sizeof(user->context)); diff --git a/config.c b/config.c index 114d6584aa..1ce10def9e 100755 --- a/config.c +++ b/config.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -28,12 +29,22 @@ struct ast_category { char name[80]; struct ast_variable *root; struct ast_category *next; + struct ast_comment *precomments; + struct ast_comment *sameline; }; struct ast_config { /* Maybe this structure isn't necessary but we'll keep it for now */ struct ast_category *root; + struct ast_category *prev; + struct ast_comment *trailingcomments; +}; + +struct ast_comment_struct +{ + struct ast_comment *root; + struct ast_comment *prev; }; static char *strip(char *buf) @@ -49,6 +60,16 @@ static char *strip(char *buf) return start; } +static void free_comments(struct ast_comment *com) +{ + struct ast_comment *l; + while (com) { + l = com; + com = com->next; + free(l); + } +} + void ast_destroy(struct ast_config *ast) { struct ast_category *cat, *catn; @@ -64,13 +85,18 @@ void ast_destroy(struct ast_config *ast) vn = v; free(v->name); free(v->value); + free_comments(v->precomments); + free_comments(v->sameline); v = v->next; free(vn); } catn = cat; + free_comments(cat->precomments); + free_comments(cat->sameline); cat = cat->next; free(catn); } + free_comments(ast->trailingcomments); free(ast); } @@ -138,6 +164,220 @@ char *ast_variable_retrieve(struct ast_config *config, char *category, char *val return NULL; } +int ast_variable_delete(struct ast_config *cfg, char *category, char *variable, char *value) +{ + struct ast_variable *v, *pv, *bv, *bpv; + struct ast_category *cat; + cat = cfg->root; + while(cat) { + if (cat->name == category) { + break; + } + cat = cat->next; + } + if (!cat) { + cat = cfg->root; + while(cat) { + if (!strcasecmp(cat->name, category)) { + break; + } + cat = cat->next; + } + } + if (!cat) + return -1; + v = cat->root; + pv = NULL; + while (v) { + if ((variable == v->name) && (!value || !strcmp(v->value, value))) + break; + pv = v; + v=v->next; + } + if (!v) { + /* Get the last one that looks like it */ + bv = NULL; + bpv = NULL; + v = cat->root; + pv = NULL; + while (v) { + if (!strcasecmp(variable, v->name) && (!value || !strcmp(v->value, value))) { + bv = v; + bpv = pv; + } + pv = v; + v=v->next; + } + v = bv; + } + + if (v) { + /* Unlink from original position */ + if (pv) + pv->next = v->next; + else + cat->root = v->next; + v->next = NULL; + free(v->name); + if (v->value) + free(v->value); + free_comments(v->sameline); + free_comments(v->precomments); + return 0; + } + return -1; +} + +int ast_category_delete(struct ast_config *cfg, char *category) +{ + struct ast_variable *v, *pv; + struct ast_category *cat, *cprev; + cat = cfg->root; + cprev = NULL; + while(cat) { + if (cat->name == category) { + break; + } + cprev = cat; + cat = cat->next; + } + if (!cat) { + cat = cfg->root; + cprev = NULL; + while(cat) { + if (!strcasecmp(cat->name, category)) { + break; + } + cprev = cat; + cat = cat->next; + } + } + if (!cat) + return -1; + /* Unlink it */ + if (cprev) + cprev->next = cat->next; + else + cfg->root = cat->next; + v = cat->root; + while (v) { + pv = v; + v=v->next; + if (pv->value) + free(pv->value); + if (pv->name) + free(pv->name); + free_comments(pv->sameline); + free_comments(pv->precomments); + free(pv); + } + free_comments(cat->sameline); + free_comments(cat->precomments); + free(cat); + return 0; +} + +struct ast_variable *ast_variable_append_modify(struct ast_config *config, char *category, char *variable, char *value, int newcat, int newvar, int move) +{ + struct ast_variable *v, *pv, *bv, *bpv; + struct ast_category *cat, *pcat; + cat = config->root; + if (!newcat) { + while(cat) { + if (cat->name == category) { + break; + } + cat = cat->next; + } + if (!cat) { + cat = config->root; + while(cat) { + if (!strcasecmp(cat->name, category)) { + break; + } + cat = cat->next; + } + } + } + if (!cat) { + cat = malloc(sizeof(struct ast_category)); + if (!cat) + return NULL; + memset(cat, 0, sizeof(struct ast_category)); + strncpy(cat->name, category, sizeof(cat->name)); + if (config->root) { + /* Put us at the end */ + pcat = config->root; + while(pcat->next) + pcat = pcat->next; + pcat->next = cat; + } else { + /* We're the first one */ + config->root = cat; + } + + } + if (!newvar) { + v = cat->root; + pv = NULL; + while (v) { + if (variable == v->name) + break; + pv = v; + v=v->next; + } + if (!v) { + /* Get the last one that looks like it */ + bv = NULL; + bpv = NULL; + v = cat->root; + pv = NULL; + while (v) { + if (!strcasecmp(variable, v->name)) { + bv = v; + bpv = pv; + } + pv = v; + v=v->next; + } + v = bv; + } + } else v = NULL; + if (v && move) { + /* Unlink from original position */ + if (pv) + pv->next = v->next; + else + cat->root = v->next; + v->next = NULL; + } + if (!v) { + v = malloc(sizeof(struct ast_variable)); + if (!v) + return NULL; + memset(v, 0, sizeof(struct ast_variable)); + v->name = strdup(variable); + move = 1; + } + if (v->value) + free(v->value); + if (value) + v->value = strdup(value); + else + v->value = strdup(""); + if (move) { + if (cat->root) { + pv = cat->root; + while (pv->next) + pv = pv->next; + pv->next = v; + } else { + cat->root = v; + } + } + return v; +} + int ast_category_exist(struct ast_config *config, char *category_name) { struct ast_category *category = NULL; @@ -153,16 +393,33 @@ int ast_category_exist(struct ast_config *config, char *category_name) return 0; } -static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, int includelevel); -static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, char *buf, int lineno, char *configfile, int includelevel) +static struct ast_comment *build_comment(char *cmt) +{ + struct ast_comment *c; + c = malloc(sizeof(struct ast_comment)); + if (c) { + memset(c, 0, sizeof(struct ast_comment)); + c->comment = strdup(cmt); + } + return c; +} + +static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, int includelevel, struct ast_comment_struct *acs); +static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, char *buf, int lineno, char *configfile, int includelevel, struct ast_comment_struct *acs) { char *c; char *cur; struct ast_variable *v; + struct ast_comment *com = NULL; + int object; /* Strip off lines using ; as comment */ c = strchr(buf, ';'); - if (c) + if (c) { *c = '\0'; + c++; + if (*c != '!') + com = build_comment(c); + } cur = strip(buf); if (strlen(cur)) { /* Actually parse the entry */ @@ -181,8 +438,16 @@ static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, stru memset(*_tmpc, 0, sizeof(struct ast_category)); strncpy((*_tmpc)->name, cur+1, sizeof((*_tmpc)->name) - 1); (*_tmpc)->root = NULL; - (*_tmpc)->next = tmp->root; - tmp->root = *_tmpc; + (*_tmpc)->precomments = acs->root; + (*_tmpc)->sameline = com; + if (!tmp->prev) + tmp->root = *_tmpc; + else + tmp->prev->next = *_tmpc; + + tmp->prev = *_tmpc; + acs->root = NULL; + acs->prev = NULL; *_last = NULL; } else { ast_log(LOG_WARNING, @@ -216,7 +481,7 @@ static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, stru break; } if (includelevel < MAX_INCLUDE_LEVEL) { - __ast_load(cur, tmp, _tmpc, _last, includelevel + 1); + __ast_load(cur, tmp, _tmpc, _last, includelevel + 1, acs); } else ast_log(LOG_WARNING, "Maximum Include level (%d) exceeded\n", includelevel); } else @@ -237,8 +502,11 @@ static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, stru *c = 0; c++; /* Ignore > in => */ - if (*c== '>') + if (*c== '>') { + object = 1; c++; + } else + object = 0; v = malloc(sizeof(struct ast_variable)); if (v) { memset(v, 0, sizeof(struct ast_variable)); @@ -246,7 +514,14 @@ static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, stru v->name = strdup(strip(cur)); v->value = strdup(strip(c)); v->lineno = lineno; - if (*_last) + v->object = object; + /* Put and reset comments */ + v->precomments = acs->root; + v->blanklines = 0; + acs->prev = NULL; + acs->root = NULL; + v->sameline = com; + if (*_last) (*_last)->next = v; else (*_tmpc)->root = v; @@ -260,17 +535,108 @@ static int cfg_process(struct ast_config *tmp, struct ast_category **_tmpc, stru ast_log(LOG_WARNING, "No '=' (equal sign) in line %d of %s\n", lineno, configfile); } + } + } else { + /* store any comments if there are any */ + if (com) { + if (acs->prev) + acs->prev->next = com; + else + acs->root = com; + acs->prev = com; + } else { + if (*_last) + (*_last)->blanklines++; + } } return 0; } -static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, int includelevel) +static void dump_comments(FILE *f, struct ast_comment *comment) +{ + while (comment) { + fprintf(f, ";%s", comment->comment); + comment = comment->next; + } +} + +int ast_save(char *configfile, struct ast_config *cfg, char *generator) +{ + FILE *f; + char fn[256]; + char date[256]; + time_t t; + struct ast_variable *var; + struct ast_category *cat; + int blanklines = 0; + if (configfile[0] == '/') { + strncpy(fn, configfile, sizeof(fn)-1); + } else { + snprintf(fn, sizeof(fn), "%s/%s", AST_CONFIG_DIR, configfile); + } + time(&t); + strncpy(date, ctime(&t), sizeof(date)); + if ((f = fopen(fn, "w"))) { + if ((option_verbose > 1) && !option_debug) + ast_verbose( VERBOSE_PREFIX_2 "Saving '%s': ", fn); + fprintf(f, ";!\n"); + fprintf(f, ";! Automatically generated configuration file\n"); + fprintf(f, ";! Filename: %s (%s)\n", configfile, fn); + fprintf(f, ";! Generator: %s\n", generator); + fprintf(f, ";! Creation Date: %s", date); + fprintf(f, ";!\n"); + cat = cfg->root; + while(cat) { + /* Dump any precomments */ + dump_comments(f, cat->precomments); + /* Dump section with any appropriate comment */ + if (cat->sameline) + fprintf(f, "[%s] ; %s\n", cat->name, cat->sameline->comment); + else + fprintf(f, "[%s]\n", cat->name); + var = cat->root; + while(var) { + dump_comments(f, var->precomments); + if (var->sameline) + fprintf(f, "%s %s %s ; %s\n", var->name, (var->object ? "=>" : "="), var->value, var->sameline->comment); + else + fprintf(f, "%s %s %s\n", var->name, (var->object ? "=>" : "="), var->value); + if (var->blanklines) { + blanklines = var->blanklines; + while (blanklines) { + fprintf(f, "\n"); + blanklines--; + } + } + + var = var->next; + } +#if 0 + /* Put an empty line */ + fprintf(f, "\n"); +#endif + cat = cat->next; + } + dump_comments(f, cfg->trailingcomments); + } else { + if (option_debug) + printf("Unable to open for writing: %s\n", fn); + else if (option_verbose > 1) + printf( "Unable to write (%s)", strerror(errno)); + return -1; + } + fclose(f); + return 0; +} + +static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, struct ast_category **_tmpc, struct ast_variable **_last, int includelevel, struct ast_comment_struct *acs) { char fn[256]; char buf[256]; FILE *f; int lineno=0; + int master=0; if (configfile[0] == '/') { strncpy(fn, configfile, sizeof(fn)-1); @@ -290,6 +656,8 @@ static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, s tmp = malloc(sizeof(struct ast_config)); if (tmp) memset(tmp, 0, sizeof(struct ast_config)); + + master = 1; } if (!tmp) { ast_log(LOG_WARNING, "Out of memory\n"); @@ -300,7 +668,7 @@ static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, s fgets(buf, sizeof(buf), f); lineno++; if (!feof(f)) { - if (cfg_process(tmp, _tmpc, _last, buf, lineno, configfile, includelevel)) { + if (cfg_process(tmp, _tmpc, _last, buf, lineno, configfile, includelevel, acs)) { fclose(f); return NULL; } @@ -313,6 +681,12 @@ static struct ast_config *__ast_load(char *configfile, struct ast_config *tmp, s else if (option_verbose > 1) ast_verbose( "Not found (%s)", strerror(errno)); } + if (master) { + /* Keep trailing comments */ + tmp->trailingcomments = acs->root; + acs->root = NULL; + acs->prev = NULL; + } return tmp; } @@ -320,7 +694,8 @@ struct ast_config *ast_load(char *configfile) { struct ast_category *tmpc=NULL; struct ast_variable *last = NULL; - return __ast_load(configfile, NULL, &tmpc, &last, 0); + struct ast_comment_struct acs = { NULL, NULL }; + return __ast_load(configfile, NULL, &tmpc, &last, 0, &acs); } char *ast_category_browse(struct ast_config *config, char *prev) diff --git a/dsp.c b/dsp.c index 9851a0ca27..62e03420fe 100755 --- a/dsp.c +++ b/dsp.c @@ -519,6 +519,7 @@ static int dtmf_detect (dtmf_detect_state_t *s, } /* Don't reset fax hits counter */ } else { if (s->fax_hits > 5) { + hit = 'f'; s->mhit = 'f'; s->detected_digits++; if (s->current_digits < MAX_DTMF_DIGITS) diff --git a/include/asterisk/config.h b/include/asterisk/config.h index ff7ad45392..b6875049b6 100755 --- a/include/asterisk/config.h +++ b/include/asterisk/config.h @@ -30,6 +30,7 @@ struct ast_variable { char *value; int lineno; int object; /* 0 for variable, 1 for object */ + int blanklines; /* Number of blanklines following entry */ struct ast_comment *precomments; struct ast_comment *sameline; struct ast_variable *next; diff --git a/manager.c b/manager.c index 638c951b06..f9d224d6ee 100755 --- a/manager.c +++ b/manager.c @@ -733,5 +733,6 @@ int init_manager(void) int reload_manager(void) { + manager_event(EVENT_FLAG_SYSTEM, "Reload", NULL); return init_manager(); } diff --git a/rtp.c b/rtp.c index 54b7e945ba..fb3ea671ff 100755 --- a/rtp.c +++ b/rtp.c @@ -282,7 +282,11 @@ struct ast_frame *ast_rtp_read(struct ast_rtp *rtp) } if (rtp->nat) { /* Send to whoever sent to us */ - memcpy(&rtp->them, &sin, sizeof(rtp->them)); + if ((rtp->them.sin_addr.s_addr != sin.sin_addr.s_addr) || + (rtp->them.sin_port != sin.sin_port)) { + memcpy(&rtp->them, &sin, sizeof(rtp->them)); + ast_log(LOG_DEBUG, "RTP NAT: Using address %s:%d\n", inet_ntoa(rtp->them.sin_addr), ntohs(rtp->them.sin_port)); + } } /* Get fields */ seqno = ntohl(rtpheader[0]);