void pa__done(pa_module*m) {
    struct userdata*u;
    pa_assert(m);

    if (!(u = m->userdata))
        return;

    unpublish_all_services(u);

    if (u->services)
        pa_hashmap_free(u->services);

    if (u->sink_new_slot)
        pa_hook_slot_free(u->sink_new_slot);
    if (u->source_new_slot)
        pa_hook_slot_free(u->source_new_slot);
    if (u->sink_changed_slot)
        pa_hook_slot_free(u->sink_changed_slot);
    if (u->source_changed_slot)
        pa_hook_slot_free(u->source_changed_slot);
    if (u->sink_unlink_slot)
        pa_hook_slot_free(u->sink_unlink_slot);
    if (u->source_unlink_slot)
        pa_hook_slot_free(u->source_unlink_slot);

    if (u->native)
        pa_native_protocol_unref(u->native);

    pa_xfree(u->service_name);
    pa_xfree(u);
}
static void client_callback(AvahiClient *c, AvahiClientState state, void *userdata) {
    struct userdata *u = userdata;

    pa_assert(c);
    pa_assert(u);

    u->client = c;

    switch (state) {
        case AVAHI_CLIENT_S_RUNNING:
            publish_all_services(u);
            break;

        case AVAHI_CLIENT_S_COLLISION:
            pa_log_debug("Host name collision");
            unpublish_all_services(u, FALSE);
            break;

        case AVAHI_CLIENT_FAILURE:
            if (avahi_client_errno(c) == AVAHI_ERR_DISCONNECTED) {
                int error;

                pa_log_debug("Avahi daemon disconnected.");

                unpublish_all_services(u, TRUE);
                avahi_client_free(u->client);

                if (!(u->client = avahi_client_new(u->avahi_poll, AVAHI_CLIENT_NO_FAIL, client_callback, u, &error))) {
                    pa_log("avahi_client_new() failed: %s", avahi_strerror(error));
                    pa_module_unload_request(u->module, TRUE);
                }
            }

            break;

        default: ;
    }
}