--- channels/chan_sip.c.orig 2005-01-04 20:29:27.000000000 -0500 +++ channels/chan_sip.c 2005-01-04 20:31:00.000000000 -0500 @@ -115,6 +115,7 @@ static char *channeltype = "SIP"; static char *tdesc = "Session Initiation Protocol (SIP)"; static char *config = "sip.conf"; +static char *notify_config = "sip_notify.conf"; #define DEFAULT_SIP_PORT 5060 /* From RFC 2543 */ #define SIP_MAX_PACKET 4096 /* Also from RFC 2543, should sub headers tho */ @@ -555,6 +556,9 @@ static int externrefresh = 10; static struct ast_ha *localaddr; +/* The list of manual NOTIFY types we know how to send */ +struct ast_config *notify_types; + static struct ast_frame *sip_read(struct ast_channel *ast); static int transmit_response(struct sip_pvt *p, char *msg, struct sip_request *req); static int transmit_response_with_sdp(struct sip_pvt *p, char *msg, struct sip_request *req, int retrans); @@ -614,6 +618,18 @@ static void sip_destroy(struct sip_pvt *p); +/*--- build_via: Build a Via header for a request ---*/ +static void build_via(struct sip_pvt *p, char *buf, int len) +{ + char iabuf[INET_ADDRSTRLEN]; + + /* z9hG4bK is a magic cookie. See RFC 3261 section 8.1.1.7 */ + if (ast_test_flag(p, SIP_NAT) != SIP_NAT_NEVER) + snprintf(buf, len, "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x;rport", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch); + else /* Work around buggy UNIDEN UIP200 firmware */ + snprintf(buf, len, "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch); +} + /*--- ast_sip_ouraddrfor: NAT fix - decide which IP address to use for ASterisk server? ---*/ /* Only used for outbound registrations */ static int ast_sip_ouraddrfor(struct in_addr *them, struct in_addr *us) @@ -2264,7 +2280,6 @@ static struct sip_pvt *sip_alloc(char *callid, struct sockaddr_in *sin, int useglobal_nat) { struct sip_pvt *p; - char iabuf[INET_ADDRSTRLEN]; p = malloc(sizeof(struct sip_pvt)); if (!p) @@ -2318,11 +2333,7 @@ } strncpy(p->fromdomain, default_fromdomain, sizeof(p->fromdomain) - 1); - /* z9hG4bK is a magic cookie. See RFC 3261 section 8.1.1.7 */ - if (ast_test_flag(p, SIP_NAT) != SIP_NAT_NEVER) - snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x;rport", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch); - else - snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch); + build_via(p, p->via, sizeof(p->via)); if (!callid) build_callid(p->callid, sizeof(p->callid), p->ourip, p->fromdomain); else @@ -3122,7 +3133,6 @@ char stripped[80] =""; char tmp[80]; char newto[256]; - char iabuf[INET_ADDRSTRLEN]; char *c, *n; char *ot, *of; @@ -3137,10 +3147,7 @@ if (newbranch) { p->branch ^= rand(); - if (ast_test_flag(p, SIP_NAT) & SIP_NAT_RFC3581) - snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x;rport", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch); - else /* Some implementations (e.g. Uniden UIP200) can't handle rport being in the message!! */ - snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch); + build_via(p, p->via, sizeof(p->via)); } if (!strcasecmp(msg, "CANCEL")) { c = p->initreq.rlPart2; /* Use original URI */ @@ -3772,15 +3779,11 @@ static int transmit_invite(struct sip_pvt *p, char *cmd, int sdp, char *auth, char *authheader, char *vxml_url, char *distinctive_ring, char *osptoken, int addsipheaders, int init) { struct sip_request req; - char iabuf[INET_ADDRSTRLEN]; if (init) { /* Bump branch even on initial requests */ p->branch ^= rand(); - if (ast_test_flag(p, SIP_NAT) & SIP_NAT_RFC3581) - snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x;rport", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch); - else /* Work around buggy UNIDEN UIP200 firmware */ - snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch); + build_via(p, p->via, sizeof(p->via)); initreqprep(&req, p, cmd, vxml_url); } else reqprep(&req, p, cmd, 0, 1); @@ -4018,7 +4021,7 @@ determine_firstline_parts(&p->initreq); } - return send_request(p, req, 1, p->ocseq); + return send_request(p, req, 0, p->ocseq); } /*--- transmit_notify_with_sipfrag: Notify a transferring party of the status of trasnfer ---*/ @@ -4149,7 +4152,6 @@ char tmp[80]; char via[80]; char addr[80]; - char iabuf[INET_ADDRSTRLEN]; struct sip_pvt *p; /* exit if we are already in process with this registrar ?*/ @@ -4259,11 +4261,7 @@ snprintf(tmp, sizeof(tmp), "%u %s", ++r->ocseq, cmd); p->ocseq = r->ocseq; - /* z9hG4bK is a magic cookie. See RFC 3261 section 8.1.1.7 */ - if (ast_test_flag(p, SIP_NAT) & SIP_NAT_RFC3581) - snprintf(via, sizeof(via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x;rport", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch); - else /* Work around buggy UNIDEN UIP200 firmware */ - snprintf(via, sizeof(via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch); + build_via(p, via, sizeof(via)); add_header(&req, "Via", via); add_header(&req, "From", from); add_header(&req, "To", to); @@ -6135,23 +6133,50 @@ return c; } -/*--- complete_sippeer: Support routine for 'sip reboot' CLI ---*/ -static char *complete_sippeer(char *line, char *word, int pos, int state) +/*--- complete_sipnotify: Support routine for 'sip notify' CLI ---*/ +static char *complete_sipnotify(char *line, char *word, int pos, int state) { - int which=0; char *c = NULL; - ASTOBJ_CONTAINER_TRAVERSE(&peerl, !c, do { - /* locking of the ASTOBJ is not required because I only compare the name */ - if (!strncasecmp(word, iterator->name, strlen(word))) { - if (++which > state) { - c = strdup(iterator->name); + if (pos == 2) { + int which = 0; + char *cat; + + /* do completion for notify type */ + + if (!notify_types) + return NULL; + + cat = ast_category_browse(notify_types, NULL); + while(cat) { + if (!strncasecmp(word, cat, strlen(word))) { + if (++which > state) { + c = strdup(cat); + break; + } } + cat = ast_category_browse(notify_types, cat); } - - } while(0) ); + return c; + } - return c; + if (pos > 2) { + int which = 0; + + /* do completion for peer name */ + + ASTOBJ_CONTAINER_TRAVERSE(&peerl, !c, do { + /* locking of the ASTOBJ is not required because I only compare the name */ + if (!strncasecmp(word, iterator->name, strlen(word))) { + if (++which > state) { + c = strdup(iterator->name); + } + } + } while(0) ); + return c; + } + + return NULL; } /*--- sip_show_channel: Show details of one call ---*/ @@ -6406,72 +6431,57 @@ static int sip_notify(int fd, int argc, char *argv[]) { - struct sip_pvt *p; - struct sip_request req; - struct ast_config *cfg; - struct ast_variable *var; - char *cat; - char name[256] = ""; - char type[256] = ""; - char iabuf[INET_ADDRSTRLEN]; - char foundtype = 0; + struct ast_variable *varlist; + int i; - if (argc != 4) { + if (argc < 4) return RESULT_SHOWUSAGE; - } else { - p = sip_alloc(NULL, NULL, 0); - if (!p) { - ast_log(LOG_WARNING, "Unable to build sip pvt data for reboot\n"); - return -1; - } - strncpy(type,argv[2],sizeof(type) - 1); - cfg = ast_load("sip_notify.conf"); - if (!cfg) { - ast_log(LOG_WARNING, "No sip_notify.conf file :\n"); - return RESULT_SUCCESS; - } + if (!notify_types) { + ast_cli(fd, "No %s file found, or no types listed there\n", notify_config); + return RESULT_FAILURE; + } - initreqprep(&req, p, "NOTIFY", NULL); + varlist = ast_variable_browse(notify_types, argv[2]); - cat = ast_category_browse(cfg, NULL); - while(cat) { - if (!strcasecmp(cat, type)) { - foundtype = 1; + if (!varlist) { + ast_cli(fd, "Unable to find notify type '%s'\n", argv[2]); + return RESULT_FAILURE; + } - var = ast_variable_browse(cfg, cat); - while (var) { - add_header(&req, var->name, var->value); - var = var->next; - } - } - cat = ast_category_browse(cfg, cat); - } - ast_destroy(cfg); + for (i = 3; i < argc; i++) { + struct sip_pvt *p; + struct sip_request req; + struct ast_variable *var; - if (foundtype == 0) { - ast_log(LOG_WARNING, "Unable to find notify enter '%s'\n",argv[2]); - return RESULT_SUCCESS; + p = sip_alloc(NULL, NULL, 0); + if (!p) { + ast_log(LOG_WARNING, "Unable to build sip pvt data for notify\n"); + return RESULT_FAILURE; } - strncpy(name, argv[3], sizeof(name) - 1); - if (create_addr(p, name)) { + if (create_addr(p, argv[i])) { /* Maybe they're not registered, etc. */ sip_destroy(p); - return 0; + ast_cli(fd, "Could not create address fo '%s'\n", argv[i]); + continue; } + + initreqprep(&req, p, "NOTIFY", NULL); + + for (var = varlist; var; var = var->next) + add_header(&req, var->name, var->value); + /* Recalculate our side, and recalculate Call ID */ - if (ast_sip_ouraddrfor(&p->sa.sin_addr,&p->ourip)) + if (ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip)) memcpy(&p->ourip, &__ourip, sizeof(p->ourip)); - /* z9hG4bK is a magic cookie. See RFC 3261 section 8.1.1.7 */ - if (ast_test_flag(p, SIP_NAT) & SIP_NAT_RFC3581) - snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x;rport", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch); - else /* UNIDEN UIP200 bug */ - snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch); + build_via(p, p->via, sizeof(p->via)); build_callid(p->callid, sizeof(p->callid), p->ourip, p->fromdomain); - transmit_sip_request(p,&req); + ast_cli(fd, "Sending NOTIFY of type '%s' to '%s'\n", argv[2], argv[i]); + transmit_sip_request(p, &req); sip_scheddestroy(p, 15000); } + return RESULT_SUCCESS; } /*--- sip_do_history: Enable SIP History logging (CLI) ---*/ @@ -6498,6 +6508,7 @@ /*--- sip_no_debug: Disable SIP Debugging in CLI ---*/ static int sip_no_debug(int fd, int argc, char *argv[]) + { if (argc != 3) return RESULT_SHOWUSAGE; @@ -6695,7 +6706,8 @@ static char notify_usage[] = "Usage: sip notify \n" -" Send a notify command to a remote SIP peer\n"; +" Send a NOTIFY message to a SIP peer\n" +" Message types are defined in sip_notify.conf\n"; static char show_users_usage[] = "Usage: sip show users\n" @@ -6764,7 +6776,7 @@ " Shows status of known SIP objects\n"; static struct ast_cli_entry cli_notify = - { { "sip", "notify", NULL }, sip_notify, "Send a notify packet to a SIP peer", notify_usage, complete_sippeer }; + { { "sip", "notify", NULL }, sip_notify, "Send a notify packet to a SIP peer", notify_usage, complete_sipnotify }; static struct ast_cli_entry cli_show_objects = { { "sip", "show", "objects", NULL }, sip_show_objects, "Show all SIP object allocations", show_objects_usage }; static struct ast_cli_entry cli_show_users = @@ -8052,7 +8064,6 @@ /* Called with peerl lock, but releases it */ struct sip_pvt *p; char name[256] = ""; - char iabuf[INET_ADDRSTRLEN]; int newmsgs, oldmsgs; /* Check for messages */ @@ -8080,11 +8091,7 @@ /* Recalculate our side, and recalculate Call ID */ if (ast_sip_ouraddrfor(&p->sa.sin_addr,&p->ourip)) memcpy(&p->ourip, &__ourip, sizeof(p->ourip)); - /* z9hG4bK is a magic cookie. See RFC 3261 section 8.1.1.7 */ - if (ast_test_flag(p, SIP_NAT) & SIP_NAT_RFC3581) - snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x;rport", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch); - else /* UNIDEN UIP200 bug */ - snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch); + build_via(p, p->via, sizeof(p->via)); build_callid(p->callid, sizeof(p->callid), p->ourip, p->fromdomain); /* Send MWI */ ast_set_flag(p, SIP_OUTGOING); @@ -8275,7 +8282,6 @@ static int sip_poke_peer(struct sip_peer *peer) { struct sip_pvt *p; - char iabuf[INET_ADDRSTRLEN]; if (!peer->maxms || !peer->addr.sin_addr.s_addr) { /* IF we have no IP, or this isn't to be monitored, return imeediately after clearing things out */ @@ -8311,11 +8317,7 @@ /* Recalculate our side, and recalculate Call ID */ if (ast_sip_ouraddrfor(&p->sa.sin_addr,&p->ourip)) memcpy(&p->ourip, &__ourip, sizeof(p->ourip)); - /* z9hG4bK is a magic cookie. See RFC 3261 section 8.1.1.7 */ - if (ast_test_flag(p, SIP_NAT) & SIP_NAT_RFC3581) - snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x;rport", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch); - else - snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch); + build_via(p, p->via, sizeof(p->via)); build_callid(p->callid, sizeof(p->callid), p->ourip, p->fromdomain); if (peer->pokeexpire > -1) @@ -8389,7 +8391,6 @@ struct ast_channel *tmpc = NULL; char *ext, *host; char tmp[256] = ""; - char iabuf[INET_ADDRSTRLEN]; char *dest = data; oldformat = format; @@ -8435,11 +8436,7 @@ /* Recalculate our side, and recalculate Call ID */ if (ast_sip_ouraddrfor(&p->sa.sin_addr,&p->ourip)) memcpy(&p->ourip, &__ourip, sizeof(p->ourip)); - /* z9hG4bK is a magic cookie. See RFC 3261 section 8.1.1.7 */ - if (ast_test_flag(p, SIP_NAT) & SIP_NAT_RFC3581) - snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x;rport", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch); - else /* UNIDEN bug */ - snprintf(p->via, sizeof(p->via), "SIP/2.0/UDP %s:%d;branch=z9hG4bK%08x", ast_inet_ntoa(iabuf, sizeof(iabuf), p->ourip), ourport, p->branch); + build_via(p, p->via, sizeof(p->via)); build_callid(p->callid, sizeof(p->callid), p->ourip, p->fromdomain); /* We have an extension to call, don't use the full contact here */ @@ -9159,6 +9156,12 @@ /* Release configuration from memory */ ast_destroy(cfg); + + /* Load the list of manual NOTIFY types to support */ + if (notify_types) + ast_destroy(notify_types); + notify_types = ast_load(notify_config); + return 0; }