summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/baresip.h1
-rw-r--r--modules/account/account.c1
-rw-r--r--modules/menu/menu.c65
-rw-r--r--modules/presence/module.mk2
-rw-r--r--modules/presence/notifier.c43
-rw-r--r--modules/presence/presence.c61
-rw-r--r--modules/presence/presence.h7
-rw-r--r--modules/presence/publisher.c277
-rw-r--r--modules/presence/subscriber.c4
-rw-r--r--src/account.c9
-rw-r--r--src/contact.c2
-rw-r--r--src/core.h1
-rw-r--r--src/sipreq.c5
-rw-r--r--src/ua.c101
14 files changed, 494 insertions, 85 deletions
diff --git a/include/baresip.h b/include/baresip.h
index 966c618..c2cb29c 100644
--- a/include/baresip.h
+++ b/include/baresip.h
@@ -42,6 +42,7 @@ struct list *account_aucodecl(const struct account *acc);
struct list *account_vidcodecl(const struct account *acc);
struct sip_addr *account_laddr(const struct account *acc);
uint32_t account_regint(const struct account *acc);
+uint32_t account_pubint(const struct account *acc);
/*
diff --git a/modules/account/account.c b/modules/account/account.c
index e92d977..9659bd0 100644
--- a/modules/account/account.c
+++ b/modules/account/account.c
@@ -50,6 +50,7 @@ static int account_write_template(const char *file)
"# ;outbound2=sip:secondary.example.com\n"
"# ;ptime={10,20,30,40,...}\n"
"# ;regint=3600\n"
+ "# ;pubint=0 (publishing off)\n"
"# ;regq=0.5\n"
"# ;rtpkeep={zero,stun,dyna,rtcp}\n"
"# ;sipnat={outbound}\n"
diff --git a/modules/menu/menu.c b/modules/menu/menu.c
index e0e6e22..fd6ef6f 100644
--- a/modules/menu/menu.c
+++ b/modules/menu/menu.c
@@ -213,6 +213,70 @@ static int dial_handler(struct re_printf *pf, void *arg)
}
+static void options_resp_handler(int err, const struct sip_msg *msg, void *arg)
+{
+ (void)arg;
+
+ if (err) {
+ warning("options reply error: %m\n", err);
+ return;
+ }
+
+ if (msg->scode < 200)
+ return;
+
+ if (msg->scode < 300) {
+
+ mbuf_set_pos(msg->mb, 0);
+ info("----- OPTIONS of %r -----\n%b",
+ &(msg->to.auri), mbuf_buf(msg->mb),
+ mbuf_get_left(msg->mb));
+ return;
+ }
+
+ info("%r: OPTIONS failed: %u %r\n", &(msg->to.auri),
+ msg->scode, &msg->reason);
+}
+
+
+static int options_command(struct re_printf *pf, void *arg)
+{
+ const struct cmd_arg *carg = arg;
+ int err = 0;
+
+ (void)pf;
+
+ if (str_isset(carg->prm)) {
+
+ mbuf_rewind(dialbuf);
+ (void)mbuf_write_str(dialbuf, carg->prm);
+
+ err = ua_options_send(uag_cur(), carg->prm,
+ options_resp_handler, NULL);
+ }
+ else if (dialbuf->end > 0) {
+
+ char *uri;
+
+ dialbuf->pos = 0;
+ err = mbuf_strdup(dialbuf, &uri, dialbuf->end);
+ if (err)
+ return err;
+
+ err = ua_options_send(uag_cur(), uri,
+ options_resp_handler, NULL);
+
+ mem_deref(uri);
+ }
+
+ if (err) {
+ warning("menu: ua_options failed: %m\n", err);
+ }
+
+ return err;
+}
+
+
static int cmd_answer(struct re_printf *pf, void *unused)
{
(void)pf;
@@ -290,6 +354,7 @@ static const struct cmd cmdv[] = {
{'l', 0, "List active calls", cmd_print_calls },
{'m', 0, "Module debug", mod_debug },
{'n', 0, "Network debug", net_debug },
+ {'o', CMD_PRM, "Options", options_command },
{'r', 0, "Registration info", ua_print_reg_status },
{'s', 0, "System info", print_system_info },
{'t', 0, "Timer debug", tmr_status },
diff --git a/modules/presence/module.mk b/modules/presence/module.mk
index 6ec5d17..b9b6a22 100644
--- a/modules/presence/module.mk
+++ b/modules/presence/module.mk
@@ -5,7 +5,7 @@
#
MOD := presence
-$(MOD)_SRCS += presence.c subscriber.c notifier.c
+$(MOD)_SRCS += presence.c subscriber.c notifier.c publisher.c
$(MOD)_LFLAGS +=
include mk/mod.mk
diff --git a/modules/presence/notifier.c b/modules/presence/notifier.c
index ced7b75..f9b7c67 100644
--- a/modules/presence/notifier.c
+++ b/modules/presence/notifier.c
@@ -22,7 +22,6 @@ struct notifier {
struct ua *ua;
};
-static enum presence_status my_status = PRESENCE_OPEN;
static struct list notifierl;
static struct sipevent_sock *evsock;
@@ -184,52 +183,19 @@ static int notifier_add(struct sipevent_sock *sock, const struct sip_msg *msg,
}
-static void notifier_update_status(enum presence_status status)
+void notifier_update_status(void)
{
struct le *le;
- if (status == my_status)
- return;
-
- info("presence: update my status from '%s' to '%s'\n",
- contact_presence_str(my_status),
- contact_presence_str(status));
-
- my_status = status;
-
for (le = notifierl.head; le; le = le->next) {
struct notifier *not = le->data;
- (void)notify(not, status);
+ (void)notify(not, my_status);
}
}
-static int cmd_online(struct re_printf *pf, void *arg)
-{
- (void)pf;
- (void)arg;
- notifier_update_status(PRESENCE_OPEN);
- return 0;
-}
-
-
-static int cmd_offline(struct re_printf *pf, void *arg)
-{
- (void)pf;
- (void)arg;
- notifier_update_status(PRESENCE_CLOSED);
- return 0;
-}
-
-
-static const struct cmd cmdv[] = {
- {'[', 0, "Set presence online", cmd_online },
- {']', 0, "Set presence offline", cmd_offline },
-};
-
-
static bool sub_handler(const struct sip_msg *msg, void *arg)
{
struct ua *ua;
@@ -255,16 +221,13 @@ int notifier_init(void)
int err;
err = sipevent_listen(&evsock, uag_sip(), 32, 32, sub_handler, NULL);
- if (err)
- return err;
- return cmd_register(cmdv, ARRAY_SIZE(cmdv));
+ return err;
}
void notifier_close(void)
{
- cmd_unregister(cmdv);
list_flush(&notifierl);
evsock = mem_deref(evsock);
}
diff --git a/modules/presence/presence.c b/modules/presence/presence.c
index 7ed4908..92e982e 100644
--- a/modules/presence/presence.c
+++ b/modules/presence/presence.c
@@ -7,6 +7,56 @@
#include <baresip.h>
#include "presence.h"
+enum presence_status my_status = PRESENCE_OPEN;
+
+
+static int cmd_online(struct re_printf *pf, void *arg)
+{
+ (void)pf;
+ (void)arg;
+
+ if (my_status == PRESENCE_OPEN)
+ return 0;
+
+ info("presence: update my status from '%s' to '%s'\n",
+ contact_presence_str(my_status),
+ contact_presence_str(PRESENCE_OPEN));
+
+ my_status = PRESENCE_OPEN;
+
+ publisher_update_status();
+ notifier_update_status();
+
+ return 0;
+}
+
+
+static int cmd_offline(struct re_printf *pf, void *arg)
+{
+ (void)pf;
+ (void)arg;
+
+ if (my_status == PRESENCE_CLOSED)
+ return 0;
+
+ info("presence: update my status from '%s' to '%s'\n",
+ contact_presence_str(my_status),
+ contact_presence_str(PRESENCE_CLOSED));
+
+ my_status = PRESENCE_CLOSED;
+
+ publisher_update_status();
+ notifier_update_status();
+
+ return 0;
+}
+
+
+static const struct cmd cmdv[] = {
+ {'[', 0, "Set presence online", cmd_online },
+ {']', 0, "Set presence offline", cmd_offline },
+};
+
static int module_init(void)
{
@@ -16,17 +66,26 @@ static int module_init(void)
if (err)
return err;
+ err = publisher_init();
+ if (err)
+ return err;
+
err = notifier_init();
if (err)
return err;
- return 0;
+ return cmd_register(cmdv, ARRAY_SIZE(cmdv));
}
static int module_close(void)
{
+ cmd_unregister(cmdv);
+
+ publisher_close();
+
notifier_close();
+
subscriber_close();
return 0;
diff --git a/modules/presence/presence.h b/modules/presence/presence.h
index a1c5e31..430afde 100644
--- a/modules/presence/presence.h
+++ b/modules/presence/presence.h
@@ -4,6 +4,7 @@
* Copyright (C) 2010 Creytiv.com
*/
+enum presence_status my_status;
int subscriber_init(void);
void subscriber_close(void);
@@ -11,3 +12,9 @@ void subscriber_close(void);
int notifier_init(void);
void notifier_close(void);
+void notifier_update_status(void);
+
+
+int publisher_init(void);
+void publisher_close(void);
+void publisher_update_status(void);
diff --git a/modules/presence/publisher.c b/modules/presence/publisher.c
new file mode 100644
index 0000000..195b055
--- /dev/null
+++ b/modules/presence/publisher.c
@@ -0,0 +1,277 @@
+/**
+ * @file publisher.c Presence Publisher (RFC 3842)
+ *
+ * Copyright (C) 2010 Creytiv.com
+ * Copyright (C) 2014 Juha Heinanen
+ */
+
+#include <string.h>
+#include <re.h>
+#include <baresip.h>
+#include "../../src/core.h"
+#include "presence.h"
+
+
+struct publisher {
+ struct le le;
+ struct tmr tmr;
+ unsigned failc;
+ char *etag;
+ unsigned int expires;
+ unsigned int refresh;
+ struct ua *ua;
+};
+
+static struct list publ = LIST_INIT;
+
+static void tmr_handler(void *arg);
+static int publish(struct publisher *pub);
+
+
+static void response_handler(int err, const struct sip_msg *msg, void *arg)
+{
+ struct publisher *pub = arg;
+ const struct sip_hdr *etag_hdr;
+
+ if (err)
+ return;
+
+ if (msg->scode < 200) {
+ return;
+ }
+
+ if (msg->scode < 300) {
+
+ if (pub->expires == 0)
+ return;
+
+ etag_hdr = sip_msg_xhdr(msg, "SIP-ETag");
+ if (etag_hdr) {
+ mem_deref(pub->etag);
+ pl_strdup(&(pub->etag), &(etag_hdr->val));
+ pub->refresh = 1;
+ tmr_start(&pub->tmr, pub->expires * 900,
+ tmr_handler, pub);
+ }
+ else {
+ warning("%s: publisher got 200 OK without etag\n",
+ ua_aor(pub->ua));
+ }
+ }
+ else if (msg->scode == 412) {
+
+ mem_deref(pub->etag);
+ pub->etag = NULL;
+ pub->refresh = 0;
+ publish(pub);
+
+ }
+ else {
+ warning("%s: publisher got error response %u %r\n",
+ ua_aor(pub->ua), msg->scode, &msg->reason);
+ }
+
+ return;
+}
+
+
+/* move this to presence.c */
+static const char *presence_status_str(enum presence_status st)
+{
+ switch (st) {
+
+ case PRESENCE_OPEN: return "open";
+ case PRESENCE_CLOSED: return "closed";
+ case PRESENCE_UNKNOWN: return "unkown";
+ default: return "?";
+ }
+}
+
+
+static int publish(struct publisher *pub)
+{
+ int err;
+ const char *aor = ua_aor(pub->ua);
+ struct mbuf *mb;
+
+ mb = mbuf_alloc(1024);
+ if (!mb)
+ return ENOMEM;
+
+ if (pub->expires && !pub->refresh)
+ err = mbuf_printf(mb,
+ "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\r\n"
+ "<presence xmlns=\"urn:ietf:params:xml:ns:pidf\"\r\n"
+ " xmlns:dm=\"urn:ietf:params:xml:ns:pidf:data-model\"\r\n"
+ " xmlns:rpid=\"urn:ietf:params:xml:ns:pidf:rpid\"\r\n"
+ " entity=\"%s\">\r\n"
+ " <dm:person id=\"p4159\"><rpid:activities/></dm:person>\r\n"
+ " <tuple id=\"t4109\">\r\n"
+ " <status>\r\n"
+ " <basic>%s</basic>\r\n"
+ " </status>\r\n"
+ " <contact>%s</contact>\r\n"
+ " </tuple>\r\n"
+ "</presence>\r\n"
+ ,aor, presence_status_str(my_status), aor);
+ else
+ err = mbuf_printf(mb, "");
+ if (err)
+ goto out;
+
+ mb->pos = 0;
+
+ /* XXX: can be simplified with 1 function call, by adding a
+ print-handler that prints "SIP-If-Match: ETAG" */
+ if (pub->etag)
+ err = sip_req_send(pub->ua, "PUBLISH", aor,
+ pub->expires ? response_handler : NULL,
+ pub,
+ "%s"
+ "Event: presence\r\n"
+ "Expires: %u\r\n"
+ "SIP-If-Match: %s\r\n"
+ "Content-Length: %zu\r\n"
+ "\r\n"
+ "%b",
+ pub->expires
+ ? "Content-Type: application/pidf+xml\r\n"
+ : "",
+
+ pub->expires,
+ pub->etag,
+ mbuf_get_left(mb),
+ mbuf_buf(mb),
+ mbuf_get_left(mb));
+ else
+ err = sip_req_send(pub->ua, "PUBLISH", aor,
+ pub->expires ? response_handler : NULL,
+ pub,
+ "%s"
+ "Event: presence\r\n"
+ "Expires: %u\r\n"
+ "Content-Length: %zu\r\n"
+ "\r\n"
+ "%b",
+ pub->expires
+ ? "Content-Type: application/pidf+xml\r\n"
+ : "",
+ pub->expires,
+ mbuf_get_left(mb),
+ mbuf_buf(mb),
+ mbuf_get_left(mb));
+ if (err) {
+ warning("publisher: send PUBLISH: (%m)\n", err);
+ }
+
+out:
+ mem_deref(mb);
+
+ return err;
+}
+
+
+/* move to presence.c */
+static uint32_t wait_fail(unsigned failc)
+{
+ switch (failc) {
+
+ case 1: return 30;
+ case 2: return 300;
+ case 3: return 3600;
+ default: return 86400;
+ }
+}
+
+
+static void tmr_handler(void *arg)
+{
+ struct publisher *pub = arg;
+
+ if (publish(pub)) {
+ tmr_start(&pub->tmr, wait_fail(++pub->failc) * 1000,
+ tmr_handler, pub);
+ }
+}
+
+
+static void destructor(void *arg)
+{
+ struct publisher *pub = arg;
+
+ list_unlink(&pub->le);
+ tmr_cancel(&pub->tmr);
+ mem_deref(pub->ua);
+ mem_deref(pub->etag);
+}
+
+
+void publisher_update_status(void)
+{
+ struct le *le;
+
+ for (le = publ.head; le; le = le->next) {
+
+ struct publisher *pub = le->data;
+
+ pub->refresh = 0;
+ publish(pub);
+ }
+}
+
+
+static int publisher_alloc(struct ua *ua)
+{
+ struct publisher *pub;
+
+ pub = mem_zalloc(sizeof(*pub), destructor);
+ if (!pub)
+ return ENOMEM;
+
+ pub->ua = mem_ref(ua);
+ pub->expires = account_pubint(ua_account(ua));
+
+ tmr_init(&pub->tmr);
+ tmr_start(&pub->tmr, 100, tmr_handler, pub);
+
+ list_append(&publ, &pub->le, pub);
+
+ return 0;
+}
+
+
+int publisher_init(void)
+{
+ struct le *le;
+ int err = 0;
+
+ for (le = list_head(uag_list()); le; le = le->next) {
+
+ struct ua *ua = le->data;
+ struct account *acc = ua_account(ua);
+
+ if (account_pubint(acc) > 0)
+ err |= publisher_alloc(ua);
+ }
+
+ if (err)
+ return err;
+
+ return 0;
+}
+
+
+void publisher_close(void)
+{
+ struct le *le;
+
+ for (le = list_head(&publ); le; le = le->next) {
+
+ struct publisher *pub = le->data;
+
+ pub->expires = 0;
+ publish(pub);
+ }
+
+ list_flush(&publ);
+}
diff --git a/modules/presence/subscriber.c b/modules/presence/subscriber.c
index 418d0d0..66c15a2 100644
--- a/modules/presence/subscriber.c
+++ b/modules/presence/subscriber.c
@@ -111,9 +111,7 @@ static void notify_handler(struct sip *sip, const struct sip_msg *msg,
}
if (!re_regex((const char *)mbuf_buf(msg->mb), mbuf_get_left(msg->mb),
- "<status>[^<]*<basic>[^<]*</basic>[^<]*</status>",
- NULL, &pl, NULL)) {
-
+ "<basic>[^<]+</basic>", &pl)) {
if (!pl_strcasecmp(&pl, "open"))
status = PRESENCE_OPEN;
}
diff --git a/src/account.c b/src/account.c
index fed2b00..0269b04 100644
--- a/src/account.c
+++ b/src/account.c
@@ -279,6 +279,9 @@ static int sip_params_decode(struct account *acc, const struct sip_addr *aor)
acc->regint = REG_INTERVAL + (rand_u32()&0xff);
err |= param_u32(&acc->regint, &aor->params, "regint");
+ acc->pubint = 0;
+ err |= param_u32(&acc->pubint, &aor->params, "pubint");
+
err |= param_dstr(&acc->regq, &aor->params, "regq");
for (i=0; i<ARRAY_SIZE(acc->outbound); i++) {
@@ -510,6 +513,12 @@ uint32_t account_regint(const struct account *acc)
}
+uint32_t account_pubint(const struct account *acc)
+{
+ return acc ? acc->pubint : 0;
+}
+
+
static const char *answermode_str(enum answermode mode)
{
switch (mode) {
diff --git a/src/contact.c b/src/contact.c
index 5161a1c..c06c7a1 100644
--- a/src/contact.c
+++ b/src/contact.c
@@ -128,7 +128,7 @@ const char *contact_presence_str(enum presence_status status)
switch (status) {
default:
- case PRESENCE_UNKNOWN: return "\x1b[32m\x1b[;m";
+ case PRESENCE_UNKNOWN: return "\x1b[32mUnknown\x1b[;m";
case PRESENCE_OPEN: return "\x1b[32mOnline\x1b[;m";
case PRESENCE_CLOSED: return "\x1b[31mOffline\x1b[;m";
case PRESENCE_BUSY: return "\x1b[31mBusy\x1b[;m";
diff --git a/src/core.h b/src/core.h
index f8c21ac..2f64192 100644
--- a/src/core.h
+++ b/src/core.h
@@ -58,6 +58,7 @@ struct account {
char *outbound[2]; /**< Optional SIP outbound proxies */
uint32_t ptime; /**< Configured packet time in [ms] */
uint32_t regint; /**< Registration interval in [seconds] */
+ uint32_t pubint; /**< Publication interval in [seconds] */
char *regq; /**< Registration Q-value */
char *rtpkeep; /**< RTP Keepalive mechanism */
char *sipnat; /**< SIP Nat mechanism */
diff --git a/src/sipreq.c b/src/sipreq.c
index 1518645..c1510b6 100644
--- a/src/sipreq.c
+++ b/src/sipreq.c
@@ -73,7 +73,8 @@ static void resp_handler(int err, const struct sip_msg *msg, void *arg)
}
out:
- sr->resph(err, msg, sr->arg);
+ if (sr->resph)
+ sr->resph(err, msg, sr->arg);
/* destroy now */
mem_deref(sr);
@@ -104,7 +105,7 @@ int sip_req_send(struct ua *ua, const char *method, const char *uri,
struct sip_req *sr;
int err;
- if (!ua || !method || !uri || !resph || !fmt)
+ if (!ua || !method || !uri || !fmt)
return EINVAL;
routev[0] = ua_outbound(ua);
diff --git a/src/ua.c b/src/ua.c
index be4c425..d7592f0 100644
--- a/src/ua.c
+++ b/src/ua.c
@@ -394,16 +394,19 @@ static void handle_options(struct ua *ua, const struct sip_msg *msg)
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);
}
@@ -586,6 +589,47 @@ int ua_alloc(struct ua **uap, const char *aor)
}
+static int uri_complete(struct ua *ua, struct mbuf *buf, const char *uri)
+{
+ size_t len;
+ int err = 0;
+
+ len = str_len(uri);
+
+ /* Append sip: scheme if missing */
+ if (0 != re_regex(uri, len, "sip:"))
+ err |= mbuf_printf(buf, "sip:");
+
+ err |= mbuf_write_str(buf, uri);
+
+ /* Append domain if missing */
+ if (0 != re_regex(uri, len, "[^@]+@[^]+", NULL, NULL)) {
+#if HAVE_INET6
+ if (AF_INET6 == ua->acc->luri.af)
+ err |= mbuf_printf(buf, "@[%r]",
+ &ua->acc->luri.host);
+ else
+#endif
+ err |= mbuf_printf(buf, "@%r",
+ &ua->acc->luri.host);
+
+ /* Also append port if specified and not 5060 */
+ switch (ua->acc->luri.port) {
+
+ case 0:
+ case SIP_PORT:
+ break;
+
+ default:
+ err |= mbuf_printf(buf, ":%u", ua->acc->luri.port);
+ break;
+ }
+ }
+
+ return err;
+}
+
+
/**
* Connect an outgoing call to a given SIP uri
*
@@ -605,14 +649,11 @@ int ua_connect(struct ua *ua, struct call **callp,
struct call *call = NULL;
struct mbuf *dialbuf;
struct pl pl;
- size_t len;
int err = 0;
if (!ua || !str_isset(uri))
return EINVAL;
- len = str_len(uri);
-
dialbuf = mbuf_alloc(64);
if (!dialbuf)
return ENOMEM;
@@ -620,35 +661,7 @@ int ua_connect(struct ua *ua, struct call **callp,
if (params)
err |= mbuf_printf(dialbuf, "<");
- /* Append sip: scheme if missing */
- if (0 != re_regex(uri, len, "sip:"))
- err |= mbuf_printf(dialbuf, "sip:");
-
- err |= mbuf_write_str(dialbuf, uri);
-
- /* Append domain if missing */
- if (0 != re_regex(uri, len, "[^@]+@[^]+", NULL, NULL)) {
-#if HAVE_INET6
- if (AF_INET6 == ua->acc->luri.af)
- err |= mbuf_printf(dialbuf, "@[%r]",
- &ua->acc->luri.host);
- else
-#endif
- err |= mbuf_printf(dialbuf, "@%r",
- &ua->acc->luri.host);
-
- /* Also append port if specified and not 5060 */
- switch (ua->acc->luri.port) {
-
- case 0:
- case SIP_PORT:
- break;
-
- default:
- err |= mbuf_printf(dialbuf, ":%u", ua->acc->luri.port);
- break;
- }
- }
+ err |= uri_complete(ua, dialbuf, uri);
if (params) {
err |= mbuf_printf(dialbuf, ";%s", params);
@@ -771,12 +784,23 @@ int ua_print_status(struct re_printf *pf, const struct ua *ua)
int ua_options_send(struct ua *ua, const char *uri,
options_resp_h *resph, void *arg)
{
- int err;
+ struct mbuf *dialbuf;
+ int err = 0;
- if (!ua)
+ (void)arg;
+
+ if (!ua || !str_isset(uri))
return EINVAL;
- err = sip_req_send(ua, "OPTIONS", uri, resph, arg,
+ dialbuf = mbuf_alloc(64);
+ if (!dialbuf)
+ return ENOMEM;
+
+ err |= uri_complete(ua, dialbuf, uri);
+
+ dialbuf->buf[dialbuf->end] = '\0';
+
+ err = sip_req_send(ua, "OPTIONS", (char *)dialbuf->buf, resph, NULL,
"Accept: application/sdp\r\n"
"Content-Length: 0\r\n"
"\r\n");
@@ -784,6 +808,8 @@ int ua_options_send(struct ua *ua, const char *uri,
warning("ua: send options: (%m)\n", err);
}
+ mem_deref(dialbuf);
+
return err;
}
@@ -1542,7 +1568,8 @@ struct list *uag_list(void)
*/
const char *uag_allowed_methods(void)
{
- return "INVITE,ACK,BYE,CANCEL,OPTIONS,REFER,NOTIFY,SUBSCRIBE,INFO";
+ return "INVITE,ACK,BYE,CANCEL,OPTIONS,REFER,"
+ "NOTIFY,SUBSCRIBE,INFO,MESSAGE";
}