Merge some more changes from team/russell/events
[asterisk/asterisk.git] / main / event.c
index 4855e43..2ce4464 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * Asterisk -- An open source telephony toolkit.
  *
- * Copyright (C) 2007, Digium, Inc.
+ * Copyright (C) 2007 - 2008, Digium, Inc.
  *
  * Russell Bryant <russell@digium.com>
  *
@@ -34,6 +34,7 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include "asterisk/lock.h"
 #include "asterisk/utils.h"
 #include "asterisk/unaligned.h"
+#include "asterisk/utils.h"
 #include "asterisk/taskprocessor.h"
 
 struct ast_taskprocessor *event_dispatcher;
@@ -78,12 +79,6 @@ struct ast_event_ref {
        AST_LIST_ENTRY(ast_event_ref) entry;
 };
 
-struct ast_event_iterator {
-       uint16_t event_len;
-       const struct ast_event *event;
-       struct ast_event_ie *ie;
-};
-
 struct ast_event_ie_val {
        AST_LIST_ENTRY(ast_event_ie_val) entry;
        enum ast_event_ie_type ie_type;
@@ -91,7 +86,9 @@ struct ast_event_ie_val {
        union {
                uint32_t uint;
                const char *str;
+               void *raw;
        } payload;
+       size_t raw_datalen;
 };
 
 /*! \brief Event subscription */
@@ -116,10 +113,128 @@ static AST_RWDLLIST_HEAD(ast_event_sub_list, ast_event_sub) ast_event_subs[AST_E
  * needs to know this state, it can get the last known state from the cache. */
 static AST_RWLIST_HEAD(ast_event_ref_list, ast_event_ref) ast_event_cache[AST_EVENT_TOTAL];
 
+/*!
+ * The index of each entry _must_ match the event type number!
+ */
+static struct event_name {
+       enum ast_event_type type;
+       const char *name;
+} event_names[] = {
+       { 0, "" },
+       { AST_EVENT_CUSTOM,              "Custom" },
+       { AST_EVENT_MWI,                 "MWI" },
+       { AST_EVENT_SUB,                 "Subscription" },
+       { AST_EVENT_UNSUB,               "Unsubscription" },
+       { AST_EVENT_DEVICE_STATE,        "DeviceState" },
+       { AST_EVENT_DEVICE_STATE_CHANGE, "DeviceStateChange" },
+};
+
+/*!
+ * The index of each entry _must_ match the event ie number!
+ */
+static struct ie_map {
+       enum ast_event_ie_type ie_type;
+       enum ast_event_ie_pltype ie_pltype;
+       const char *name;
+} ie_maps[] = {
+       { 0, 0, "" },
+       { AST_EVENT_IE_NEWMSGS,   AST_EVENT_IE_PLTYPE_UINT, "NewMessages" },
+       { AST_EVENT_IE_OLDMSGS,   AST_EVENT_IE_PLTYPE_UINT, "OldMessages" },
+       { AST_EVENT_IE_MAILBOX,   AST_EVENT_IE_PLTYPE_STR,  "Mailbox" },
+       { AST_EVENT_IE_UNIQUEID,  AST_EVENT_IE_PLTYPE_UINT, "UniqueID" },
+       { AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, "EventType" },
+       { AST_EVENT_IE_EXISTS,    AST_EVENT_IE_PLTYPE_UINT, "Exists" },
+       { AST_EVENT_IE_DEVICE,    AST_EVENT_IE_PLTYPE_STR,  "Device" },
+       { AST_EVENT_IE_STATE,     AST_EVENT_IE_PLTYPE_UINT, "State" },
+       { AST_EVENT_IE_CONTEXT,   AST_EVENT_IE_PLTYPE_STR,  "Context" },
+       { AST_EVENT_IE_EID,       AST_EVENT_IE_PLTYPE_RAW,  "EntityID" },
+};
+
+const char *ast_event_get_type_name(const struct ast_event *event)
+{
+       enum ast_event_type type;
+
+       type = ast_event_get_type(event);
+
+       if (type >= AST_EVENT_TOTAL || type < 0) {
+               ast_log(LOG_ERROR, "Invalid event type - '%d'\n", type);
+               return "";
+       }
+
+       return event_names[type].name;
+}
+
+int ast_event_str_to_event_type(const char *str, enum ast_event_type *event_type)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_LEN(event_names); i++) {
+               if (strcasecmp(event_names[i].name, str))
+                       continue;
+
+               *event_type = event_names[i].type;
+               return 0;
+       }
+
+       return -1;
+}
+
+const char *ast_event_get_ie_type_name(enum ast_event_ie_type ie_type)
+{
+       if (ie_type <= 0 || ie_type > AST_EVENT_IE_MAX) {
+               ast_log(LOG_ERROR, "Invalid IE type - '%d'\n", ie_type);
+               return "";
+       }
+
+       return ie_maps[ie_type].name;
+}
+
+enum ast_event_ie_pltype ast_event_get_ie_pltype(enum ast_event_ie_type ie_type)
+{
+       if (ie_type <= 0 || ie_type > AST_EVENT_IE_MAX) {
+               ast_log(LOG_ERROR, "Invalid IE type - '%d'\n", ie_type);
+               return AST_EVENT_IE_PLTYPE_UNKNOWN;
+       }
+
+       return ie_maps[ie_type].ie_pltype;
+}
+
+int ast_event_str_to_ie_type(const char *str, enum ast_event_ie_type *ie_type)
+{
+       int i;
+
+       for (i = 0; i < ARRAY_LEN(ie_maps); i++) {
+               if (strcasecmp(ie_maps[i].name, str))
+                       continue;
+
+               *ie_type = ie_maps[i].ie_type;
+               return 0;
+       }
+
+       return -1;
+}
+
+size_t ast_event_get_size(const struct ast_event *event)
+{
+       size_t res;
+
+       res = ntohs(event->event_len);
+
+       return res;
+}
+
 static void ast_event_ie_val_destroy(struct ast_event_ie_val *ie_val)
 {
-       if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
-               ast_free((void *) ie_val->payload.str);
+       switch (ie_val->ie_pltype) {
+       case AST_EVENT_IE_PLTYPE_STR:
+       case AST_EVENT_IE_PLTYPE_RAW:
+               ast_free(ie_val->payload.raw);
+               break;
+       case AST_EVENT_IE_PLTYPE_UINT:
+       case AST_EVENT_IE_PLTYPE_EXISTS:
+       case AST_EVENT_IE_PLTYPE_UNKNOWN:
+               break;
+       }
 
        ast_free(ie_val);
 }
@@ -151,6 +266,13 @@ enum ast_event_subscriber_res ast_event_check_subscriber(enum ast_event_type typ
                        ie_val->payload.uint = va_arg(ap, uint32_t);
                else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
                        ie_val->payload.str = ast_strdupa(va_arg(ap, const char *));
+               else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) {
+                       void *data = va_arg(ap, void *);
+                       size_t datalen = va_arg(ap, size_t);
+                       ie_val->payload.raw = alloca(datalen);
+                       memcpy(ie_val->payload.raw, data, datalen);
+                       ie_val->raw_datalen = datalen;
+               }
                AST_LIST_INSERT_TAIL(&ie_vals, ie_val, entry);
        }
        va_end(ap);
@@ -176,6 +298,9 @@ enum ast_event_subscriber_res ast_event_check_subscriber(enum ast_event_type typ
                        if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR &&
                                strcmp(ie_val->payload.str, sub_ie_val->payload.str))
                                break;
+                       if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW &&
+                               memcmp(ie_val->payload.raw, sub_ie_val->payload.raw, ie_val->raw_datalen))
+                               break;
                }
                if (!ie_val)
                        break;
@@ -193,6 +318,97 @@ enum ast_event_subscriber_res ast_event_check_subscriber(enum ast_event_type typ
        return res;
 }
 
+static int match_ie_val(struct ast_event *event, struct ast_event_ie_val *ie_val, struct ast_event *event2)
+{
+       if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT) {
+               uint32_t val = event2 ? ast_event_get_ie_uint(event2, ie_val->ie_type) : ie_val->payload.uint;
+               if (val == ast_event_get_ie_uint(event, ie_val->ie_type))
+                       return 1;
+               return 0;
+       }
+
+       if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR) {
+               const char *str = event2 ? ast_event_get_ie_str(event2, ie_val->ie_type) : ie_val->payload.str;
+               if (str && !strcmp(str, ast_event_get_ie_str(event, ie_val->ie_type)))
+                       return 1;
+               return 0;
+       }
+
+       if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) {
+               const void *buf = event2 ? ast_event_get_ie_raw(event2, ie_val->ie_type) : ie_val->payload.raw;
+               if (buf && !memcmp(buf, ast_event_get_ie_raw(event, ie_val->ie_type), ie_val->raw_datalen))
+                       return 1;
+               return 0;
+       }
+
+       if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS) {
+               if (ast_event_get_ie_raw(event, ie_val->ie_type))
+                       return 1;
+               return 0;
+       }
+
+       return 0;
+}
+
+/*! \brief Dump the event cache for the subscribed event type */
+void ast_event_dump_cache(const struct ast_event_sub *event_sub)
+{
+       struct ast_event_ref *event_ref;
+       enum ast_event_type type = event_sub->type;
+
+       AST_RWLIST_RDLOCK(&ast_event_cache[type]);
+       AST_RWLIST_TRAVERSE_SAFE_BEGIN(&ast_event_cache[type], event_ref, entry) {
+               struct ast_event_ie_val *ie_val;
+               AST_LIST_TRAVERSE(&event_sub->ie_vals, ie_val, entry) {
+                       if (!match_ie_val(event_ref->event, ie_val, NULL))
+                               break;
+               }
+               if (!ie_val) {
+                       /* All parameters were matched on this cache entry, so dump it */
+                       event_sub->cb(event_ref->event, event_sub->userdata);
+               }
+       }
+       AST_RWLIST_TRAVERSE_SAFE_END
+       AST_RWLIST_UNLOCK(&ast_event_cache[type]);
+}
+
+static struct ast_event *gen_sub_event(struct ast_event_sub *sub)
+{
+       struct ast_event_ie_val *ie_val;
+       struct ast_event *event;
+
+       event = ast_event_new(AST_EVENT_SUB,
+               AST_EVENT_IE_UNIQUEID,  AST_EVENT_IE_PLTYPE_UINT, sub->uniqueid,
+               AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
+               AST_EVENT_IE_END);
+
+       if (!event)
+               return NULL;
+
+       AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
+               switch (ie_val->ie_pltype) {
+               case AST_EVENT_IE_PLTYPE_UNKNOWN:
+                       break;
+               case AST_EVENT_IE_PLTYPE_EXISTS:
+                       ast_event_append_ie_uint(&event, AST_EVENT_IE_EXISTS, ie_val->ie_type);
+                       break;
+               case AST_EVENT_IE_PLTYPE_UINT:
+                       ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
+                       break;
+               case AST_EVENT_IE_PLTYPE_STR:
+                       ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
+                       break;
+               case AST_EVENT_IE_PLTYPE_RAW:
+                       ast_event_append_ie_raw(&event, ie_val->ie_type, ie_val->payload.raw, ie_val->raw_datalen);
+                       break;
+               }
+               if (!event)
+                       break;
+       }
+
+       return event;
+}
+
 /*! \brief Send AST_EVENT_SUB events to this subscriber of ... subscriber events */
 void ast_event_report_subs(const struct ast_event_sub *event_sub)
 {
@@ -219,26 +435,7 @@ void ast_event_report_subs(const struct ast_event_sub *event_sub)
                if (event_sub == sub)
                        continue;
 
-               event = ast_event_new(AST_EVENT_SUB,
-                       AST_EVENT_IE_UNIQUEID,  AST_EVENT_IE_PLTYPE_UINT, sub->uniqueid,
-                       AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
-                       AST_EVENT_IE_END);
-
-               AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
-                       switch (ie_val->ie_pltype) {
-                       case AST_EVENT_IE_PLTYPE_EXISTS:
-                               ast_event_append_ie_uint(&event, AST_EVENT_IE_EXISTS, ie_val->ie_type);
-                               break;
-                       case AST_EVENT_IE_PLTYPE_UINT:
-                               ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
-                               break;
-                       case AST_EVENT_IE_PLTYPE_STR:
-                               ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
-                               break;
-                       }
-                       if (!event)
-                               break;
-               }
+               event = gen_sub_event(sub);
 
                if (!event)
                        continue;
@@ -250,15 +447,12 @@ void ast_event_report_subs(const struct ast_event_sub *event_sub)
        AST_RWDLLIST_UNLOCK(&ast_event_subs[event_type]);
 }
 
-struct ast_event_sub *ast_event_subscribe(enum ast_event_type type, ast_event_cb_t cb, 
-       void *userdata, ...)
+struct ast_event_sub *ast_event_subscribe_new(enum ast_event_type type, 
+       ast_event_cb_t cb, void *userdata)
 {
-       va_list ap;
-       enum ast_event_ie_type ie_type;
        struct ast_event_sub *sub;
-       struct ast_event *event;
 
-       if (type >= AST_EVENT_TOTAL) {
+       if (type < 0 || type >= AST_EVENT_TOTAL) {
                ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
                return NULL;
        }
@@ -266,71 +460,178 @@ struct ast_event_sub *ast_event_subscribe(enum ast_event_type type, ast_event_cb
        if (!(sub = ast_calloc(1, sizeof(*sub))))
                return NULL;
 
-       va_start(ap, userdata);
-       for (ie_type = va_arg(ap, enum ast_event_type);
-               ie_type != AST_EVENT_IE_END;
-               ie_type = va_arg(ap, enum ast_event_type))
-       {
-               struct ast_event_ie_val *ie_val;
-               if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
-                       continue;
-               ie_val->ie_type = ie_type;
-               ie_val->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
-               if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
-                       ie_val->payload.uint = va_arg(ap, uint32_t);
-               else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR) {
-                       if (!(ie_val->payload.str = ast_strdup(va_arg(ap, const char *)))) {
-                               ast_free(ie_val);
-                               continue;
-                       }
-               }
-               AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
-       }
-       va_end(ap);
-
        sub->type = type;
        sub->cb = cb;
        sub->userdata = userdata;
        sub->uniqueid = ast_atomic_fetchadd_int((int *) &sub_uniqueid, 1);
 
+       return sub;
+}
+
+int ast_event_sub_append_ie_uint(struct ast_event_sub *sub,
+       enum ast_event_ie_type ie_type, uint32_t uint)
+{
+       struct ast_event_ie_val *ie_val;
+
+       if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX)
+               return -1;
+
+       if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
+               return -1;
+
+       ie_val->ie_type = ie_type;
+       ie_val->payload.uint = uint;
+       ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_UINT;
+
+       AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
+
+       return 0;
+}
+
+int ast_event_sub_append_ie_exists(struct ast_event_sub *sub,
+       enum ast_event_ie_type ie_type)
+{
+       struct ast_event_ie_val *ie_val;
+
+       if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX)
+               return -1;
+
+       if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
+               return -1;
+
+       ie_val->ie_type = ie_type;
+       ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_EXISTS;
+
+       AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
+
+       return 0;
+}
+
+int ast_event_sub_append_ie_str(struct ast_event_sub *sub,     
+       enum ast_event_ie_type ie_type, const char *str)
+{
+       struct ast_event_ie_val *ie_val;
+
+       if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX)
+               return -1;
+
+       if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
+               return -1;
+
+       ie_val->ie_type = ie_type;
+       ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_STR;
+
+       if (!(ie_val->payload.str = ast_strdup(str))) {
+               ast_free(ie_val);
+               return -1;
+       }
+
+       AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
+
+       return 0;
+}
+
+int ast_event_sub_append_ie_raw(struct ast_event_sub *sub,     
+       enum ast_event_ie_type ie_type, void *data, size_t raw_datalen)
+{
+       struct ast_event_ie_val *ie_val;
+
+       if (ie_type < 0 || ie_type > AST_EVENT_IE_MAX)
+               return -1;
+
+       if (!(ie_val = ast_calloc(1, sizeof(*ie_val))))
+               return -1;
+
+       ie_val->ie_type = ie_type;
+       ie_val->ie_pltype = AST_EVENT_IE_PLTYPE_RAW;
+       ie_val->raw_datalen = raw_datalen;
+
+       if (!(ie_val->payload.raw = ast_malloc(raw_datalen))) {
+               ast_free(ie_val);
+               return -1;
+       }
+
+       memcpy(ie_val->payload.raw, data, raw_datalen);
+
+       AST_LIST_INSERT_TAIL(&sub->ie_vals, ie_val, entry);
+
+       return 0;
+}
+
+int ast_event_sub_activate(struct ast_event_sub *sub)
+{
        if (ast_event_check_subscriber(AST_EVENT_SUB,
-               AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, type,
+               AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
                AST_EVENT_IE_END) != AST_EVENT_SUB_NONE) {
-               struct ast_event_ie_val *ie_val;
+               struct ast_event *event;
 
-               event = ast_event_new(AST_EVENT_SUB,
-                       AST_EVENT_IE_UNIQUEID,  AST_EVENT_IE_PLTYPE_UINT, sub->uniqueid,
-                       AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
-                       AST_EVENT_IE_END);
-
-               AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
-                       switch (ie_val->ie_pltype) {
-                       case AST_EVENT_IE_PLTYPE_EXISTS:
-                               ast_event_append_ie_uint(&event, AST_EVENT_IE_EXISTS, ie_val->ie_type);
-                               break;
-                       case AST_EVENT_IE_PLTYPE_UINT:
-                               ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
-                               break;
-                       case AST_EVENT_IE_PLTYPE_STR:
-                               ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
-                               break;
-                       }
-                       if (!event)
-                               break;
-               }
+               event = gen_sub_event(sub);
 
                if (event)
                        ast_event_queue(event);
        }
 
-       AST_RWDLLIST_WRLOCK(&ast_event_subs[type]);
-       AST_RWDLLIST_INSERT_TAIL(&ast_event_subs[type], sub, entry);
-       AST_RWDLLIST_UNLOCK(&ast_event_subs[type]);
+       AST_RWDLLIST_WRLOCK(&ast_event_subs[sub->type]);
+       AST_RWDLLIST_INSERT_TAIL(&ast_event_subs[sub->type], sub, entry);
+       AST_RWDLLIST_UNLOCK(&ast_event_subs[sub->type]);
+
+       return 0;
+}
+
+struct ast_event_sub *ast_event_subscribe(enum ast_event_type type, ast_event_cb_t cb, 
+       void *userdata, ...)
+{
+       va_list ap;
+       enum ast_event_ie_type ie_type;
+       struct ast_event_sub *sub;
+
+       if (!(sub = ast_event_subscribe_new(type, cb, userdata)))
+               return NULL;
+
+       va_start(ap, userdata);
+       for (ie_type = va_arg(ap, enum ast_event_type);
+               ie_type != AST_EVENT_IE_END;
+               ie_type = va_arg(ap, enum ast_event_type))
+       {
+               enum ast_event_ie_pltype ie_pltype;
+
+               ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
+
+               switch (ie_pltype) {
+               case AST_EVENT_IE_PLTYPE_UNKNOWN:
+                       break;
+               case AST_EVENT_IE_PLTYPE_UINT:
+               {
+                       uint32_t uint = va_arg(ap, uint32_t);
+                       ast_event_sub_append_ie_uint(sub, ie_type, uint);
+                       break;
+               }
+               case AST_EVENT_IE_PLTYPE_STR:
+               {
+                       const char *str = va_arg(ap, const char *);
+                       ast_event_sub_append_ie_str(sub, ie_type, str);
+                       break;
+               }
+               case AST_EVENT_IE_PLTYPE_RAW:
+               {
+                       void *data = va_arg(ap, void *);
+                       size_t data_len = va_arg(ap, size_t);
+                       ast_event_sub_append_ie_raw(sub, ie_type, data, data_len);
+                       break;
+               }
+               case AST_EVENT_IE_PLTYPE_EXISTS:
+                       ast_event_sub_append_ie_exists(sub, ie_type);
+                       break;
+               }
+       }
+       va_end(ap);
+
+       ast_event_sub_activate(sub);
 
        return sub;
 }
 
-static void ast_event_sub_destroy(struct ast_event_sub *sub)
+void ast_event_sub_destroy(struct ast_event_sub *sub)
 {
        struct ast_event_ie_val *ie_val;
 
@@ -340,7 +641,7 @@ static void ast_event_sub_destroy(struct ast_event_sub *sub)
        ast_free(sub);
 }
 
-void ast_event_unsubscribe(struct ast_event_sub *sub)
+struct ast_event_sub *ast_event_unsubscribe(struct ast_event_sub *sub)
 {
        struct ast_event *event;
 
@@ -362,6 +663,8 @@ void ast_event_unsubscribe(struct ast_event_sub *sub)
        }
 
        ast_event_sub_destroy(sub);
+
+       return NULL;
 }
 
 void ast_event_iterator_init(struct ast_event_iterator *iterator, const struct ast_event *event)
@@ -494,6 +797,13 @@ struct ast_event *ast_event_new(enum ast_event_type type, ...)
                        ie_val->payload.uint = va_arg(ap, uint32_t);
                else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
                        ie_val->payload.str = ast_strdupa(va_arg(ap, const char *));
+               else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) {
+                       void *data = va_arg(ap, void *);
+                       size_t datalen = va_arg(ap, size_t);
+                       ie_val->payload.raw = alloca(datalen);
+                       memcpy(ie_val->payload.raw, data, datalen);
+                       ie_val->raw_datalen = datalen;
+               }
                AST_LIST_INSERT_TAIL(&ie_vals, ie_val, entry);
        }
        va_end(ap);
@@ -509,11 +819,19 @@ struct ast_event *ast_event_new(enum ast_event_type type, ...)
                        ast_event_append_ie_str(&event, ie_val->ie_type, ie_val->payload.str);
                else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT)
                        ast_event_append_ie_uint(&event, ie_val->ie_type, ie_val->payload.uint);
+               else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_RAW)
+                       ast_event_append_ie_raw(&event, ie_val->ie_type, ie_val->payload.raw, ie_val->raw_datalen);
 
                if (!event)
                        break;
        }
 
+       if (!ast_event_get_ie_raw(event, AST_EVENT_IE_EID)) {
+               /* If the event is originating on this server, add the server's
+                * entity ID to the event. */
+               ast_event_append_ie_raw(&event, AST_EVENT_IE_EID, &g_eid, sizeof(g_eid));
+       }
+
        return event;
 }
 
@@ -533,7 +851,7 @@ static struct ast_event *ast_event_dup(const struct ast_event *event)
        struct ast_event *dup_event;
        uint16_t event_len;
 
-       event_len = ntohs(event->event_len);
+       event_len = ast_event_get_size(event);
 
        if (!(dup_event = ast_calloc(1, event_len)))
                return NULL;
@@ -549,16 +867,8 @@ struct ast_event *ast_event_get_cached(enum ast_event_type type, ...)
        enum ast_event_ie_type ie_type;
        struct ast_event *dup_event = NULL;
        struct ast_event_ref *event_ref;
-       struct cache_arg {
-               AST_LIST_ENTRY(cache_arg) entry;
-               enum ast_event_ie_type ie_type;
-               enum ast_event_ie_pltype ie_pltype;
-               union {
-                       uint32_t uint;
-                       const char *str;
-               } payload;
-       } *cache_arg;
-       AST_LIST_HEAD_NOLOCK_STATIC(cache_args, cache_arg);
+       struct ast_event_ie_val *cache_arg;
+       AST_LIST_HEAD_NOLOCK_STATIC(cache_args, ast_event_ie_val);
 
        if (type >= AST_EVENT_TOTAL) {
                ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
@@ -578,6 +888,13 @@ struct ast_event *ast_event_get_cached(enum ast_event_type type, ...)
                        cache_arg->payload.uint = va_arg(ap, uint32_t);
                else if (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_STR)
                        cache_arg->payload.str = ast_strdupa(va_arg(ap, const char *));
+               else if (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_RAW) {
+                       void *data = va_arg(ap, void *);
+                       size_t datalen = va_arg(ap, size_t);
+                       cache_arg->payload.raw = alloca(datalen);
+                       memcpy(cache_arg->payload.raw, data, datalen);
+                       cache_arg->raw_datalen = datalen;
+               }
                AST_LIST_INSERT_TAIL(&cache_args, cache_arg, entry);
        }
        va_end(ap);
@@ -591,19 +908,8 @@ struct ast_event *ast_event_get_cached(enum ast_event_type type, ...)
        AST_RWLIST_RDLOCK(&ast_event_cache[type]);
        AST_RWLIST_TRAVERSE_SAFE_BEGIN(&ast_event_cache[type], event_ref, entry) {
                AST_LIST_TRAVERSE(&cache_args, cache_arg, entry) {
-                       if ( ! ( (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_UINT &&
-                          (cache_arg->payload.uint ==
-                           ast_event_get_ie_uint(event_ref->event, cache_arg->ie_type))) ||
-
-                          (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_STR &&
-                          (!strcmp(cache_arg->payload.str,
-                            ast_event_get_ie_str(event_ref->event, cache_arg->ie_type)))) ||
-
-                          (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS &&
-                           ast_event_get_ie_raw(event_ref->event, cache_arg->ie_type)) ) ) 
-                       {
+                       if (!match_ie_val(event_ref->event, cache_arg, NULL))
                                break;  
-                       }
                }
                if (!cache_arg) {
                        /* All parameters were matched on this cache entry, so return it */
@@ -643,12 +949,8 @@ int ast_event_queue_and_cache(struct ast_event *event, ...)
        uint16_t host_event_type;
        struct ast_event_ref *event_ref;
        int res;
-       struct cache_arg {
-               AST_LIST_ENTRY(cache_arg) entry;
-               enum ast_event_ie_type ie_type;
-               enum ast_event_ie_pltype ie_pltype;
-       } *cache_arg;
-       AST_LIST_HEAD_NOLOCK_STATIC(cache_args, cache_arg);
+       struct ast_event_ie_val *cache_arg;
+       AST_LIST_HEAD_NOLOCK_STATIC(cache_args, ast_event_ie_val);
 
        host_event_type = ntohs(event->type);
 
@@ -668,6 +970,8 @@ int ast_event_queue_and_cache(struct ast_event *event, ...)
                memset(cache_arg, 0, sizeof(*cache_arg));
                cache_arg->ie_type = ie_type;
                cache_arg->ie_pltype = va_arg(ap, enum ast_event_ie_pltype);
+               if (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_RAW)
+                       cache_arg->raw_datalen = va_arg(ap, size_t);
                AST_LIST_INSERT_TAIL(&cache_args, cache_arg, entry);
        }
        va_end(ap);
@@ -681,19 +985,8 @@ int ast_event_queue_and_cache(struct ast_event *event, ...)
        AST_RWLIST_WRLOCK(&ast_event_cache[host_event_type]);
        AST_RWLIST_TRAVERSE_SAFE_BEGIN(&ast_event_cache[host_event_type], event_ref, entry) {
                AST_LIST_TRAVERSE(&cache_args, cache_arg, entry) {
-                       if ( ! ( (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_UINT &&
-                          (ast_event_get_ie_uint(event, cache_arg->ie_type) ==
-                           ast_event_get_ie_uint(event_ref->event, cache_arg->ie_type))) ||
-
-                          (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_STR &&
-                          (!strcmp(ast_event_get_ie_str(event, cache_arg->ie_type),
-                            ast_event_get_ie_str(event_ref->event, cache_arg->ie_type)))) ||
-
-                          (cache_arg->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS &&
-                           ast_event_get_ie_raw(event_ref->event, cache_arg->ie_type)) ) )
-                       {
+                       if (!match_ie_val(event_ref->event, cache_arg, event))
                                break;  
-                       }
                }
                if (!cache_arg) {
                        /* All parameters were matched on this cache entry, so remove it */
@@ -721,19 +1014,8 @@ static int handle_event(void *data)
        AST_RWDLLIST_TRAVERSE(&ast_event_subs[host_event_type], sub, entry) {
                struct ast_event_ie_val *ie_val;
                AST_LIST_TRAVERSE(&sub->ie_vals, ie_val, entry) {
-                       if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_EXISTS &&
-                               ast_event_get_ie_raw(event_ref->event, ie_val->ie_type)) {
-                               continue;
-                       } else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_UINT &&
-                               ast_event_get_ie_uint(event_ref->event, ie_val->ie_type) 
-                               == ie_val->payload.uint) {
-                               continue;
-                       } else if (ie_val->ie_pltype == AST_EVENT_IE_PLTYPE_STR &&
-                               !strcmp(ast_event_get_ie_str(event_ref->event, ie_val->ie_type),
-                                       ie_val->payload.str)) {
-                               continue;
-                       }
-                       break;
+                       if (!match_ie_val(event_ref->event, ie_val, NULL))
+                               break;
                }
                if (ie_val)
                        continue;