+/*----- Backgrounded operations -------------------------------------------*/
+
+#define BGTAG(bg) \
+ (((admin_bgop *)(bg))->tag ? ((admin_bgop *)(bg))->tag : "<foreground>")
+
+/* --- @a_bgrelease@ --- *
+ *
+ * Arguments: @admin_bgop *bg@ = backgrounded operation
+ *
+ * Returns: ---
+ *
+ * Use: Removes a backgrounded operation from the queue, since
+ * (presumably) it's done.
+ */
+
+static void a_bgrelease(admin_bgop *bg)
+{
+ admin *a = bg->a;
+
+ T( trace(T_ADMIN, "admin: release bgop %s", BGTAG(bg)); )
+ if (bg->tag) xfree(bg->tag);
+ else selbuf_enable(&a->b);
+ if (bg->next) bg->next->prev = bg->prev;
+ if (bg->prev) bg->prev->next = bg->next;
+ else a->bg = bg->next;
+ xfree(bg);
+ if (a->f & AF_CLOSE) a_destroy(a);
+ a_unlock(a);
+}
+
+/* --- @a_bgok@, @a_bginfo@, @a_bgfail@ --- *
+ *
+ * Arguments: @admin_bgop *bg@ = backgrounded operation
+ * @const char *fmt@ = format string
+ * @...@ = other arguments
+ *
+ * Returns: ---
+ *
+ * Use: Convenience functions for @a_write@.
+ */
+
+static void a_bgok(admin_bgop *bg)
+ { a_write(bg->a, "OK", bg->tag, 0); }
+
+static void a_bginfo(admin_bgop *bg, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ a_vwrite(bg->a, "INFO", bg->tag, fmt, ap);
+ va_end(ap);
+}
+
+static void a_bgfail(admin_bgop *bg, const char *fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ a_vwrite(bg->a, "FAIL", bg->tag, fmt, ap);
+ va_end(ap);
+}
+
+/* --- @a_bgadd@ --- *
+ *
+ * Arguments: @admin *a@ = administration connection
+ * @admin_bgop *bg@ = pointer to background operation
+ * @const char *tag@ = background tag, or null for foreground
+ * @void (*cancel)(admin_bgop *)@ = cancel function
+ *
+ * Returns: ---
+ *
+ * Use: Links a background job into the list.
+ */
+
+static void a_bgadd(admin *a, admin_bgop *bg, const char *tag,
+ void (*cancel)(admin_bgop *))
+{
+ if (tag)
+ bg->tag = xstrdup(tag);
+ else {
+ bg->tag = 0;
+ selbuf_disable(&a->b);
+ }
+ bg->a = a;
+ bg->cancel = cancel;
+ bg->next = a->bg;
+ bg->prev = 0;
+ if (a->bg) a->bg->prev = bg;
+ a->bg = bg;
+ a_lock(a);
+ T( trace(T_ADMIN, "admin: add bgop %s", BGTAG(bg)); )
+ if (tag) a_write(a, "DETACH", tag, 0);
+}
+