[asterisk-commits] russell: branch russell/events r59575 - in /team/russell/events: ./ apps/ con...

asterisk-commits at lists.digium.com asterisk-commits at lists.digium.com
Fri Mar 30 16:08:49 MST 2007


Author: russell
Date: Fri Mar 30 18:08:49 2007
New Revision: 59575

URL: http://svn.digium.com/view/asterisk?view=rev&rev=59575
Log:
Add a bunch of code that addresses a problem I identified with event based MWI.

The issue is that there may be external entities other than app_voicemail that
may modify mailboxes.  So, in that case, unfortunately, we still need to poll
the mailbox to check for changes.  However, I did it in a "smart" way.

First, there are a couple of new options in voicemail.conf - "pollmailboxes" to
enable mailbox polling, and "pollfreq" to control the polling frequency.

Second, I made the event core generate events when someone subscribes to events
or unsubscribes from events.  Then, I made app_voicemail subscribe to these
events and keep track of which mailboxes are currently subscribed to.  Then, it
will only poll the mailboxes that someone is currently subscribed to.

On a related note, these "subscription events" will be important when we are
able to send events over the network.  That way, remote servers will easily
know which other servers want to know about certain events.

Modified:
    team/russell/events/UPGRADE.txt
    team/russell/events/apps/app_voicemail.c
    team/russell/events/configs/voicemail.conf.sample
    team/russell/events/include/asterisk/event.h
    team/russell/events/include/asterisk/event_defs.h
    team/russell/events/main/event.c

Modified: team/russell/events/UPGRADE.txt
URL: http://svn.digium.com/view/asterisk/team/russell/events/UPGRADE.txt?view=diff&rev=59575&r1=59574&r2=59575
==============================================================================
--- team/russell/events/UPGRADE.txt (original)
+++ team/russell/events/UPGRADE.txt Fri Mar 30 18:08:49 2007
@@ -24,13 +24,24 @@
   style' layout introduced in Asterisk 1.4 (and used by the automatic
   sound file installer in the Makefile).
 
-Applications:
+Voicemail:
 
 * The voicemail configuration values 'maxmessage' and 'minmessage' have
   been changed to 'maxsecs' and 'minsecs' to clarify their purpose and
   to make them more distinguishable from 'maxmsgs', which sets folder
   size.  The old variables will continue to work in this version, albeit
   with a deprecation warning.
+* If you use any interface for modifying voicemail aside from the built in
+  dialplan applications, then the option "pollmailboxes" *must* be set in
+  voicemail.conf for message waiting indication (MWI) to work properly.  This
+  is because Voicemail notification is now event based instead of polling
+  based.  The channel drivers are no longer responsible for constantly manually
+  checking mailboxes for changes so that they can send MWI information to users.
+  Examples of situations that would require this option are web interfaces to
+  voicemail or an email client in the case of using IMAP storage.
+
+Applications:
+
 * ChanIsAvail() now has a 't' option, which allows the specified device
   to be queried for state without consulting the channel drivers. This
   performs mostly a 'ChanExists' sort of function.

Modified: team/russell/events/apps/app_voicemail.c
URL: http://svn.digium.com/view/asterisk/team/russell/events/apps/app_voicemail.c?view=diff&rev=59575&r1=59574&r2=59575
==============================================================================
--- team/russell/events/apps/app_voicemail.c (original)
+++ team/russell/events/apps/app_voicemail.c Fri Mar 30 18:08:49 2007
@@ -529,6 +529,42 @@
 static int maxgreet;
 static int skipms;
 static int maxlogins;
+
+/*! Poll mailboxes for changes since there is something external to
+ *  app_voicemail that may change them. */
+static unsigned int poll_mailboxes;
+
+/*! Polling frequency */
+static unsigned int poll_freq;
+/*! By default, poll every 30 seconds */
+#define DEFAULT_POLL_FREQ 30
+
+AST_MUTEX_DEFINE_STATIC(poll_lock);
+static ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER;
+static pthread_t poll_thread = AST_PTHREADT_NULL;
+static unsigned char poll_thread_run;
+
+/*! Subscription to ... MWI event subscriptions */
+static struct ast_event_sub *mwi_sub_sub;
+/*! Subscription to ... MWI event un-subscriptions */
+static struct ast_event_sub *mwi_unsub_sub;
+
+/*!
+ * \brief An MWI subscription
+ *
+ * This is so we can keep track of which mailboxes are subscribed to.
+ * This way, we know which mailboxes to poll when the pollmailboxes
+ * option is being used.
+ */
+struct mwi_sub {
+	AST_RWLIST_ENTRY(mwi_sub) entry;
+	int old_new;
+	int old_old;
+	uint32_t uniqueid;
+	char mailbox[1];
+};
+
+static AST_RWLIST_HEAD_STATIC(mwi_subs, mwi_sub);
 
 /* custom password sounds */
 static char vm_password[80] = "vm-password";
@@ -7242,6 +7278,162 @@
 	voicemail_show_zones_help, NULL, NULL },
 };
 
+static void poll_subscribed_mailboxes(void)
+{
+	struct mwi_sub *mwi_sub;
+
+	AST_RWLIST_RDLOCK(&mwi_subs);
+	AST_RWLIST_TRAVERSE(&mwi_subs, mwi_sub, entry) {
+		int new = 0, old = 0;
+
+		if (ast_strlen_zero(mwi_sub->mailbox))
+			continue;
+
+		inboxcount(mwi_sub->mailbox, &new, &old);
+
+		if (new != mwi_sub->old_new || old != mwi_sub->old_old) {
+			mwi_sub->old_new = new;
+			mwi_sub->old_old = old;
+			queue_mwi_event(mwi_sub->mailbox, new, old);
+		}
+	}
+	AST_RWLIST_UNLOCK(&mwi_subs);
+}
+
+static void *mb_poll_thread(void *data)
+{
+	while (poll_thread_run) {
+		struct timespec ts = { 0, };
+		struct timeval tv;
+
+		tv = ast_tvadd(ast_tvnow(), ast_samp2tv(poll_freq, 1));
+		ts.tv_sec = tv.tv_sec;
+		ts.tv_nsec = tv.tv_usec * 1000;
+
+		ast_mutex_lock(&poll_lock);
+		ast_cond_timedwait(&poll_cond, &poll_lock, &ts);
+		ast_mutex_unlock(&poll_lock);
+
+		if (!poll_thread_run)
+			break;
+
+		poll_subscribed_mailboxes();
+	}
+
+	return NULL;
+}
+
+static void mwi_sub_destroy(struct mwi_sub *mwi_sub)
+{
+	free(mwi_sub);
+}
+
+static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
+{
+	uint32_t uniqueid;
+	struct mwi_sub *mwi_sub;
+
+	if (ast_event_get_type(event) != AST_EVENT_UNSUB)
+		return;
+
+	if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
+		return;
+
+	uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
+
+	AST_RWLIST_WRLOCK(&mwi_subs);
+	AST_RWLIST_TRAVERSE_SAFE_BEGIN(&mwi_subs, mwi_sub, entry) {
+		if (mwi_sub->uniqueid == uniqueid) {
+			AST_LIST_REMOVE_CURRENT(&mwi_subs, entry);
+			break;
+		}
+	}
+	AST_RWLIST_TRAVERSE_SAFE_END
+	AST_RWLIST_UNLOCK(&mwi_subs);
+
+	if (mwi_sub)
+		mwi_sub_destroy(mwi_sub);
+}
+
+static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
+{
+	const char *mailbox;
+	uint32_t uniqueid;
+	unsigned int len;
+	struct mwi_sub *mwi_sub;
+
+	if (ast_event_get_type(event) != AST_EVENT_SUB)
+		return;
+
+	if (ast_event_get_ie_uint(event, AST_EVENT_IE_EVENTTYPE) != AST_EVENT_MWI)
+		return;
+
+	mailbox = ast_event_get_ie_str(event, AST_EVENT_IE_MAILBOX);
+	uniqueid = ast_event_get_ie_uint(event, AST_EVENT_IE_UNIQUEID);
+
+	len = sizeof(*mwi_sub);
+	if (!ast_strlen_zero(mailbox))
+		len += strlen(mailbox);
+
+	if (!(mwi_sub = ast_calloc(1, len)))
+		return;
+
+	mwi_sub->uniqueid = uniqueid;
+	if (!ast_strlen_zero(mailbox))
+		strcpy(mwi_sub->mailbox, mailbox);
+
+	AST_RWLIST_WRLOCK(&mwi_subs);
+	AST_RWLIST_INSERT_TAIL(&mwi_subs, mwi_sub, entry);
+	AST_RWLIST_UNLOCK(&mwi_subs);
+}
+
+static void start_poll_thread(void)
+{
+	pthread_attr_t attr;
+
+	mwi_sub_sub = ast_event_subscribe(AST_EVENT_SUB, mwi_sub_event_cb, NULL,
+		AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
+		AST_EVENT_IE_END);
+
+	mwi_unsub_sub = ast_event_subscribe(AST_EVENT_UNSUB, mwi_unsub_event_cb, NULL,
+		AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, AST_EVENT_MWI,
+		AST_EVENT_IE_END);
+
+	if (mwi_sub_sub)
+		ast_event_report_subs(mwi_sub_sub);
+
+	poll_thread_run = 1;
+
+	pthread_attr_init(&attr);
+	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+	ast_pthread_create(&poll_thread, &attr, 
+		mb_poll_thread, NULL);
+	pthread_attr_destroy(&attr);
+}
+
+static void stop_poll_thread(void)
+{
+	poll_thread_run = 0;
+
+	if (mwi_sub_sub) {
+		ast_event_unsubscribe(mwi_sub_sub);
+		mwi_sub_sub = NULL;
+	}
+
+	if (mwi_unsub_sub) {
+		ast_event_unsubscribe(mwi_unsub_sub);
+		mwi_unsub_sub = NULL;
+	}
+
+	ast_mutex_lock(&poll_lock);
+	ast_cond_signal(&poll_cond);
+	ast_mutex_unlock(&poll_lock);
+
+	pthread_join(poll_thread, NULL);
+
+	poll_thread = AST_PTHREADT_NULL;
+}
+
 static int load_config(void)
 {
 	struct ast_vm_user *cur;
@@ -7626,6 +7818,19 @@
 		if (!(val = ast_variable_retrieve(cfg, "general", "usedirectory"))) 
 			val = "no";
 		ast_set2_flag((&globalflags), ast_true(val), VM_DIRECFORWARD);	
+
+		poll_freq = DEFAULT_POLL_FREQ;
+		if ((val = ast_variable_retrieve(cfg, "general", "pollfreq"))) {
+			if (sscanf(val, "%u", &poll_freq) != 1) {
+				poll_freq = DEFAULT_POLL_FREQ;
+				ast_log(LOG_ERROR, "'%s' is not a valid value for the pollfreq option!\n", val);
+			}
+		}
+
+		poll_mailboxes = 0;
+		if ((val = ast_variable_retrieve(cfg, "general", "pollmailboxes")))
+			poll_mailboxes = ast_true(val);
+
 		if ((ucfg = ast_config_load("users.conf"))) {	
 			for (cat = ast_category_browse(ucfg, NULL); cat ; cat = ast_category_browse(ucfg, cat)) {
 				if (!ast_true(ast_config_option(ucfg, cat, "hasvoicemail")))
@@ -7785,6 +7990,12 @@
 		}
 		AST_LIST_UNLOCK(&users);
 		ast_config_destroy(cfg);
+
+		if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL)
+			start_poll_thread();
+		if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL)
+			stop_poll_thread();;
+
 		return 0;
 	} else {
 		AST_LIST_UNLOCK(&users);
@@ -7811,6 +8022,9 @@
 	ast_uninstall_vm_functions();
 	
 	ast_module_user_hangup_all();
+
+	if (poll_thread != AST_PTHREADT_NULL)
+		stop_poll_thread();
 
 	return res;
 }

Modified: team/russell/events/configs/voicemail.conf.sample
URL: http://svn.digium.com/view/asterisk/team/russell/events/configs/voicemail.conf.sample?view=diff&rev=59575&r1=59574&r2=59575
==============================================================================
--- team/russell/events/configs/voicemail.conf.sample (original)
+++ team/russell/events/configs/voicemail.conf.sample Fri Mar 30 18:08:49 2007
@@ -126,6 +126,19 @@
 ; You can override the default program to send e-mail if you wish, too
 ;
 ;mailcmd=/usr/sbin/sendmail -t
+;
+;pollmailboxes=no    ;   If mailboxes are changed anywhere outside of app_voicemail,
+;                    ; then this option must be enabled for MWI to work.  This
+;                    ; enables polling mailboxes for changes.  Normally, it will
+;                    ; expect that changes are only made when someone called in
+;                    ; to one of the voicemail applications.
+;                    ;   Examples of situations that would require this option are 
+;                    ; web interfaces to voicemail or an email client in the case 
+;                    ; of using IMAP storage.
+;
+;pollfreq=30         ;   If the "pollmailboxes" option is enabled, this option
+;                    ; sets the polling frequency.  The default is once every
+;                    ; 30 seconds.
 ; 
 ; Users may be located in different timezones, or may have different 
 ; message announcements for their introductory message when they enter 

Modified: team/russell/events/include/asterisk/event.h
URL: http://svn.digium.com/view/asterisk/team/russell/events/include/asterisk/event.h?view=diff&rev=59575&r1=59574&r2=59575
==============================================================================
--- team/russell/events/include/asterisk/event.h (original)
+++ team/russell/events/include/asterisk/event.h Fri Mar 30 18:08:49 2007
@@ -124,6 +124,23 @@
  * mailbox defined in the "mailbox" variable.
  */
 enum ast_event_subscriber_res ast_event_check_subscriber(enum ast_event_type event_type, ...);
+
+/*!
+ * \brief Report current subscriptions to a subscription subscriber
+ *
+ * \arg sub the subscription subscriber
+ *
+ * \return nothing
+ *
+ * This reports all of the current subscribers to a subscriber of
+ * subscribers to a specific event type.  (Try saying that a few times fast).
+ *
+ * The idea here is that it is sometimes very useful for a module to know when
+ * someone subscribes to events.  However, when they first subscribe, this
+ * provides that module the ability to request the event core report to them
+ * all of the subscriptions to that event type that already exist.
+ */
+void ast_event_report_subs(const struct ast_event_sub *sub);
 
 /*!
  * \brief Create a new event

Modified: team/russell/events/include/asterisk/event_defs.h
URL: http://svn.digium.com/view/asterisk/team/russell/events/include/asterisk/event_defs.h?view=diff&rev=59575&r1=59574&r2=59575
==============================================================================
--- team/russell/events/include/asterisk/event_defs.h (original)
+++ team/russell/events/include/asterisk/event_defs.h Fri Mar 30 18:08:49 2007
@@ -38,29 +38,74 @@
 	AST_EVENT_CUSTOM = 0x01,
 	/*! Voicemail message waiting indication */
 	AST_EVENT_MWI    = 0x02,
+	/*! Someone has subscribed to events */
+	AST_EVENT_SUB    = 0x03,
+	/*! Someone has unsubscribed from events */
+	AST_EVENT_UNSUB  = 0x04,
 	/*! Number of event types.  This should be the last event type + 1 */
-	AST_EVENT_TOTAL  = 0x03,
+	AST_EVENT_TOTAL  = 0x05,
 };
 
 /*! \brief Event Information Element types */
 enum ast_event_ie_type {
-	/*! Used to terminate the arguments to caching functions */
-	AST_EVENT_IE_END = -1,
-	/*! Used with AST_EVENT_MWI */
-	AST_EVENT_IE_NEWMSGS = 0x01,
-	/*! Used with AST_EVENT_MWI */
-	AST_EVENT_IE_OLDMSGS = 0x02,
-	/*! Used with AST_EVENT_MWI */
-	AST_EVENT_IE_MAILBOX = 0x03,
+	/*! Used to terminate the arguments to event functions */
+	AST_EVENT_IE_END       = -1,
+
+	/*! 
+	 * \brief Number of new messages
+	 * Used by: AST_EVENT_MWI 
+	 * Payload type: UINT
+	 */
+	AST_EVENT_IE_NEWMSGS   = 0x01,
+	/*! 
+	 * \brief Number of
+	 * Used by: AST_EVENT_MWI 
+	 * Payload type: UINT
+	 */
+	AST_EVENT_IE_OLDMSGS   = 0x02,
+	/*! 
+	 * \brief Mailbox name (mailbox[@context])
+	 * Used by: AST_EVENT_MWI 
+	 * Payload type: STR
+	 */
+	AST_EVENT_IE_MAILBOX   = 0x03,
+	/*! 
+	 * \brief Unique ID
+	 * Used by: AST_EVENT_SUB, AST_EVENT_UNSUB
+	 * Payload type: UINT
+	 */
+	AST_EVENT_IE_UNIQUEID  = 0x04,
+	/*! 
+	 * \brief Event type 
+	 * Used by: AST_EVENT_SUB, AST_EVENT_UNSUB
+	 * Payload type: UINT
+	 */
+	AST_EVENT_IE_EVENTTYPE = 0x05,
+	/*!
+	 * \brief Hint that someone cares than an IE exists
+	 * Used by: AST_EVENT_SUB
+	 * Payload type: UINT (ast_event_ie_type)
+	 */
+	AST_EVENT_IE_EXISTS    = 0x06,
 };
 
+/*!
+ * \brief Payload types for event information elements
+ */
 enum ast_event_ie_pltype {
 	/*! Just check if it exists, not the value */
 	AST_EVENT_IE_PLTYPE_EXISTS,
+	/*! Unsigned Integer (Can be used for signed, too ...) */
 	AST_EVENT_IE_PLTYPE_UINT,
+	/*! String */
 	AST_EVENT_IE_PLTYPE_STR,
 };
 
+/*!
+ * \brief Results for checking for subscribers
+ *
+ * \ref ast_event_check_subscriber()
+ */
 enum ast_event_subscriber_res {
 	/*! No subscribers exist */
 	AST_EVENT_SUB_NONE,

Modified: team/russell/events/main/event.c
URL: http://svn.digium.com/view/asterisk/team/russell/events/main/event.c?view=diff&rev=59575&r1=59574&r2=59575
==============================================================================
--- team/russell/events/main/event.c (original)
+++ team/russell/events/main/event.c Fri Mar 30 18:08:49 2007
@@ -44,10 +44,19 @@
 	unsigned char ie_payload[0];
 } __attribute__ ((packed));
 
+/*!
+ * \brief An event
+ *
+ * \note The format of this structure is important, and can not change, since
+ *       they are sent directly over the network (via IAX2).
+ *
+ */
 struct ast_event {
+	/*! Event type */
 	enum ast_event_type type:16;
 	/*! Total length of the event */
 	uint16_t event_len:16;
+	/*! The data payload of the event, made up of information elements */
 	unsigned char payload[0];
 } __attribute__ ((packed));
 
@@ -80,9 +89,12 @@
 	enum ast_event_type type;
 	ast_event_cb_t cb;
 	void *userdata;
+	uint32_t uniqueid;
 	AST_LIST_HEAD_NOLOCK(, ast_event_ie_val) ie_vals;
 	AST_RWLIST_ENTRY(ast_event_sub) entry;
 };
+
+static uint32_t sub_uniqueid;
 
 /*! \brief Event subscriptions
  * The event subscribers are indexed by which event they are subscribed to */
@@ -171,12 +183,70 @@
 	return res;
 }
 
+/*! Send AST_EVENT_SUB events to this subscriber of ... subscriber events */
+void ast_event_report_subs(const struct ast_event_sub *event_sub)
+{
+	struct ast_event *event;
+	struct ast_event_sub *sub;
+	enum ast_event_type event_type = -1;
+	struct ast_event_ie_val *ie_val;
+
+	if (event_sub->type != AST_EVENT_SUB)
+		return;
+
+	AST_LIST_TRAVERSE(&event_sub->ie_vals, ie_val, entry) {
+		if (ie_val->ie_type == AST_EVENT_IE_EVENTTYPE) {
+			event_type = ie_val->payload.uint;
+			break;
+		}
+	}
+
+	if (event_type == -1)
+		return;
+
+	AST_RWLIST_RDLOCK(&ast_event_subs[event_type]);
+	AST_RWLIST_TRAVERSE(&ast_event_subs[event_type], sub, entry) {
+		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;
+		}
+
+		if (!event)
+			continue;
+
+		event_sub->cb(event, event_sub->userdata);
+
+		ast_event_destroy(event);
+	}
+	AST_RWLIST_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, ...)
 {
 	va_list ap;
 	enum ast_event_ie_type ie_type;
 	struct ast_event_sub *sub;
+	struct ast_event *event;
 
 	if (type >= AST_EVENT_TOTAL) {
 		ast_log(LOG_ERROR, "%u is an invalid type!\n", type);
@@ -211,6 +281,37 @@
 	sub->type = type;
 	sub->cb = cb;
 	sub->userdata = userdata;
+	sub->uniqueid = ast_atomic_fetchadd_int((int *) &sub_uniqueid, 1);
+
+	if (ast_event_check_subscriber(AST_EVENT_SUB,
+		AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, type,
+		AST_EVENT_IE_END) != AST_EVENT_SUB_NONE) {
+		struct ast_event_ie_val *ie_val;
+
+		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;
+		}
+
+		if (event)
+			ast_event_queue(event);
+	}
 
 	AST_RWLIST_WRLOCK(&ast_event_subs[type]);
 	AST_RWLIST_INSERT_TAIL(&ast_event_subs[type], sub, entry);
@@ -231,9 +332,24 @@
 
 void ast_event_unsubscribe(struct ast_event_sub *sub)
 {
+	struct ast_event *event;
+
 	AST_RWLIST_WRLOCK(&ast_event_subs[sub->type]);
 	AST_LIST_REMOVE(&ast_event_subs[sub->type], sub, entry);
 	AST_RWLIST_UNLOCK(&ast_event_subs[sub->type]);
+
+	if (ast_event_check_subscriber(AST_EVENT_UNSUB,
+		AST_EVENT_IE_EVENTTYPE, AST_EVENT_IE_PLTYPE_UINT, sub->type,
+		AST_EVENT_IE_END) != AST_EVENT_SUB_NONE) {
+		
+		event = ast_event_new(AST_EVENT_UNSUB,
+			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)
+			ast_event_queue(event);
+	}
 
 	ast_event_sub_destroy(sub);
 }



More information about the asterisk-commits mailing list