Add mapper-wait-until-removed

This option will do the opposite of mapper wait
by blocking if a dbus object exists until that
object is removed.

Change-Id: Ia460b1ffdb912ba475b15ae5f8499a177e801dfd
Signed-off-by: Adriana Kobylak <anoo@us.ibm.com>
diff --git a/libmapper/app.c b/libmapper/app.c
index 7efc08c..aa42461 100644
--- a/libmapper/app.c
+++ b/libmapper/app.c
@@ -119,7 +119,10 @@
 		goto finish;
 	}
 
-	r = mapper_wait_async(conn, loop, argv+2, quit, loop, &wait);
+	if (!strcmp(argv[1], "wait"))
+		r = mapper_wait_async(conn, loop, argv+2, quit, loop, &wait, true);
+	else if (!strcmp(argv[1], "wait-until-removed"))
+		r = mapper_wait_async(conn, loop, argv+2, quit, loop, &wait, false);
 	if(r < 0) {
 		fprintf(stderr, "Error configuring waitlist: %s\n",
 				strerror(-r));
@@ -178,6 +181,8 @@
 		"\nCOMMANDS:\n"
 		"  call           invoke the specified method\n"
 		"  wait           wait for the specified objects to appear on the DBus\n"
+		"  wait-until-removed"
+		"		wait until the specified objects are not present in the DBus\n"
 		"  get-service    return the service identifier for input path\n";
 
 	if(argc < 2) {
@@ -187,7 +192,8 @@
 
 	if(!strcmp(argv[1], "call"))
 		call_main(argc, argv);
-	if(!strcmp(argv[1], "wait"))
+	if(!strcmp(argv[1], "wait") ||
+	   !strcmp(argv[1], "wait-until-removed"))
 		wait_main(argc, argv);
 	if(!strcmp(argv[1], "get-service"))
 		get_service_main(argc, argv);
diff --git a/libmapper/mapper.c b/libmapper/mapper.c
index 962b4e0..ad64d4a 100644
--- a/libmapper/mapper.c
+++ b/libmapper/mapper.c
@@ -35,6 +35,11 @@
 	"interface='org.freedesktop.DBus.ObjectManager',"
 	"member='InterfacesAdded'";
 
+static const char *async_wait_interfaces_removed_match =
+	"type='signal',"
+	"interface='org.freedesktop.DBus.ObjectManager',"
+	"member='InterfacesRemoved'";
+
 static const int mapper_busy_retries = 5;
 static const uint64_t mapper_busy_delay_interval_usec = 1000000;
 
@@ -51,6 +56,7 @@
 	int count;
 	int finished;
 	int r;
+	bool added;
 };
 
 struct async_wait_callback_data
@@ -157,8 +163,12 @@
 		goto exit;
 
 	r = sd_bus_message_get_errno(m);
-	if(r == ENOENT)
-		goto exit;
+	if(r == ENOENT) {
+		if (wait->added)
+			goto exit;
+		else
+			r = 0;
+	}
 
 	if(r == EBUSY && data->retry < mapper_busy_retries) {
 		r = sd_event_now(wait->loop,
@@ -296,7 +306,8 @@
 		char *objs[],
 		void (*callback)(int, void *),
 		void *userdata,
-		mapper_async_wait **w)
+		mapper_async_wait **w,
+		bool added)
 {
 	int r;
 	mapper_async_wait *wait = NULL;
@@ -313,6 +324,7 @@
 	wait->count = sarraylen(objs);
 	if(!wait->count)
 		return 0;
+	wait->added = added;
 
 	wait->objs = sarraydup(objs);
 	if(!wait->objs) {
@@ -327,26 +339,39 @@
 	}
 	memset(wait->status, 0, sizeof(*wait->status) * wait->count);
 
-	r = sd_bus_add_match(conn,
-			&wait->introspection_slot,
-			async_wait_introspection_match,
-			async_wait_match_introspection_complete,
-			wait);
-	if(r < 0) {
-		fprintf(stderr, "Error adding match rule: %s\n",
-				strerror(-r));
-		goto free_status;
-	}
+	if (wait->added) {
+		r = sd_bus_add_match(conn,
+				&wait->introspection_slot,
+				async_wait_introspection_match,
+				async_wait_match_introspection_complete,
+				wait);
+		if(r < 0) {
+			fprintf(stderr, "Error adding match rule: %s\n",
+					strerror(-r));
+			goto free_status;
+		}
 
-	r = sd_bus_add_match(conn,
-                        &wait->intf_slot,
-			async_wait_interfaces_added_match,
-                        async_wait_match_introspection_complete,
-                        wait);
-	if(r < 0) {
-		fprintf(stderr, "Error adding match rule: %s\n",
-				strerror(-r));
-		goto unref_name_slot;
+		r = sd_bus_add_match(conn,
+				&wait->intf_slot,
+				async_wait_interfaces_added_match,
+				async_wait_match_introspection_complete,
+				wait);
+		if(r < 0) {
+			fprintf(stderr, "Error adding match rule: %s\n",
+					strerror(-r));
+			goto unref_name_slot;
+		}
+	} else {
+		r = sd_bus_add_match(conn,
+				&wait->intf_slot,
+				async_wait_interfaces_removed_match,
+				async_wait_match_introspection_complete,
+				wait);
+		if(r < 0) {
+			fprintf(stderr, "Error adding match rule: %s\n",
+					strerror(-r));
+			goto unref_name_slot;
+		}
 	}
 
 	r = async_wait_get_objects(wait);
diff --git a/libmapper/mapper.h b/libmapper/mapper.h
index 7459e15..9f85c5f 100644
--- a/libmapper/mapper.h
+++ b/libmapper/mapper.h
@@ -1,3 +1,4 @@
+#include <stdbool.h>
 #include <systemd/sd-bus.h>
 #include <systemd/sd-event.h>
 
@@ -8,7 +9,8 @@
 void mapper_wait_async_free(mapper_async_wait *);
 
 int mapper_wait_async(sd_bus *, sd_event *, char *[],
-		void (*)(int, void *), void *, mapper_async_wait **);
+		void (*)(int, void *), void *, mapper_async_wait **,
+		bool);
 int mapper_get_service(sd_bus *conn, const char *obj, char **service);
 int mapper_get_object(sd_bus *conn, const char *obj, sd_bus_message **reply);
 #ifdef __cplusplus