00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <string.h>
00020
00021 #include <microfeed-provider/microfeedprovider.h>
00022 #include <microfeed-common/microfeedmisc.h>
00023 #include <microfeed-common/microfeedstore.h>
00024 #include <microfeed-common/microfeedprotocol.h>
00025
00026 struct _MicrofeedProvider {
00027 MicrofeedConfiguration* configuration;
00028 char* bus_name;
00029 MicrofeedProviderCallbacks callbacks;
00030 void* user_data;
00031 DBusConnection* connection;
00032
00033 MicrofeedStore* publishers;
00034 };
00035
00036 static DBusHandlerResult handle_message(DBusConnection* connection, DBusMessage* message, void* user_data);
00037 static void no_more_subscribers(MicrofeedPublisher* publisher, void* user_data);
00038
00054 MicrofeedProvider* microfeed_provider_new(const char* bus_name, DBusConnection* connection, MicrofeedProviderCallbacks* callbacks, void* user_data) {
00055 MicrofeedProvider* provider;
00056 DBusError error;
00057
00058 provider = microfeed_memory_allocate(MicrofeedProvider);
00059
00060 dbus_error_init(&error);
00061 if (dbus_bus_request_name(connection, bus_name, 0, &error) == -1) {
00062 microfeed_memory_free(provider);
00063 provider = NULL;
00064
00065 return NULL;
00066 } else if (!dbus_connection_add_filter(connection, handle_message, provider, NULL)) {
00067 microfeed_memory_free(provider);
00068 provider = NULL;
00069 dbus_bus_release_name(connection, bus_name, &error);
00070
00071 return NULL;
00072 } else {
00073 provider->bus_name = strdup(bus_name);
00074 provider->configuration = microfeed_configuration_new();
00075 provider->connection = connection;
00076 provider->callbacks = *callbacks;
00077 provider->user_data = user_data;
00078 provider->publishers = microfeed_store_new_sorted((MicrofeedStoreCompareKeysFunction)strcmp,
00079 (MicrofeedStoreGetKeyFunction)microfeed_publisher_get_object_path);
00080 }
00081
00082 return provider;
00083 }
00084
00092 void microfeed_provider_free(MicrofeedProvider* provider) {
00093 DBusError error;
00094
00095 dbus_error_init(&error);
00096 dbus_connection_remove_filter(provider->connection, handle_message, provider);
00097 dbus_bus_release_name(provider->connection, provider->bus_name, &error);
00098
00099 free(provider->bus_name);
00100 provider->connection = NULL;
00101 provider->bus_name = NULL;
00102 microfeed_memory_free(provider);
00103 }
00104
00114 void microfeed_provider_add_publisher(MicrofeedProvider* provider, MicrofeedPublisher* publisher) {
00115 microfeed_store_insert(provider->publishers, publisher);
00116 }
00117
00124 void microfeed_provider_remove_publisher(MicrofeedProvider* provider, MicrofeedPublisher* publisher) {
00125 microfeed_store_remove(provider->publishers, publisher);
00126 }
00127
00134 DBusConnection* microfeed_provider_get_dbus_connection(MicrofeedProvider* provider) {
00135
00136 return provider->connection;
00137 }
00138
00145 const char* microfeed_provider_get_bus_name(MicrofeedProvider* provider) {
00146
00147 return provider->bus_name;
00148 }
00149
00150 static DBusHandlerResult handle_message(DBusConnection* connection, DBusMessage* message, void* user_data) {
00151 DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
00152 MicrofeedProvider* provider;
00153 const char* name;
00154 const char* old_owner;
00155 const char* new_owner;
00156 MicrofeedStoreIterator* iterator;
00157 MicrofeedPublisher* publisher;
00158 const char* object_path;
00159 char* publisher_identifier;
00160 const char* publisher_directory;
00161 DBusMessage* reply;
00162 MicrofeedPublisherCallbacks callbacks;
00163
00164 provider = (MicrofeedProvider*)user_data;
00165 if (dbus_message_is_signal(message, "org.freedesktop.DBus", "NameOwnerChanged") &&
00166 dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &old_owner, DBUS_TYPE_STRING, &new_owner, DBUS_TYPE_INVALID) &&
00167 name[0] == ':' && new_owner[0] == 0 && !strcmp(name, old_owner)) {
00168 for (iterator = microfeed_store_iterate(provider->publishers, NULL);
00169 (publisher = microfeed_store_iterator_get(iterator, MicrofeedPublisher));
00170 microfeed_store_iterator_next(iterator)) {
00171 microfeed_publisher_remove_subscriber(publisher, name);
00172 }
00173 }
00174 object_path = dbus_message_get_path(message);
00175 if (object_path && !(publisher = microfeed_store_get(provider->publishers, object_path, MicrofeedPublisher)) &&
00176 !strncmp(object_path, MICROFEED_DBUS_OBJECT_PATH_PREFIX_PUBLISHER, strlen(MICROFEED_DBUS_OBJECT_PATH_PREFIX_PUBLISHER))) {
00177 publisher_identifier = microfeed_util_string_concatenate(object_path + strlen(MICROFEED_DBUS_OBJECT_PATH_PREFIX_PUBLISHER), MICROFEED_PUBLISHER_IDENTIFIER_SEPARATOR_STRING, provider->bus_name, NULL);
00178 microfeed_configuration_invalidate(provider->configuration);
00179 if ((publisher_directory = microfeed_configuration_get_publisher_directory(provider->configuration, publisher_identifier)) ||
00180 (dbus_message_is_method_call(message, MICROFEED_DBUS_INTERFACE_PUBLISHER, MICROFEED_METHOD_NAME_CREATE_PUBLISHER) &&
00181 provider->callbacks.publisher_callbacks.initialize_settings &&
00182 (publisher_directory = microfeed_configuration_get_default_publisher_directory(provider->configuration)))) {
00183 publisher_identifier = microfeed_util_string_concatenate(object_path + strlen(MICROFEED_DBUS_OBJECT_PATH_PREFIX_PUBLISHER), MICROFEED_PUBLISHER_IDENTIFIER_SEPARATOR_STRING, provider->bus_name, NULL);
00184 callbacks = provider->callbacks.publisher_callbacks;
00185 callbacks.no_more_subscribers = no_more_subscribers;
00186 if ((publisher = microfeed_publisher_new(publisher_identifier, publisher_directory, provider->connection, &callbacks, provider->user_data))) {
00187 microfeed_publisher_set_provider(publisher, provider);
00188 microfeed_provider_add_publisher(provider, publisher);
00189 free(publisher_identifier);
00190 } else {
00191 reply = dbus_message_new_error(message, MICROFEED_DBUS_INTERFACE_ERROR "." MICROFEED_ERROR_UNKNOWN, "Instantiation of a publisher failed.");
00192 dbus_connection_send(connection, reply, NULL);
00193 dbus_message_unref(reply);
00194 result = DBUS_HANDLER_RESULT_HANDLED;
00195 }
00196 } else {
00197 reply = dbus_message_new_error(message, MICROFEED_DBUS_INTERFACE_ERROR "." MICROFEED_ERROR_NO_SUCH_PUBLISHER, "Publisher does not exist.");
00198 dbus_connection_send(connection, reply, NULL);
00199 dbus_message_unref(reply);
00200 result = DBUS_HANDLER_RESULT_HANDLED;
00201 }
00202 }
00203
00204 return result;
00205 }
00206
00207 static void no_more_subscribers(MicrofeedPublisher* publisher, void* user_data) {
00208 MicrofeedProvider* provider;
00209
00210 provider = microfeed_publisher_get_provider(publisher);
00211 if (provider->callbacks.publisher_callbacks.no_more_subscribers) {
00212 provider->callbacks.publisher_callbacks.no_more_subscribers(publisher, user_data);
00213 }
00214 microfeed_store_remove(provider->publishers, publisher);
00215 microfeed_publisher_free(publisher);
00216 if (microfeed_store_get_size(provider->publishers) == 0) {
00217 provider->callbacks.no_more_publishers(provider, provider->user_data);
00218 }
00219 }
00220