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