diff -Naur asterisk-89312.orig/channels/chan_sip.c asterisk-89312.patched-9896/channels/chan_sip.c --- asterisk-89312.orig/channels/chan_sip.c 2007-11-16 09:42:34.000000000 +0600 +++ asterisk-89312.patched-9896/channels/chan_sip.c 2007-11-16 10:31:43.000000000 +0600 @@ -1088,6 +1088,7 @@ struct ast_channel *owner; /*!< Who owns us (if we have an owner) */ struct sip_route *route; /*!< Head of linked list of routing steps (fm Record-Route) */ int route_persistant; /*!< Is this the "real" route? */ + struct ast_variable *notify_headers; /*!< Custom notify type */ struct sip_auth *peerauth; /*!< Realm authentication */ int noncecount; /*!< Nonce-count */ char lastmsg[256]; /*!< Last Message sent/received */ @@ -1485,7 +1486,6 @@ static int __sip_reliable_xmit(struct sip_pvt *p, int seqno, int resp, char *data, int len, int fatal, int sipmethod); static int __transmit_response(struct sip_pvt *p, const char *msg, const struct sip_request *req, enum xmittype reliable); static int retrans_pkt(const void *data); -static int transmit_sip_request(struct sip_pvt *p, struct sip_request *req); static int transmit_response_using_temp(ast_string_field callid, struct sockaddr_in *sin, int useglobal_nat, const int intended_method, const struct sip_request *req, const char *msg); static int transmit_response(struct sip_pvt *p, const char *msg, const struct sip_request *req); static int transmit_response_reliable(struct sip_pvt *p, const char *msg, const struct sip_request *req); @@ -1771,6 +1771,7 @@ /*------Response handling functions */ static void handle_response_invite(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno); +static void handle_response_notify(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno); static void handle_response_refer(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno); static int handle_response_register(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno); static void handle_response(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno); @@ -3646,7 +3647,10 @@ ast_sched_del(sched, p->initid); if (p->autokillid > -1) ast_sched_del(sched, p->autokillid); - + if (p->notify_headers) { + ast_variables_destroy(p->notify_headers); + p->notify_headers = NULL; + } if (p->rtp) ast_rtp_destroy(p->rtp); if (p->vrtp) @@ -7757,6 +7761,7 @@ static int transmit_invite(struct sip_pvt *p, int sipmethod, int sdp, int init) { struct sip_request req; + struct ast_variable *var; req.method = sipmethod; if (init) {/* Bump branch even on initial requests */ @@ -7770,7 +7775,6 @@ if (p->options && p->options->auth) add_header(&req, p->options->authheader, p->options->auth); - append_date(&req); if (sipmethod == SIP_REFER) { /* Call transfer */ if (p->refer) { char buf[BUFSIZ]; @@ -7788,9 +7792,19 @@ add_header(&req, "Replaces", p->options->replaces); add_header(&req, "Require", "replaces"); } + if(p->notify_headers) { + for (var = p->notify_headers; var; var = var->next) { + char buf[512]; + ast_copy_string(buf, var->value, sizeof(buf)); + ast_debug(1, " Adding pair %s=%s\n", var->name, var->value); + add_header(&req, var->name, ast_unescape_semicolon(buf)); + } + } else { + append_date(&req); + add_header(&req, "Allow", ALLOWED_METHODS); + add_header(&req, "Supported", SUPPORTED_EXTENSIONS); + } - add_header(&req, "Allow", ALLOWED_METHODS); - add_header(&req, "Supported", SUPPORTED_EXTENSIONS); if (p->options && p->options->addsipheaders && p->owner) { struct ast_channel *chan = p->owner; /* The owner channel */ struct varshead *headp; @@ -7839,7 +7853,8 @@ } else if (p->rtp) add_sdp(&req, p); } else { - add_header_contentLength(&req, 0); + if(!p->notify_headers) + add_header_contentLength(&req, 0); } if (!p->initreq.headers) @@ -8068,14 +8083,6 @@ return send_request(p, &req, XMIT_RELIABLE, p->ocseq); } -/*! \brief Transmit SIP request unreliably (only used in sip_notify subsystem) */ -static int transmit_sip_request(struct sip_pvt *p, struct sip_request *req) -{ - if (!p->initreq.headers) /* Initialize first request before sending */ - initialize_initreq(p, req); - return send_request(p, req, XMIT_UNRELIABLE, p->ocseq); -} - /*! \brief Notify a transferring party of the status of transfer */ static int transmit_notify_with_sipfrag(struct sip_pvt *p, int cseq, char *message, int terminate) { @@ -12604,7 +12611,7 @@ for (i = 3; i < a->argc; i++) { struct sip_pvt *p; struct sip_request req; - struct ast_variable *var; + struct ast_variable *var, *newvar; if (!(p = sip_alloc(NULL, NULL, 0, SIP_NOTIFY))) { ast_log(LOG_WARNING, "Unable to build sip pvt data for notify (memory/socket error)\n"); @@ -12618,22 +12625,33 @@ continue; } + /* Notify is outgoing call */ + ast_set_flag(&p->flags[0], SIP_OUTGOING); + + /* Recalculate our side, and recalculate Call ID */ + ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip); + build_via(p); + build_callid_pvt(p); initreqprep(&req, p, SIP_NOTIFY); + /* Copy notify vars and add headers */ + add_header(&req, "Subscription-State", "terminated"); + p->notify_headers = newvar = ast_variable_new("Subscription-State", "terminated", ""); for (var = varlist; var; var = var->next) { char buf[512]; ast_copy_string(buf, var->value, sizeof(buf)); + ast_debug(1, " Adding pair %s=%s\n", var->name, var->value); add_header(&req, var->name, ast_unescape_semicolon(buf)); + newvar->next = ast_variable_new(var->name, var->value, ""); + newvar = newvar->next; } - - /* Recalculate our side, and recalculate Call ID */ - ast_sip_ouraddrfor(&p->sa.sin_addr, &p->ourip); - build_via(p); - build_callid_pvt(p); ast_cli(a->fd, "Sending NOTIFY of type '%s' to '%s'\n", a->argv[2], a->argv[i]); - transmit_sip_request(p, &req); - sip_scheddestroy(p, DEFAULT_TRANS_TIMEOUT); - dialog_unref(p); + + if (!p->initreq.headers) /* Initialize first request before sending */ + initialize_initreq(p, &req); // transmit_invite is now like swiss-army-knife + + send_request(p, &req, XMIT_UNRELIABLE, p->ocseq); + sip_scheddestroy(p, SIP_TRANS_TIMEOUT); } return CLI_SUCCESS; @@ -13511,6 +13529,42 @@ ast_log(LOG_WARNING, "Could not transmit message in dialog %s\n", p->callid); } +/* \brief Handle SIP response in NOTIFY transaction + We've sent a NOTIFY, now handle responses to it + */ +static void handle_response_notify(struct sip_pvt *p, int resp, char *rest, struct sip_request *req, int seqno) +{ + switch (resp) { + case 200: /* Notify accepted */ + if (option_debug > 2) + ast_log(LOG_DEBUG, "Got 200 accepted on notify\n"); + /* Now we can destroy this dialog */ + p->needdestroy = 1; + break; + case 401: /* Not www-authorized on SIP method */ + case 407: /* Proxy auth */ + ast_string_field_set(p, theirtag, NULL); + if (ast_strlen_zero(p->authname)) { + ast_log(LOG_WARNING, "Asked to authenticate NOTIFY to %s:%d but we have no matching peer or realm auth!\n", ast_inet_ntoa(p->recv.sin_addr), ntohs(p->recv.sin_port)); + p->needdestroy = 1; + } + if (p->authtries > 1 || do_proxy_auth(p, req, resp, SIP_NOTIFY, 0)) { + ast_log(LOG_NOTICE, "Failed to authenticate on NOTYFY to '%s'\n", get_header(&p->initreq, "From")); + p->needdestroy = 1; + } + break; + case 481: /* Call leg does not exist */ + ast_log(LOG_WARNING, "Remote host can't match NOTIFY request to call '%s'. Giving up.\n", p->callid); + p->needdestroy = 1; + break; + case 500: /* Server error */ + case 501: /* Method not implemented */ + ast_log(LOG_NOTICE, "SIP notify to %s failed. \n", p->refer->refer_to); + p->needdestroy = 1; + break; + } +} + /* \brief Handle SIP response in REFER transaction We've sent a REFER, now handle responses to it */ @@ -13875,6 +13929,8 @@ case 407: /* Proxy auth required */ if (sipmethod == SIP_INVITE) handle_response_invite(p, resp, rest, req, seqno); + else if (sipmethod == SIP_NOTIFY) + handle_response_notify(p, resp, rest, req, seqno); else if (sipmethod == SIP_REFER) handle_response_refer(p, resp, rest, req, seqno); else if (p->registry && sipmethod == SIP_REGISTER) diff -Naur asterisk-89312.orig/configs/sip_notify.conf.sample asterisk-89312.patched-9896/configs/sip_notify.conf.sample --- asterisk-89312.orig/configs/sip_notify.conf.sample 2007-11-16 09:42:38.000000000 +0600 +++ asterisk-89312.patched-9896/configs/sip_notify.conf.sample 2007-11-16 09:51:39.000000000 +0600 @@ -2,11 +2,18 @@ Event=>check-sync Content-Length=>0 -; Untested [sipura-check-cfg] Event=>resync Content-Length=>0 +[linksys-cold-restart] +Event=>reboot_now +Content-Length=>0 + +[linksys-warm-restart] +Event=>restart_now +Content-Length=>0 + ; Untested [grandstream-check-cfg] Event=>sys-control @@ -16,7 +23,6 @@ Event=>check-sync Content-Length=>0 -; Tested [snom-check-cfg] Event=>check-sync\;reboot=false Content-Length=>0