diff options
author | Alfred E. Heggestad <aeh@db.org> | 2014-11-01 22:04:34 +0100 |
---|---|---|
committer | Alfred E. Heggestad <aeh@db.org> | 2014-11-01 22:04:34 +0100 |
commit | 0d11889082d7ce823a2965f75ac896c27d62ae25 (patch) | |
tree | 6cca9551c8d58b1fabd60c866fcc5c71334136ca /modules/presence | |
parent | 0a240e73793d84423285930a682984359e725c75 (diff) |
presence/options patch from Juha
most of this work was done by Juha Heinanen, and reviewed by me.
thanks!
- menu: add support for sending SIP OPTIONS requests to any peer,
using the 'o' command
- presence: add support for PUBLISH, set ;pubint=N to activate
- ua: add Allow/Supported header to OPTIONS reply
add MESSAGE to allowed methods
Diffstat (limited to 'modules/presence')
-rw-r--r-- | modules/presence/module.mk | 2 | ||||
-rw-r--r-- | modules/presence/notifier.c | 43 | ||||
-rw-r--r-- | modules/presence/presence.c | 61 | ||||
-rw-r--r-- | modules/presence/presence.h | 7 | ||||
-rw-r--r-- | modules/presence/publisher.c | 277 | ||||
-rw-r--r-- | modules/presence/subscriber.c | 4 |
6 files changed, 349 insertions, 45 deletions
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(¬ifierl); 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; } |