static void sipsess_refer_handler(struct sip *sip, const struct sip_msg *msg, void *arg) { struct call *call = arg; const struct sip_hdr *hdr; int err; /* get the transfer target */ hdr = sip_msg_hdr(msg, SIP_HDR_REFER_TO); if (!hdr) { warning("call: bad REFER request from %r\n", &msg->from.auri); (void)sip_reply(sip, msg, 400, "Missing Refer-To header"); return; } /* The REFER creates an implicit subscription. * Reply 202 to the REFER request */ call->not = mem_deref(call->not); err = sipevent_accept(&call->not, uag_sipevent_sock(), msg, sipsess_dialog(call->sess), NULL, 202, "Accepted", 60, 60, 60, ua_cuser(call->ua), "message/sipfrag", auth_handler, call->acc, true, sipnot_close_handler, call, "Allow: %s\r\n", uag_allowed_methods()); if (err) { warning("call: refer: sipevent_accept failed: %m\n", err); return; } (void)call_notify_sipfrag(call, 100, "Trying"); call_event_handler(call, CALL_EVENT_TRANSFER, "%r", &hdr->val); }
/** * Transfer the call to a target SIP uri * * @param call Call object * @param uri Target SIP uri * * @return 0 if success, otherwise errorcode */ int call_transfer(struct call *call, const char *uri) { char *nuri; int err; if (!call || !uri) return EINVAL; err = normalize_uri(&nuri, uri, &call->acc->luri); if (err) return err; info("transferring call to %s\n", nuri); call->sub = mem_deref(call->sub); err = sipevent_drefer(&call->sub, uag_sipevent_sock(), sipsess_dialog(call->sess), ua_cuser(call->ua), auth_handler, call->acc, true, sipsub_notify_handler, sipsub_close_handler, call, "Refer-To: %s\r\n", nuri); if (err) { warning("call: sipevent_drefer: %m\n", err); } mem_deref(nuri); return err; }
static int mwi_subscribe(struct ua *ua) { const char *routev[1]; struct mwi *mwi; int err; mwi = mem_zalloc(sizeof(*mwi), destructor); if (!mwi) return ENOMEM; list_append(&mwil, &mwi->le, mwi); mwi->ua = ua; routev[0] = ua_outbound(ua); info("mwi: subscribing to messages for %s\n", ua_aor(ua)); err = sipevent_subscribe(&mwi->sub, uag_sipevent_sock(), ua_aor(ua), NULL, ua_aor(ua), "message-summary", NULL, 600, ua_cuser(ua), routev, routev[0] ? 1 : 0, auth_handler, ua_prm(ua), true, NULL, notify_handler, close_handler, mwi, "Accept:" " application/simple-message-summary\r\n"); if (err) { warning("mwi: subscribe ERROR: %m\n", err); } if (err) mem_deref(mwi); return err; }
static int subscribe(struct presence *pres) { const char *routev[1]; struct ua *ua; char uri[256]; int err; /* We use the first UA */ ua = uag_find_aor(NULL); if (!ua) { warning("presence: no UA found\n"); return ENOENT; } pl_strcpy(&contact_addr(pres->contact)->auri, uri, sizeof(uri)); routev[0] = ua_outbound(ua); err = sipevent_subscribe(&pres->sub, uag_sipevent_sock(), uri, NULL, ua_aor(ua), "presence", NULL, 600, ua_cuser(ua), routev, routev[0] ? 1 : 0, auth_handler, ua_prm(ua), true, NULL, notify_handler, close_handler, pres, "%H", ua_print_supported, ua); if (err) { warning("presence: sipevent_subscribe failed: %m\n", err); } return err; }
static void handle_options(struct ua *ua, const struct sip_msg *msg) { struct sip_contact contact; struct call *call = NULL; struct mbuf *desc = NULL; int err; err = ua_call_alloc(&call, ua, VIDMODE_ON, NULL, NULL, NULL); if (err) { (void)sip_treply(NULL, uag.sip, msg, 500, "Call Error"); return; } err = call_sdp_get(call, &desc, true); if (err) goto out; sip_contact_set(&contact, ua_cuser(ua), &msg->dst, msg->tp); err = sip_treplyf(NULL, NULL, uag.sip, msg, true, 200, "OK", "Allow: %s\r\n" "%H" "%H" "Content-Type: application/sdp\r\n" "Content-Length: %zu\r\n" "\r\n" "%b", uag_allowed_methods(), ua_print_supported, ua, sip_contact_print, &contact, mbuf_get_left(desc), mbuf_buf(desc), mbuf_get_left(desc)); if (err) { warning("ua: options: sip_treplyf: %m\n", err); } out: mem_deref(desc); mem_deref(call); }
static int send_invite(struct call *call) { const char *routev[1]; struct mbuf *desc; int err; routev[0] = ua_outbound(call->ua); err = call_sdp_get(call, &desc, true); if (err) return err; err = sipsess_connect(&call->sess, uag_sipsess_sock(), call->peer_uri, call->local_name, call->local_uri, ua_cuser(call->ua), routev[0] ? routev : NULL, routev[0] ? 1 : 0, "application/sdp", desc, auth_handler, call->acc, true, sipsess_offer_handler, sipsess_answer_handler, sipsess_progr_handler, sipsess_estab_handler, sipsess_info_handler, sipsess_refer_handler, sipsess_close_handler, call, "Allow: %s\r\n%H", uag_allowed_methods(), ua_print_supported, call->ua); if (err) { warning("call: sipsess_connect: %m\n", err); } /* save call setup timer */ call->time_conn = time(NULL); mem_deref(desc); return err; }
static int notifier_alloc(struct notifier **notp, struct sipevent_sock *sock, const struct sip_msg *msg, const struct sipevent_event *se, struct ua *ua) { struct notifier *not; int err; if (!sock || !msg || !se) return EINVAL; not = mem_zalloc(sizeof(*not), destructor); if (!not) return ENOMEM; not->sock = mem_ref(sock); not->ua = mem_ref(ua); err = sipevent_accept(¬->not, sock, msg, NULL, se, 200, "OK", 600, 600, 600, ua_cuser(not->ua), "application/pidf+xml", auth_handler, ua_prm(not->ua), true, sipnot_close_handler, not, NULL); if (err) { warning("presence: sipevent_accept failed: %m\n", err); goto out; } list_append(¬ifierl, ¬->le, not); out: if (err) mem_deref(not); else if (notp) *notp = not; return err; }
int call_accept(struct call *call, struct sipsess_sock *sess_sock, const struct sip_msg *msg) { bool got_offer; int err; if (!call || !msg) return EINVAL; call->outgoing = false; got_offer = (mbuf_get_left(msg->mb) > 0); err = pl_strdup(&call->peer_uri, &msg->from.auri); if (err) return err; if (pl_isset(&msg->from.dname)) { err = pl_strdup(&call->peer_name, &msg->from.dname); if (err) return err; } if (got_offer) { struct sdp_media *m; const struct sa *raddr; err = sdp_decode(call->sdp, msg->mb, true); if (err) return err; call->got_offer = true; /* * Each media description in the SDP answer MUST * use the same network type as the corresponding * media description in the offer. * * See RFC 6157 */ m = stream_sdpmedia(audio_strm(call->audio)); raddr = sdp_media_raddr(m); if (sa_af(raddr) != call->af) { info("call: incompatible address-family" " (local=%s, remote=%s)\n", net_af2name(call->af), net_af2name(sa_af(raddr))); sip_treply(NULL, uag_sip(), msg, 488, "Not Acceptable Here"); call_event_handler(call, CALL_EVENT_CLOSED, "Wrong address family"); return 0; } /* Check if we have any common audio codecs, after * the SDP offer has been parsed */ if (!have_common_audio_codecs(call)) { info("call: no common audio codecs - rejected\n"); sip_treply(NULL, uag_sip(), msg, 488, "Not Acceptable Here"); call_event_handler(call, CALL_EVENT_CLOSED, "No audio codecs"); return 0; } } err = sipsess_accept(&call->sess, sess_sock, msg, 180, "Ringing", ua_cuser(call->ua), "application/sdp", NULL, auth_handler, call->acc, true, sipsess_offer_handler, sipsess_answer_handler, sipsess_estab_handler, sipsess_info_handler, sipsess_refer_handler, sipsess_close_handler, call, "Allow: %s\r\n", uag_allowed_methods()); if (err) { warning("call: sipsess_accept: %m\n", err); return err; } set_state(call, STATE_INCOMING); /* New call */ tmr_start(&call->tmr_inv, LOCAL_TIMEOUT*1000, invite_timeout, call); if (!call->acc->mnat) call_event_handler(call, CALL_EVENT_INCOMING, call->peer_uri); return err; }
int call_accept(struct call *call, struct sipsess_sock *sess_sock, const struct sip_msg *msg) { bool got_offer; int err; if (!call || !msg) return EINVAL; got_offer = (mbuf_get_left(msg->mb) > 0); err = pl_strdup(&call->peer_uri, &msg->from.auri); if (err) return err; if (pl_isset(&msg->from.dname)) { err = pl_strdup(&call->peer_name, &msg->from.dname); if (err) return err; } if (got_offer) { err = sdp_decode(call->sdp, msg->mb, true); if (err) return err; call->got_offer = true; /* Check if we have any common audio codecs, after * the SDP offer has been parsed */ if (!have_common_audio_codecs(call)) { info("call: no common audio codecs - rejected\n"); sip_treply(NULL, uag_sip(), msg, 488, "Not Acceptable Here"); call_event_handler(call, CALL_EVENT_CLOSED, "No audio codecs"); return 0; } } err = sipsess_accept(&call->sess, sess_sock, msg, 180, "Ringing", ua_cuser(call->ua), "application/sdp", NULL, auth_handler, call->acc, true, sipsess_offer_handler, sipsess_answer_handler, sipsess_estab_handler, sipsess_info_handler, sipsess_refer_handler, sipsess_close_handler, call, "Allow: %s\r\n", uag_allowed_methods()); if (err) { warning("call: sipsess_accept: %m\n", err); return err; } set_state(call, STATE_INCOMING); /* New call */ tmr_start(&call->tmr_inv, LOCAL_TIMEOUT*1000, invite_timeout, call); if (!call->acc->mnat) call_event_handler(call, CALL_EVENT_INCOMING, call->peer_uri); return err; }