00001 #include <string.h>
00002
00003 #include <microfeed-provider/microfeedprovider.h>
00004 #include <microfeed-common/microfeedmisc.h>
00005 #include <microfeed-common/microfeedstore.h>
00006 #include <microfeed-common/microfeedprotocol.h>
00007
00008 struct _MicrofeedProvider {
00009 MicrofeedConfiguration* configuration;
00010 char* bus_name;
00011 MicrofeedProviderCallbacks callbacks;
00012 void* user_data;
00013 DBusConnection* connection;
00014
00015 MicrofeedStore* publishers;
00016 };
00017
00018 static DBusHandlerResult handle_message(DBusConnection* connection, DBusMessage* message, void* user_data);
00019 static void no_more_subscribers(MicrofeedPublisher* publisher, void* user_data);
00020
00036 MicrofeedProvider* microfeed_provider_new(const char* bus_name, DBusConnection* connection, MicrofeedProviderCallbacks* callbacks, void* user_data) {
00037 MicrofeedProvider* provider;
00038 DBusError error;
00039
00040 provider = microfeed_memory_allocate(MicrofeedProvider);
00041
00042 dbus_error_init(&error);
00043 if (dbus_bus_request_name(connection, bus_name, 0, &error) == -1) {
00044 microfeed_memory_free(provider);
00045 provider = NULL;
00046
00047 return NULL;
00048 } else if (!dbus_connection_add_filter(connection, handle_message, provider, NULL)) {
00049 microfeed_memory_free(provider);
00050 provider = NULL;
00051 dbus_bus_release_name(connection, bus_name, &error);
00052
00053 return NULL;
00054 } else {
00055 provider->bus_name = strdup(bus_name);
00056 provider->configuration = microfeed_configuration_new();
00057 provider->connection = connection;
00058 provider->callbacks = *callbacks;
00059 provider->user_data = user_data;
00060 provider->publishers = microfeed_store_new_sorted((MicrofeedStoreCompareKeysFunction)strcmp,
00061 (MicrofeedStoreGetKeyFunction)microfeed_publisher_get_object_path);
00062 }
00063
00064 return provider;
00065 }
00066
00074 void microfeed_provider_free(MicrofeedProvider* provider) {
00075 DBusError error;
00076
00077 dbus_error_init(&error);
00078 dbus_connection_remove_filter(provider->connection, handle_message, provider);
00079 dbus_bus_release_name(provider->connection, provider->bus_name, &error);
00080
00081 free(provider->bus_name);
00082 provider->connection = NULL;
00083 provider->bus_name = NULL;
00084 microfeed_memory_free(provider);
00085 }
00086
00096 void microfeed_provider_add_publisher(MicrofeedProvider* provider, MicrofeedPublisher* publisher) {
00097 microfeed_store_insert(provider->publishers, publisher);
00098 }
00099
00106 void microfeed_provider_remove_publisher(MicrofeedProvider* provider, MicrofeedPublisher* publisher) {
00107 microfeed_store_remove(provider->publishers, publisher);
00108 }
00109
00116 DBusConnection* microfeed_provider_get_dbus_connection(MicrofeedProvider* provider) {
00117
00118 return provider->connection;
00119 }
00120
00127 const char* microfeed_provider_get_bus_name(MicrofeedProvider* provider) {
00128
00129 return provider->bus_name;
00130 }
00131
00132 static DBusHandlerResult handle_message(DBusConnection* connection, DBusMessage* message, void* user_data) {
00133 DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00134 MicrofeedProvider* provider;
00135 const char* name;
00136 const char* old_owner;
00137 const char* new_owner;
00138 MicrofeedStoreIterator* iterator;
00139 MicrofeedPublisher* publisher;
00140 const char* object_path;
00141 char* publisher_identifier;
00142 const char* publisher_directory;
00143 DBusMessage* reply;
00144 MicrofeedPublisherCallbacks callbacks;
00145
00146 provider = (MicrofeedProvider*)user_data;
00147 if (dbus_message_is_signal(message, "org.freedesktop.DBus", "NameOwnerChanged") &&
00148 dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &old_owner, DBUS_TYPE_STRING, &new_owner, DBUS_TYPE_INVALID) &&
00149 name[0] == ':' && new_owner[0] == 0 && !strcmp(name, old_owner)) {
00150 for (iterator = microfeed_store_iterate(provider->publishers, NULL);
00151 (publisher = microfeed_store_iterator_get(iterator, MicrofeedPublisher));
00152 microfeed_store_iterator_next(iterator)) {
00153 microfeed_publisher_remove_subscriber(publisher, name);
00154 }
00155 }
00156 object_path = dbus_message_get_path(message);
00157 if (object_path && !(publisher = microfeed_store_get(provider->publishers, object_path, MicrofeedPublisher)) &&
00158 !strncmp(object_path, MICROFEED_DBUS_OBJECT_PATH_PREFIX_PUBLISHER, strlen(MICROFEED_DBUS_OBJECT_PATH_PREFIX_PUBLISHER))) {
00159 publisher_identifier = microfeed_util_string_concatenate(object_path + strlen(MICROFEED_DBUS_OBJECT_PATH_PREFIX_PUBLISHER), MICROFEED_PUBLISHER_IDENTIFIER_SEPARATOR_STRING, provider->bus_name, NULL);
00160 microfeed_configuration_invalidate(provider->configuration);
00161 if ((publisher_directory = microfeed_configuration_get_publisher_directory(provider->configuration, publisher_identifier)) ||
00162 (dbus_message_is_method_call(message, MICROFEED_DBUS_INTERFACE_PUBLISHER, MICROFEED_METHOD_NAME_CREATE_PUBLISHER) &&
00163 provider->callbacks.publisher_callbacks.initialize_settings &&
00164 (publisher_directory = microfeed_configuration_get_default_publisher_directory(provider->configuration)))) {
00165 publisher_identifier = microfeed_util_string_concatenate(object_path + strlen(MICROFEED_DBUS_OBJECT_PATH_PREFIX_PUBLISHER), MICROFEED_PUBLISHER_IDENTIFIER_SEPARATOR_STRING, provider->bus_name, NULL);
00166 callbacks = provider->callbacks.publisher_callbacks;
00167 callbacks.no_more_subscribers = no_more_subscribers;
00168 if ((publisher = microfeed_publisher_new(publisher_identifier, publisher_directory, provider->connection, &callbacks, provider->user_data))) {
00169 microfeed_publisher_set_provider(publisher, provider);
00170 microfeed_provider_add_publisher(provider, publisher);
00171 free(publisher_identifier);
00172 } else {
00173 reply = dbus_message_new_error(message, MICROFEED_DBUS_INTERFACE_ERROR "." MICROFEED_ERROR_UNKNOWN, "Instantiation of a publisher failed.");
00174 dbus_connection_send(connection, reply, NULL);
00175 dbus_message_unref(reply);
00176 result = DBUS_HANDLER_RESULT_HANDLED;
00177 }
00178 } else {
00179 reply = dbus_message_new_error(message, MICROFEED_DBUS_INTERFACE_ERROR "." MICROFEED_ERROR_NO_SUCH_PUBLISHER, "Publisher does not exist.");
00180 dbus_connection_send(connection, reply, NULL);
00181 dbus_message_unref(reply);
00182 result = DBUS_HANDLER_RESULT_HANDLED;
00183 }
00184 }
00185
00186 return result;
00187 }
00188
00189 static void no_more_subscribers(MicrofeedPublisher* publisher, void* user_data) {
00190 MicrofeedProvider* provider;
00191
00192 provider = microfeed_publisher_get_provider(publisher);
00193 if (provider->callbacks.publisher_callbacks.no_more_subscribers) {
00194 provider->callbacks.publisher_callbacks.no_more_subscribers(publisher, user_data);
00195 }
00196 microfeed_store_remove(provider->publishers, publisher);
00197 microfeed_publisher_free(publisher);
00198 if (microfeed_store_get_size(provider->publishers) == 0) {
00199 provider->callbacks.no_more_publishers(provider, provider->user_data);
00200 }
00201 }
00202