00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <microfeed-subscriber/microfeedsubscriber.h>
00020 #include <microfeed-common/microfeedmisc.h>
00021 #include <microfeed-common/microfeedconfiguration.h>
00022 #include <microfeed-common/microfeedprotocol.h>
00023
00024 #include <stdio.h>
00025 #include <stdlib.h>
00026 #include <string.h>
00027 #include <time.h>
00028 #include <sys/types.h>
00029 #include <dirent.h>
00030
00031
00032
00033 struct _MicrofeedSubscriber {
00034 char* identifier;
00035 DBusConnection* connection;
00036 char* object_path;
00037 MicrofeedConfiguration* configuration;
00038 unsigned int max_retries;
00039
00040 MicrofeedStore* publishers_by_identifier;
00041 MicrofeedStore* providers_by_bus_name;
00042 MicrofeedStore* providers_by_unique_connection_name;
00043 };
00044
00045 typedef struct {
00046 MicrofeedSubscriber* subscriber;
00047 char* bus_name;
00048 char* unique_connection_name;
00049 MicrofeedStore* publishers_by_object_path;
00050 } Provider;
00051
00052 typedef struct {
00053 unsigned int reference_count;
00054 Provider* provider;
00055 char* identifier;
00056 char* object_path;
00057 time_t last_activity;
00058 MicrofeedStore* feeds;
00059 } Publisher;
00060
00061 typedef struct _Subscription Subscription;
00062 struct _Subscription {
00063 Subscription* next;
00064 Subscription* previous;
00065 MicrofeedSubscriberCallbacks* callbacks;
00066 void* user_data;
00067 };
00068
00069 typedef struct {
00070 unsigned int reference_count;
00071 Publisher* publisher;
00072 char* uri;
00073 char* name;
00074 Subscription* subscriptions;
00075 } Feed;
00076
00077
00078 typedef struct {
00079 const char* name;
00080 void (*callback)(MicrofeedSubscriber* subscriber, Publisher* publisher, DBusMessage* message);
00081 } SignalCallback;
00082
00083 typedef struct {
00084 Publisher* publisher;
00085 char* uri;
00086 char* uid;
00087 DBusMessage* message;
00088 unsigned int retry_counter;
00089 MicrofeedSubscriberErrorCallback callback;
00090 void* user_data;
00091 } MethodReturnData;
00092
00093 static Provider* provider_new(MicrofeedSubscriber* subscriber, const char* bus_name);
00094 static void provider_free(Provider* provider);
00095 static const char* provider_get_bus_name(Provider* provider);
00096 static const char* provider_get_unique_connection_name(Provider* provider);
00097 static void provider_set_unique_connection_name(Provider* provider, const char* unique_connection_name);
00098
00099 static Publisher* publisher_new(Provider* provider, const char* identifier);
00100 static void publisher_free(Publisher* publisher);
00101 static Publisher* publisher_ref(Publisher* publisher);
00102 static void publisher_unref(Publisher* publisher);
00103 static const char* publisher_get_identifier(Publisher* publisher);
00104 static const char* publisher_get_object_path(Publisher* publisher);
00105
00106 static Feed* feed_new(Publisher* publisher, const char* uri);
00107 static void feed_free(Feed* feed);
00108 static const char* feed_get_uri(Feed* feed);
00109 static void feed_add_subscription(Feed* feed, MicrofeedSubscriberCallbacks* callbacks, void* user_data);
00110 static void feed_remove_subscription(Feed* feed, MicrofeedSubscriberCallbacks* callbacks, void* user_data);
00111
00112 static void call_publisher_method(Publisher* publisher, const char* uri, const char* uid, DBusMessage* message, MicrofeedSubscriberErrorCallback callback, void* user_data);
00113 static MicrofeedItem* parse_item_from_message(DBusMessageIter* iter);
00114 static int parse_item_signal(Publisher* publisher, DBusMessage* message, Feed** feed_return, MicrofeedItem** item_return);
00115 static int parse_feed_signal(Publisher* publisher, DBusMessage* message, Feed** feed_return);
00116 static Publisher* get_publisher(MicrofeedSubscriber* subscriber, const char* publisher_identifier, const char* uri, const char* uid, MicrofeedSubscriberErrorCallback callback, void* user_data);
00117 static Feed* get_feed(MicrofeedSubscriber* subscriber, const char* publisher_identifier, const char* uri, const char* uid, MicrofeedSubscriberErrorCallback callback, void* user_data);
00118 static void object_unregister(DBusConnection* connection, void* user_data);
00119 static DBusHandlerResult object_message(DBusConnection* connection, DBusMessage* message, void* user_data);
00120
00121 static void signal_feed_update_started(MicrofeedSubscriber* subscriber, Publisher* publisher, DBusMessage* message);
00122 static void signal_feed_update_ended(MicrofeedSubscriber* subscriber, Publisher* publisher, DBusMessage* message);
00123 static void signal_feed_republishing_started(MicrofeedSubscriber* subscriber, Publisher* publisher, DBusMessage* message);
00124 static void signal_feed_republishing_ended(MicrofeedSubscriber* subscriber, Publisher* publisher, DBusMessage* message);
00125 static void signal_item_data(MicrofeedSubscriber* subscriber, Publisher* publisher, DBusMessage* message);
00126 static void signal_item_added(MicrofeedSubscriber* subscriber, Publisher* publisher, DBusMessage* message);
00127 static void signal_item_changed(MicrofeedSubscriber* subscriber, Publisher* publisher, DBusMessage* message);
00128 static void signal_item_republished(MicrofeedSubscriber* subscriber, Publisher* publisher, DBusMessage* message);
00129 static void signal_item_removed(MicrofeedSubscriber* subscriber, Publisher* publisher, DBusMessage* message);
00130 static void signal_item_status_changed(MicrofeedSubscriber* subscriber, Publisher* publisher, DBusMessage* message);
00131
00132 static SignalCallback signal_callbacks[] = {
00133 { MICROFEED_SIGNAL_NAME_FEED_UPDATE_STARTED, signal_feed_update_started },
00134 { MICROFEED_SIGNAL_NAME_FEED_UPDATE_ENDED, signal_feed_update_ended },
00135 { MICROFEED_SIGNAL_NAME_FEED_REPUBLISHING_STARTED, signal_feed_republishing_started },
00136 { MICROFEED_SIGNAL_NAME_FEED_REPUBLISHING_ENDED, signal_feed_republishing_ended },
00137 { MICROFEED_SIGNAL_NAME_ITEM_DATA, signal_item_data },
00138 { MICROFEED_SIGNAL_NAME_ITEM_ADDED, signal_item_added },
00139 { MICROFEED_SIGNAL_NAME_ITEM_CHANGED, signal_item_changed },
00140 { MICROFEED_SIGNAL_NAME_ITEM_REPUBLISHED, signal_item_republished },
00141 { MICROFEED_SIGNAL_NAME_ITEM_REMOVED, signal_item_removed },
00142 { MICROFEED_SIGNAL_NAME_ITEM_STATUS_CHANGED, signal_item_status_changed },
00143 { NULL, NULL }
00144 };
00145
00146 static DBusObjectPathVTable object_vtable = {
00147 object_unregister,
00148 object_message
00149 };
00150
00151 static unsigned int subscriber_count = 0;
00152
00153 MicrofeedSubscriber* microfeed_subscriber_new(const char* identifier, DBusConnection* connection) {
00154 MicrofeedSubscriber* subscriber;
00155 char buffer[1024];
00156
00157 subscriber = microfeed_memory_allocate(MicrofeedSubscriber);
00158 subscriber->identifier = strdup(identifier);
00159 subscriber->connection = connection;
00160 snprintf(buffer, 1024, "%s%u", MICROFEED_DBUS_OBJECT_PATH_PREFIX_SUBSCRIBER, subscriber_count++);
00161 subscriber->object_path = strdup(buffer);
00162 subscriber->configuration = microfeed_configuration_new();
00163 subscriber->max_retries = 3;
00164
00165 subscriber->publishers_by_identifier = microfeed_store_new_sorted((MicrofeedStoreCompareKeysFunction)strcmp,
00166 (MicrofeedStoreGetKeyFunction)publisher_get_identifier);
00167 subscriber->providers_by_bus_name = microfeed_store_new_sorted((MicrofeedStoreCompareKeysFunction)strcmp,
00168 (MicrofeedStoreGetKeyFunction)provider_get_bus_name);
00169 subscriber->providers_by_unique_connection_name = microfeed_store_new_sorted((MicrofeedStoreCompareKeysFunction)strcmp,
00170 (MicrofeedStoreGetKeyFunction)provider_get_unique_connection_name);
00171
00172 if (!dbus_connection_register_object_path(subscriber->connection, subscriber->object_path, &object_vtable, subscriber)) {
00173
00174 return NULL;
00175 }
00176 if (!dbus_connection_add_filter(subscriber->connection, object_message, subscriber, NULL)) {
00177
00178 return NULL;
00179 }
00180
00181 snprintf(buffer, 1024, "type='signal',interface='%s',destination='%s'", MICROFEED_DBUS_INTERFACE_PUBLISHER_TO_DESTINATION, dbus_bus_get_unique_name(subscriber->connection));
00182 dbus_bus_add_match(subscriber->connection, buffer, NULL);
00183 snprintf(buffer, 1024, "type='signal',interface='%s',destination ='%s'", MICROFEED_DBUS_INTERFACE_ERROR_TO_DESTINATION, dbus_bus_get_unique_name(subscriber->connection));
00184 dbus_bus_add_match(subscriber->connection, buffer, NULL);
00185
00186 return subscriber;
00187 }
00188
00192 void microfeed_subscriber_free(MicrofeedSubscriber* subscriber) {
00193 char buffer[1024];
00194
00195 snprintf(buffer, 1024, "type='signal',interface='%s',destination='%s'", MICROFEED_DBUS_INTERFACE_PUBLISHER_TO_DESTINATION, dbus_bus_get_unique_name(subscriber->connection));
00196 dbus_bus_remove_match(subscriber->connection, buffer, NULL);
00197 snprintf(buffer, 1024, "type='signal',interface='%s',destination ='%s'", MICROFEED_DBUS_INTERFACE_ERROR_TO_DESTINATION, dbus_bus_get_unique_name(subscriber->connection));
00198 dbus_bus_remove_match(subscriber->connection, buffer, NULL);
00199
00200
00201 }
00202
00203 const char* microfeed_subscriber_get_identifier(MicrofeedSubscriber* subscriber) {
00204
00205 return subscriber->identifier;
00206 }
00207
00208 int microfeed_subscriber_add_item(MicrofeedSubscriber* subscriber, const char* publisher_identifier, const char* uri, MicrofeedItem* item, MicrofeedSubscriberErrorCallback callback, void* user_data) {
00209 int retvalue = 0;
00210 Publisher* publisher;
00211 DBusMessage* message;
00212 DBusMessageIter iter;
00213 const char* uid;
00214 MicrofeedItemIterator* iterator;
00215 const char* key;
00216 const char* value;
00217
00218 if ((publisher = get_publisher(subscriber, publisher_identifier, uri, microfeed_item_get_uid(item), callback, user_data))) {
00219 message = dbus_message_new_method_call(publisher->provider->bus_name, publisher->object_path, MICROFEED_DBUS_INTERFACE_PUBLISHER, MICROFEED_METHOD_NAME_ADD_ITEM);
00220 dbus_message_iter_init_append(message, &iter);
00221 uid = microfeed_item_get_uid(item);
00222 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &uri);
00223 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &uid);
00224 for (iterator = microfeed_item_iterate_properties(item, NULL);
00225 microfeed_item_iterator_get(iterator, &key, &value);
00226 microfeed_item_iterator_next(iterator)) {
00227 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key);
00228 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &value);
00229 }
00230 microfeed_item_iterator_free(iterator);
00231 call_publisher_method(publisher, uri, microfeed_item_get_uid(item), message, callback, user_data);
00232 dbus_message_unref(message);
00233 retvalue = 1;
00234 }
00235
00236 return retvalue;
00237 }
00238
00239 int microfeed_subscriber_modify_item(MicrofeedSubscriber*subscriber, const char* publisher_identifier, const char* uri, MicrofeedItem* item, MicrofeedSubscriberErrorCallback callback, void* user_data) {
00240 int retvalue = 0;
00241 Publisher* publisher;
00242 DBusMessage* message;
00243 DBusMessageIter iter;
00244 const char* uid;
00245 MicrofeedItemIterator* iterator;
00246 const char* key;
00247 const char* value;
00248
00249 if ((publisher = get_publisher(subscriber, publisher_identifier, uri, microfeed_item_get_uid(item), callback, user_data))) {
00250 message = dbus_message_new_method_call(publisher->provider->bus_name, publisher->object_path, MICROFEED_DBUS_INTERFACE_PUBLISHER, MICROFEED_METHOD_NAME_MODIFY_ITEM);
00251 dbus_message_iter_init_append(message, &iter);
00252 uid = microfeed_item_get_uid(item);
00253 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &uri);
00254 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &uid);
00255 for (iterator = microfeed_item_iterate_properties(item, NULL);
00256 microfeed_item_iterator_get(iterator, &key, &value);
00257 microfeed_item_iterator_next(iterator)) {
00258 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key);
00259 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &value);
00260 }
00261 microfeed_item_iterator_free(iterator);
00262 call_publisher_method(publisher, uri, microfeed_item_get_uid(item), message, callback, user_data);
00263 dbus_message_unref(message);
00264 retvalue = 1;
00265 }
00266
00267 return retvalue;
00268 }
00269
00270 int microfeed_subscriber_remove_item(MicrofeedSubscriber* subscriber, const char* publisher_identifier, const char* uri, const char* uid, MicrofeedSubscriberReplyCallback callback, void* user_data) {
00271 int retvalue = 0;
00272 Publisher* publisher;
00273 DBusMessage* message;
00274
00275 if ((publisher = get_publisher(subscriber, publisher_identifier, uri, uid, callback, user_data))) {
00276 message = dbus_message_new_method_call(publisher->provider->bus_name, publisher->object_path, MICROFEED_DBUS_INTERFACE_PUBLISHER, MICROFEED_METHOD_NAME_REMOVE_ITEM);
00277 dbus_message_append_args(message, DBUS_TYPE_STRING, &uri, DBUS_TYPE_STRING, &uid, DBUS_TYPE_INVALID);
00278 call_publisher_method(publisher, uri, uid, message, callback, user_data);
00279 dbus_message_unref(message);
00280 retvalue = 1;
00281 }
00282
00283 return retvalue;
00284
00285 }
00286
00287 int microfeed_subscriber_subscribe_feed(MicrofeedSubscriber* subscriber, const char* publisher_identifier, const char* uri, MicrofeedSubscriberCallbacks* callbacks, void* callbacks_user_data, MicrofeedSubscriberErrorCallback callback, void* user_data) {
00288 int retvalue = 0;
00289 Publisher* publisher;
00290 Feed* feed;
00291 DBusMessage* message;
00292 char buffer[1024];
00293
00294 if ((publisher = get_publisher(subscriber, publisher_identifier, uri, NULL, callback, user_data))) {
00295 if ((feed = microfeed_store_get(publisher->feeds, uri, Feed))) {
00296 feed_add_subscription(feed, callbacks, callbacks_user_data);
00297 if (callback) {
00298 callback(subscriber, publisher_identifier, uri, NULL, NULL, NULL, user_data);
00299 }
00300 } else {
00301 feed = feed_new(publisher, uri);
00302 feed_add_subscription(feed, callbacks, callbacks_user_data);
00303
00304 snprintf(buffer, 1024, "type='signal',path='%s',interface='%s',arg0='%s'", publisher->object_path, MICROFEED_DBUS_INTERFACE_PUBLISHER, uri);
00305 printf("%s : %d\n", buffer);
00306 dbus_bus_add_match(subscriber->connection, buffer, NULL);
00307 snprintf(buffer, 1024, "type='signal',path='%s',interface='%s',arg0='%s'", publisher->object_path, MICROFEED_DBUS_INTERFACE_ERROR, uri);
00308 dbus_bus_add_match(subscriber->connection, buffer, NULL);
00309
00310 message = dbus_message_new_method_call(feed->publisher->provider->bus_name, feed->publisher->object_path, MICROFEED_DBUS_INTERFACE_PUBLISHER, MICROFEED_METHOD_NAME_SUBSCRIBE_FEED);
00311 dbus_message_append_args(message, DBUS_TYPE_STRING, &feed->uri, DBUS_TYPE_INVALID);
00312 call_publisher_method(publisher, uri, NULL, message, callback, user_data);
00313 dbus_message_unref(message);
00314 retvalue = 1;
00315 }
00316 }
00317
00318 return retvalue;
00319 }
00320
00321 int microfeed_subscriber_unsubscribe_feed(MicrofeedSubscriber* subscriber, const char* publisher_identifier, const char* uri, MicrofeedSubscriberCallbacks* callbacks, void* callbacks_user_data, MicrofeedSubscriberErrorCallback callback, void* user_data) {
00322 int retvalue = 0;
00323 Feed* feed;
00324 Publisher* publisher;
00325 DBusMessage* message;
00326 char buffer[1024];
00327
00328 if ((feed = get_feed(subscriber, publisher_identifier, uri, NULL, callback, user_data))) {
00329 publisher = feed->publisher;
00330 feed_remove_subscription(feed, callbacks, callbacks_user_data);
00331 if (feed->subscriptions) {
00332 if (callback) {
00333 callback(subscriber, publisher_identifier, uri, NULL, NULL, NULL, user_data);
00334 }
00335 } else {
00336 snprintf(buffer, 1024, "type='signal',path='%s',interface='%s',arg0='%s'", publisher->object_path, MICROFEED_DBUS_INTERFACE_PUBLISHER, uri);
00337 dbus_bus_remove_match(subscriber->connection, buffer, NULL);
00338 snprintf(buffer, 1024, "type='signal',path='%s',interface='%s',arg0='%s'", publisher->object_path, MICROFEED_DBUS_INTERFACE_ERROR, uri);
00339 dbus_bus_remove_match(subscriber->connection, buffer, NULL);
00340
00341 message = dbus_message_new_method_call(feed->publisher->provider->bus_name, feed->publisher->object_path, MICROFEED_DBUS_INTERFACE_PUBLISHER, MICROFEED_METHOD_NAME_UNSUBSCRIBE_FEED);
00342 dbus_message_append_args(message, DBUS_TYPE_STRING, &feed->uri, DBUS_TYPE_INVALID);
00343 call_publisher_method(feed->publisher, feed->uri, NULL, message, callback, user_data);
00344 dbus_message_unref(message);
00345 retvalue = 1;
00346
00347 publisher = feed->publisher;
00348 feed_free(feed);
00349 if (microfeed_store_get_size(publisher->feeds) == 0) {
00350 publisher_unref(publisher);
00351 }
00352 }
00353 }
00354
00355 return retvalue;
00356 }
00357
00358 int microfeed_subscriber_update_feed(MicrofeedSubscriber* subscriber, const char* publisher_identifier, const char* uri, MicrofeedSubscriberErrorCallback callback, void* user_data) {
00359 int retvalue = 0;
00360 Feed* feed;
00361 DBusMessage* message;
00362
00363 if ((feed = get_feed(subscriber, publisher_identifier, uri, NULL, callback, user_data))) {
00364 message = dbus_message_new_method_call(feed->publisher->provider->bus_name, feed->publisher->object_path, MICROFEED_DBUS_INTERFACE_PUBLISHER, MICROFEED_METHOD_NAME_UPDATE_FEED);
00365 dbus_message_append_args(message, DBUS_TYPE_STRING, &uri, DBUS_TYPE_INVALID);
00366 call_publisher_method(feed->publisher, feed->uri, NULL, message, callback, user_data);
00367 dbus_message_unref(message);
00368 retvalue = 1;
00369 }
00370
00371 return retvalue;
00372 }
00373
00374 int microfeed_subscriber_republish_items(MicrofeedSubscriber* subscriber, const char* publisher_identifier, const char* uri, const char* start_uid, const char* end_uid, unsigned int max_count, MicrofeedSubscriberErrorCallback callback, void* user_data) {
00375 int retvalue = 0;
00376 Feed* feed;
00377 DBusMessage* message;
00378 const char* start_uid_dbus;
00379 const char* end_uid_dbus;
00380 dbus_uint16_t max_count_dbus;
00381
00382 if ((feed = get_feed(subscriber, publisher_identifier, uri, start_uid, callback, user_data))) {
00383 message = dbus_message_new_method_call(feed->publisher->provider->bus_name, feed->publisher->object_path, MICROFEED_DBUS_INTERFACE_PUBLISHER, MICROFEED_METHOD_NAME_REPUBLISH_ITEMS);
00384 start_uid_dbus = (start_uid ? start_uid : "");
00385 end_uid_dbus = (end_uid ? end_uid : "");
00386 max_count_dbus = max_count;
00387 dbus_message_append_args(message, DBUS_TYPE_STRING, &uri, DBUS_TYPE_STRING, &start_uid_dbus, DBUS_TYPE_STRING, &end_uid_dbus, DBUS_TYPE_UINT16, &max_count_dbus, DBUS_TYPE_INVALID);
00388 call_publisher_method(feed->publisher, feed->uri, start_uid, message, callback, user_data);
00389 dbus_message_unref(message);
00390 retvalue = 1;
00391 }
00392
00393 return retvalue;
00394 }
00395
00396 int microfeed_subscriber_send_item_data(MicrofeedSubscriber* subscriber, const char* publisher_identifier, const char* uri, const char* uid, MicrofeedSubscriberErrorCallback callback, void* user_data) {
00397 int retvalue = 0;
00398 Publisher* publisher;
00399 DBusMessage* message;
00400
00401 if ((publisher = get_publisher(subscriber, publisher_identifier, NULL, uid, callback, user_data))) {
00402 message = dbus_message_new_method_call(publisher->provider->bus_name, publisher->object_path, MICROFEED_DBUS_INTERFACE_PUBLISHER, MICROFEED_METHOD_NAME_SEND_ITEM_DATA);
00403 dbus_message_append_args(message, DBUS_TYPE_STRING, &uri, DBUS_TYPE_STRING, &uid, DBUS_TYPE_INVALID);
00404 call_publisher_method(publisher, NULL, uid, message, callback, user_data);
00405 dbus_message_unref(message);
00406 retvalue = 1;
00407 }
00408
00409 return retvalue;
00410 }
00411
00412 int microfeed_subscriber_create_publisher(MicrofeedSubscriber* subscriber, const char* publisher_identifier, MicrofeedSubscriberErrorCallback callback, void* user_data) {
00413 int retvalue = 0;
00414 Publisher* publisher;
00415 DBusMessage* message;
00416
00417 microfeed_configuration_invalidate(subscriber->configuration);
00418 if (microfeed_configuration_get_publisher_directory(subscriber->configuration, publisher_identifier)) {
00419 if (callback) {
00420 callback(subscriber, publisher_identifier, NULL, NULL, MICROFEED_ERROR_PUBLISHER_ALREADY_EXISTS, "Trying to create a publisher that already exists.", user_data);
00421 }
00422 } else if ((publisher = get_publisher(subscriber, publisher_identifier, NULL, NULL, callback, user_data))) {
00423 message = dbus_message_new_method_call(publisher->provider->bus_name, publisher->object_path, MICROFEED_DBUS_INTERFACE_PUBLISHER, MICROFEED_METHOD_NAME_CREATE_PUBLISHER);
00424 call_publisher_method(publisher, NULL, NULL, message, callback, user_data);
00425 dbus_message_unref(message);
00426 retvalue = 1;
00427 }
00428
00429 return retvalue;
00430 }
00431
00432 int microfeed_subscriber_destroy_publisher(MicrofeedSubscriber* subscriber, const char* publisher_identifier, MicrofeedSubscriberErrorCallback callback, void* user_data) {
00433 int retvalue = 0;
00434 Publisher* publisher;
00435 DBusMessage* message;
00436
00437 if ((publisher = get_publisher(subscriber, publisher_identifier, NULL, NULL, callback, user_data))) {
00438 message = dbus_message_new_method_call(publisher->provider->bus_name, publisher->object_path, MICROFEED_DBUS_INTERFACE_PUBLISHER, MICROFEED_METHOD_NAME_DESTROY_PUBLISHER);
00439 call_publisher_method(publisher, NULL, NULL, message, callback, user_data);
00440 dbus_message_unref(message);
00441 retvalue = 1;
00442 }
00443
00444 return retvalue;
00445 }
00446
00447 int microfeed_subscriber_mark_item(MicrofeedSubscriber* subscriber, const char* publisher_identifier, const char* uri, const char* uid, MicrofeedSubscriberErrorCallback callback, void* user_data) {
00448 int retvalue = 0;
00449 Publisher* publisher;
00450 DBusMessage* message;
00451
00452 if ((publisher = get_publisher(subscriber, publisher_identifier, NULL, NULL, callback, user_data))) {
00453 message = dbus_message_new_method_call(publisher->provider->bus_name, publisher->object_path, MICROFEED_DBUS_INTERFACE_PUBLISHER, MICROFEED_METHOD_NAME_MARK_ITEM);
00454 dbus_message_append_args(message, DBUS_TYPE_STRING, &uri, DBUS_TYPE_STRING, &uid, DBUS_TYPE_INVALID);
00455 call_publisher_method(publisher, uri, uid, message, callback, user_data);
00456 dbus_message_unref(message);
00457 retvalue = 1;
00458 }
00459
00460 return retvalue;
00461 }
00462
00463 int microfeed_subscriber_unmark_item(MicrofeedSubscriber* subscriber, const char* publisher_identifier, const char* uri, const char* uid, MicrofeedSubscriberErrorCallback callback, void* user_data) {
00464 int retvalue = 0;
00465 Publisher* publisher;
00466 DBusMessage* message;
00467
00468 if ((publisher = get_publisher(subscriber, publisher_identifier, NULL, NULL, callback, user_data))) {
00469 message = dbus_message_new_method_call(publisher->provider->bus_name, publisher->object_path, MICROFEED_DBUS_INTERFACE_PUBLISHER, MICROFEED_METHOD_NAME_UNMARK_ITEM);
00470 dbus_message_append_args(message, DBUS_TYPE_STRING, &uri, DBUS_TYPE_STRING, &uid, DBUS_TYPE_INVALID);
00471 call_publisher_method(publisher, uri, uid, message, callback, user_data);
00472 dbus_message_unref(message);
00473 retvalue = 1;
00474 }
00475
00476 return retvalue;
00477 }
00478
00479 int microfeed_subscriber_read_items(MicrofeedSubscriber* subscriber, const char* publisher_identifier, const char* uri, const char* start_uid, const char* end_uid, MicrofeedSubscriberReplyCallback callback, void* user_data) {
00480 int retvalue = 0;
00481 Feed* feed;
00482 DBusMessage* message;
00483 const char* start_uid_dbus;
00484 const char* end_uid_dbus;
00485
00486 if ((feed = get_feed(subscriber, publisher_identifier, uri, start_uid, callback, user_data))) {
00487 message = dbus_message_new_method_call(feed->publisher->provider->bus_name, feed->publisher->object_path, MICROFEED_DBUS_INTERFACE_PUBLISHER, MICROFEED_METHOD_NAME_READ_ITEMS);
00488 start_uid_dbus = (start_uid ? start_uid : "");
00489 end_uid_dbus = (end_uid ? end_uid : "");
00490 dbus_message_append_args(message, DBUS_TYPE_STRING, &uri, DBUS_TYPE_STRING, &start_uid_dbus, DBUS_TYPE_STRING, &end_uid_dbus, DBUS_TYPE_INVALID);
00491 call_publisher_method(feed->publisher, feed->uri, start_uid, message, callback, user_data);
00492 dbus_message_unref(message);
00493 retvalue = 1;
00494 }
00495
00496 return retvalue;
00497 }
00498
00499
00500 MicrofeedConfiguration* microfeed_subscriber_get_configuration(MicrofeedSubscriber* subscriber) {
00501
00502 return subscriber->configuration;
00503 }
00504
00505 int microfeed_subscriber_handle_configured_subscriptions(MicrofeedSubscriber* subscriber, MicrofeedSubscriberConfiguredSubscribeCallback configured_subscribe, MicrofeedSubscriberConfiguredUnsubscribeCallback configured_unsubscribe, void* user_data) {
00506 int retvalue = 0;
00507 const char** subscriptions;
00508 const char** s;
00509 MicrofeedStoreIterator* publishers_iterator;
00510 Publisher* publisher;
00511 MicrofeedStoreIterator* feeds_iterator;
00512 Feed* feed;
00513 Subscription* subscription;
00514
00515 microfeed_configuration_invalidate(subscriber->configuration);
00516 if ((subscriptions = microfeed_configuration_get_subscriptions(subscriber->configuration, subscriber->identifier))) {
00517 retvalue = 1;
00518
00519
00520 for (s = subscriptions; *s; s++) {
00521 if (!microfeed_store_get(subscriber->publishers_by_identifier, *s, Publisher)) {
00522 configured_subscribe(subscriber, *s, user_data);
00523 }
00524 }
00525
00526
00527 for (publishers_iterator = microfeed_store_iterate(subscriber->publishers_by_identifier, NULL);
00528 (publisher = microfeed_store_iterator_get(publishers_iterator, Publisher));
00529 microfeed_store_iterator_next(publishers_iterator)) {
00530 for (s = subscriptions; *s; s++) {
00531 if (!strcmp(publisher->identifier, *s)) {
00532 break;
00533 }
00534 }
00535 if (!*s) {
00536 for (feeds_iterator = microfeed_store_iterate(publisher->feeds, NULL);
00537 (feed = microfeed_store_iterator_get(feeds_iterator, Feed));
00538 microfeed_store_iterator_next(feeds_iterator)) {
00539 for (subscription = feed->subscriptions; subscription; subscription = subscription->next) {
00540 configured_unsubscribe(subscriber, publisher->identifier, feed->uri, subscription->callbacks, subscription->user_data, user_data);
00541 }
00542 }
00543 }
00544 }
00545 }
00546
00547 return retvalue;
00548 }
00549
00550 static Provider* provider_new(MicrofeedSubscriber* subscriber, const char* bus_name) {
00551 Provider* provider;
00552
00553 provider = microfeed_memory_allocate(Provider);
00554 provider->subscriber = subscriber;
00555 provider->bus_name = strdup(bus_name);
00556 provider->publishers_by_object_path = microfeed_store_new_sorted((MicrofeedStoreCompareKeysFunction)strcmp,
00557 (MicrofeedStoreGetKeyFunction)publisher_get_object_path);
00558
00559 microfeed_store_insert(subscriber->providers_by_bus_name, provider);
00560
00561 return provider;
00562 }
00563
00564 static void provider_free(Provider* provider) {
00565 microfeed_store_remove(provider->subscriber->providers_by_bus_name, provider);
00566 provider_set_unique_connection_name(provider, NULL);
00567
00568 free(provider->bus_name);
00569 free(provider->unique_connection_name);
00570 microfeed_store_free(provider->publishers_by_object_path);
00571 provider->subscriber = NULL;
00572 provider->bus_name = NULL;
00573 provider->unique_connection_name = NULL;
00574 provider->publishers_by_object_path = NULL;
00575 microfeed_memory_free(provider);
00576 }
00577
00578 static const char* provider_get_bus_name(Provider* provider) {
00579
00580 return provider->bus_name;
00581 }
00582
00583 static const char* provider_get_unique_connection_name(Provider* provider) {
00584
00585 return (provider->unique_connection_name ? provider->unique_connection_name : "");
00586 }
00587
00588 static void provider_set_unique_connection_name(Provider* provider, const char* unique_connection_name) {
00589 char buffer[1024];
00590
00591 if (unique_connection_name) {
00592 if (provider->unique_connection_name) {
00593 provider_set_unique_connection_name(provider, NULL);
00594 }
00595 provider->unique_connection_name = strdup(unique_connection_name);
00596 microfeed_store_insert(provider->subscriber->providers_by_unique_connection_name, provider);
00597
00598 snprintf(buffer, 1024, "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',arg0='%s'", provider->unique_connection_name);
00599 dbus_bus_add_match(provider->subscriber->connection, buffer, NULL);
00600 } else if (provider->unique_connection_name) {
00601 snprintf(buffer, 1024, "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',arg0='%s'", provider->unique_connection_name);
00602 dbus_bus_remove_match(provider->subscriber->connection, buffer, NULL);
00603
00604 microfeed_store_remove(provider->subscriber->providers_by_unique_connection_name, provider);
00605 free(provider->unique_connection_name);
00606 provider->unique_connection_name = NULL;
00607 }
00608 }
00609
00610 static Publisher* publisher_new(Provider* provider, const char* identifier) {
00611 Publisher* publisher = NULL;
00612 char* separator;
00613
00614 publisher = microfeed_memory_allocate(Publisher);
00615 publisher->reference_count = 1;
00616 publisher->identifier = strdup(identifier);
00617 if ((separator = strchr(publisher->identifier, MICROFEED_PUBLISHER_IDENTIFIER_SEPARATOR_CHAR))) {
00618 *separator = 0;
00619 publisher->object_path = microfeed_util_string_concatenate(MICROFEED_DBUS_OBJECT_PATH_PREFIX_PUBLISHER, publisher->identifier, NULL);
00620 *separator = MICROFEED_PUBLISHER_IDENTIFIER_SEPARATOR_CHAR;
00621 } else {
00622 publisher->object_path = strdup(identifier);
00623 }
00624 publisher->feeds = microfeed_store_new_sorted((MicrofeedStoreCompareKeysFunction)strcmp,
00625 (MicrofeedStoreGetKeyFunction)feed_get_uri);
00626 publisher->provider = provider;
00627
00628 microfeed_store_insert(provider->publishers_by_object_path, publisher);
00629 microfeed_store_insert(provider->subscriber->publishers_by_identifier, publisher);
00630
00631 return publisher;
00632 }
00633
00634 static void publisher_free(Publisher* publisher) {
00635 microfeed_store_remove(publisher->provider->subscriber->publishers_by_identifier, publisher);
00636 microfeed_store_remove(publisher->provider->publishers_by_object_path, publisher);
00637 if (microfeed_store_get_size(publisher->provider->publishers_by_object_path) == 0) {
00638 provider_free(publisher->provider);
00639 }
00640
00641 free(publisher->identifier);
00642 free(publisher->object_path);
00643 publisher->provider = NULL;
00644 publisher->identifier = NULL;
00645 publisher->object_path = NULL;
00646 microfeed_store_free(publisher->feeds);
00647 microfeed_memory_free(publisher);
00648 }
00649
00650 static Publisher* publisher_ref(Publisher* publisher) {
00651 publisher->reference_count++;
00652
00653 return publisher;
00654 }
00655
00656 static void publisher_unref(Publisher* publisher) {
00657 publisher->reference_count--;
00658 if (publisher->reference_count == 0) {
00659 publisher_free(publisher);
00660 }
00661 }
00662
00663 static const char* publisher_get_identifier(Publisher* publisher) {
00664
00665 return publisher->identifier;
00666 }
00667
00668 static const char* publisher_get_object_path(Publisher* publisher) {
00669
00670 return publisher->object_path;
00671 }
00672
00673 static Feed* feed_new(Publisher* publisher, const char* uri) {
00674 Feed* feed;
00675
00676 feed = microfeed_memory_allocate(Feed);
00677 feed->reference_count = 1;
00678 feed->publisher = publisher;
00679 feed->uri = strdup(uri);
00680
00681 microfeed_store_insert(publisher->feeds, feed);
00682
00683 return feed;
00684 }
00685
00686 static void feed_free(Feed* feed) {
00687 microfeed_store_remove(feed->publisher->feeds, feed);
00688
00689 free(feed->uri);
00690 free(feed->name);
00691 feed->publisher = NULL;
00692 feed->uri = NULL;
00693 feed->name = NULL;
00694 microfeed_memory_free(feed);
00695 }
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711 static const char* feed_get_uri(Feed* feed) {
00712
00713 return feed->uri;
00714 }
00715
00716 static void feed_add_subscription(Feed* feed, MicrofeedSubscriberCallbacks* callbacks, void* user_data) {
00717 Subscription* s;
00718
00719 for (s = feed->subscriptions; s; s = s->next) {
00720 if (s->callbacks == callbacks && s->user_data == user_data) {
00721 break;
00722 }
00723 }
00724 if (!s) {
00725 s = microfeed_memory_allocate(Subscription);
00726 s->callbacks = callbacks;
00727 s->user_data = user_data;
00728
00729 s->next = feed->subscriptions;
00730 feed->subscriptions = s;
00731 }
00732 }
00733
00734 static void feed_remove_subscription(Feed* feed, MicrofeedSubscriberCallbacks* callbacks, void* user_data) {
00735 Subscription* s;
00736
00737 for (s = feed->subscriptions; s; s = s->next) {
00738 if (s->callbacks == callbacks && s->user_data == user_data) {
00739 break;
00740 }
00741 }
00742 if (s) {
00743 if (s->next) {
00744 s->next->previous = s->previous;
00745 }
00746 if (s->previous) {
00747 s->previous->next = s->next;
00748 } else {
00749 feed->subscriptions = s->next;
00750 }
00751
00752 microfeed_memory_free(s);
00753 }
00754 }
00755
00756 static void signal_feed_update_started(MicrofeedSubscriber* subscriber, Publisher* publisher, DBusMessage* message) {
00757 Feed* feed;
00758 Subscription* s;
00759
00760 if (parse_feed_signal(publisher, message, &feed)) {
00761 for (s = feed->subscriptions; s; s = s->next) {
00762 if (s->callbacks->feed_update_started) {
00763 s->callbacks->feed_update_started(subscriber, publisher->identifier, feed->uri, s->user_data);
00764 }
00765 }
00766 }
00767 }
00768
00769 static void signal_feed_update_ended(MicrofeedSubscriber* subscriber, Publisher* publisher, DBusMessage* message) {
00770 Feed* feed;
00771 Subscription* s;
00772
00773 if (parse_feed_signal(publisher, message, &feed)) {
00774 for (s = feed->subscriptions; s; s = s->next) {
00775 if (s->callbacks->feed_update_ended) {
00776 s->callbacks->feed_update_ended(subscriber, publisher->identifier, feed->uri, s->user_data);
00777 }
00778 }
00779 }
00780 }
00781
00782 static void signal_feed_republishing_started(MicrofeedSubscriber* subscriber, Publisher* publisher, DBusMessage* message) {
00783 Feed* feed;
00784 Subscription* s;
00785
00786 if (parse_feed_signal(publisher, message, &feed)) {
00787 for (s = feed->subscriptions; s; s = s->next) {
00788 if (s->callbacks->feed_republishing_started) {
00789 s->callbacks->feed_republishing_started(subscriber, publisher->identifier, feed->uri, s->user_data);
00790 }
00791 }
00792 }
00793 }
00794
00795 static void signal_feed_republishing_ended(MicrofeedSubscriber* subscriber, Publisher* publisher, DBusMessage* message) {
00796 Feed* feed;
00797 Subscription* s;
00798
00799 if (parse_feed_signal(publisher, message, &feed)) {
00800 for (s = feed->subscriptions; s; s = s->next) {
00801 if (s->callbacks->feed_republishing_ended) {
00802 s->callbacks->feed_republishing_ended(subscriber, publisher->identifier, feed->uri, s->user_data);
00803 }
00804 }
00805 }
00806 }
00807
00808 static void signal_item_data(MicrofeedSubscriber* subscriber, Publisher* publisher, DBusMessage* message) {
00809 DBusMessageIter iter;
00810 char* uri;
00811 Feed* feed;
00812 char* uid;
00813 DBusMessageIter subiter;
00814 char* data;
00815 int length;
00816 Subscription* s;
00817
00818 if (dbus_message_iter_init(message, &iter) && dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING) {
00819 dbus_message_iter_get_basic(&iter, &uri);
00820 if ((feed = microfeed_store_get(publisher->feeds, uri, Feed)) &&
00821 dbus_message_iter_next(&iter) && dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING) {
00822 dbus_message_iter_get_basic(&iter, &uid);
00823 if (dbus_message_iter_next(&iter) && dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_ARRAY &&
00824 dbus_message_iter_get_element_type(&iter) == DBUS_TYPE_BYTE) {
00825 dbus_message_iter_recurse(&iter, &subiter);
00826 dbus_message_iter_get_fixed_array(&subiter, &data, &length);
00827
00828 for (s = feed->subscriptions; s; s = s->next) {
00829 if (s->callbacks->item_data_received) {
00830 s->callbacks->item_data_received(subscriber, publisher->identifier, feed->uri, uid, data, length, s->user_data);
00831 }
00832 }
00833 }
00834 }
00835 }
00836 }
00837
00838 static void signal_item_added(MicrofeedSubscriber* subscriber, Publisher* publisher, DBusMessage* message) {
00839 Feed* feed;
00840 MicrofeedItem* item;
00841 Subscription* s;
00842
00843 if (parse_item_signal(publisher, message, &feed, &item)) {
00844 for (s = feed->subscriptions; s; s = s->next) {
00845 if (s->callbacks->item_added) {
00846 s->callbacks->item_added(subscriber, publisher->identifier, feed->uri, item, s->user_data);
00847 }
00848 }
00849 microfeed_item_free(item);
00850 }
00851 }
00852
00853 static void signal_item_changed(MicrofeedSubscriber* subscriber, Publisher* publisher, DBusMessage* message) {
00854 Feed* feed;
00855 MicrofeedItem* item;
00856 Subscription* s;
00857
00858 if (parse_item_signal(publisher, message, &feed, &item)) {
00859 for (s = feed->subscriptions; s; s = s->next) {
00860 if (s->callbacks->item_changed) {
00861 s->callbacks->item_changed(subscriber, publisher->identifier, feed->uri, item, s->user_data);
00862 }
00863 }
00864 microfeed_item_free(item);
00865 }
00866 }
00867
00868 static void signal_item_republished(MicrofeedSubscriber* subscriber, Publisher* publisher, DBusMessage* message) {
00869 Feed* feed;
00870 MicrofeedItem* item;
00871 Subscription* s;
00872
00873 if (parse_item_signal(publisher, message, &feed, &item)) {
00874 for (s = feed->subscriptions; s; s = s->next) {
00875 if (s->callbacks->item_republished) {
00876 s->callbacks->item_republished(subscriber, publisher->identifier, feed->uri, item, s->user_data);
00877 }
00878 }
00879 microfeed_item_free(item);
00880 }
00881 }
00882
00883 static void signal_item_removed(MicrofeedSubscriber* subscriber, Publisher* publisher, DBusMessage* message) {
00884 DBusError error;
00885 char* uri;
00886 char* uid;
00887 Feed* feed;
00888 Subscription* s;
00889
00890 dbus_error_init(&error);
00891 if (dbus_message_get_args(message, &error, DBUS_TYPE_STRING, &uri, DBUS_TYPE_STRING, &uid, DBUS_TYPE_INVALID) &&
00892 (feed = microfeed_store_get(publisher->feeds, uri, Feed))) {
00893 for (s = feed->subscriptions; s; s = s->next) {
00894 if (s->callbacks->item_republished) {
00895 s->callbacks->item_removed(subscriber, publisher->identifier, feed->uri, uid, s->user_data);
00896 }
00897 }
00898 }
00899 }
00900
00901 static void signal_item_status_changed(MicrofeedSubscriber* subscriber, Publisher* publisher, DBusMessage* message) {
00902 DBusError error;
00903 char* uri;
00904 char* uid;
00905 char status;
00906 Feed* feed;
00907 Subscription* s;
00908
00909 dbus_error_init(&error);
00910 if (dbus_message_get_args(message, &error, DBUS_TYPE_STRING, &uri, DBUS_TYPE_STRING, &uid, DBUS_TYPE_BYTE, &status, DBUS_TYPE_INVALID) &&
00911 (feed = microfeed_store_get(publisher->feeds, uri, Feed))) {
00912 for (s = feed->subscriptions; s; s = s->next) {
00913 if (s->callbacks->item_status_changed) {
00914 s->callbacks->item_status_changed(subscriber, publisher->identifier, feed->uri, uid, (MicrofeedItemStatus)status, s->user_data);
00915 }
00916 }
00917 }
00918 }
00919
00920 static Publisher* get_publisher(MicrofeedSubscriber* subscriber, const char* publisher_identifier, const char* uri, const char* uid, MicrofeedSubscriberErrorCallback callback, void* user_data) {
00921 Publisher* publisher;
00922 const char* bus_name;
00923 Provider* provider;
00924
00925 if (!(publisher = microfeed_store_get(subscriber->publishers_by_identifier, publisher_identifier, Publisher))) {
00926 if ((bus_name = strchr(publisher_identifier, MICROFEED_PUBLISHER_IDENTIFIER_SEPARATOR_CHAR)) && bus_name[1] != 0) {
00927 bus_name++;
00928 if (!(provider = microfeed_store_get(subscriber->providers_by_bus_name, bus_name, Provider))) {
00929 microfeed_configuration_invalidate(subscriber->configuration);
00930 if (microfeed_configuration_get_provider_name(subscriber->configuration, bus_name)) {
00931 provider = provider_new(subscriber, bus_name);
00932 } else if (callback) {
00933 callback(subscriber, publisher_identifier, uri, uid, MICROFEED_ERROR_NO_SUCH_PROVIDER, "Provider for the publisher does not exist.", user_data);
00934 }
00935 }
00936 if (provider) {
00937 publisher = publisher_new(provider, publisher_identifier);
00938 }
00939 } else if (callback) {
00940 callback(subscriber, publisher_identifier, uri, uid, MICROFEED_ERROR_INVALID_PUBLISHER_IDENTIFIER, "Publisher identifier was invalid.", user_data);
00941 }
00942 }
00943
00944 return publisher;
00945 }
00946
00947 static Feed* get_feed(MicrofeedSubscriber* subscriber, const char* publisher_identifier, const char* uri, const char* uid, MicrofeedSubscriberErrorCallback callback, void* user_data) {
00948 Publisher* publisher;
00949 Feed* feed = NULL;
00950
00951 if (!(publisher = microfeed_store_get(subscriber->publishers_by_identifier, publisher_identifier, Publisher))) {
00952 if (callback) {
00953 callback(subscriber, publisher_identifier, uri, uid, MICROFEED_ERROR_NO_SUCH_PUBLISHER, "Publisher does not exist.", user_data);
00954 }
00955 } else if (!(feed = microfeed_store_get(publisher->feeds, uri, Feed))) {
00956 if (callback) {
00957 callback(subscriber, publisher_identifier, uri, uid, MICROFEED_ERROR_FEED_NOT_SUBSCRIBED, "Trying to access a feed that is not subscribed.", user_data);
00958 }
00959 }
00960
00961 return feed;
00962 }
00963
00964 static MicrofeedItem* parse_item_from_message(DBusMessageIter* iter) {
00965 MicrofeedItem* item = NULL;
00966 char* uid;
00967 dbus_uint64_t timestamp;
00968 unsigned char status;
00969 char* key;
00970 char* value;
00971
00972 if (dbus_message_iter_next(iter) && dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
00973 dbus_message_iter_get_basic(iter, &uid);
00974 if (dbus_message_iter_next(iter) && dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_UINT64) {
00975 dbus_message_iter_get_basic(iter, ×tamp);
00976 if (dbus_message_iter_next(iter) && dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_BYTE) {
00977 dbus_message_iter_get_basic(iter, &status);
00978 item = microfeed_item_new_with_status(uid, (time_t)timestamp, (MicrofeedItemStatus)status);
00979 while (dbus_message_iter_next(iter) && dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
00980 dbus_message_iter_get_basic(iter, &key);
00981 if (dbus_message_iter_next(iter) && dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
00982 dbus_message_iter_get_basic(iter, &value);
00983 microfeed_item_set_property(item, key, value);
00984 }
00985 }
00986 }
00987 } else {
00988 item = microfeed_item_new(uid, 0);
00989 }
00990 }
00991
00992 return item;
00993 }
00994
00995 static int parse_item_signal(Publisher* publisher, DBusMessage* message, Feed** feed_return, MicrofeedItem** item_return) {
00996 int retvalue = 0;
00997 DBusMessageIter iter;
00998 char* uri;
00999 Feed* feed;
01000 MicrofeedItem* item;
01001
01002 if (dbus_message_iter_init(message, &iter) && dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING) {
01003 dbus_message_iter_get_basic(&iter, &uri);
01004 if ((feed = microfeed_store_get(publisher->feeds, uri, Feed)) &&
01005 (item = parse_item_from_message(&iter))) {
01006 *feed_return = feed;
01007 *item_return = item;
01008 retvalue = 1;
01009 }
01010 }
01011
01012 return retvalue;
01013 }
01014
01015 static int parse_feed_signal(Publisher* publisher, DBusMessage* message, Feed** feed_return) {
01016 int retvalue = 0;
01017 DBusError error;
01018 const char* uri;
01019 Feed* feed;
01020
01021 dbus_error_init(&error);
01022 if (dbus_message_get_args(message, &error, DBUS_TYPE_STRING, &uri, DBUS_TYPE_INVALID)) {
01023 if ((feed = microfeed_store_get(publisher->feeds, uri, Feed))) {
01024 *feed_return = feed;
01025 retvalue = 1;
01026 }
01027 } else {
01028 dbus_error_free(&error);
01029 }
01030
01031 return retvalue;
01032 }
01033
01034 static void handle_publisher_method_return(DBusPendingCall* pending, void* user_data) {
01035 MethodReturnData* data;
01036 DBusMessage* reply;
01037 DBusError error;
01038 const char* error_name;
01039 const char* error_message;
01040 int retrying = 0;
01041 DBusPendingCall* pending_call;
01042
01043 data = (MethodReturnData*)user_data;
01044 reply = dbus_pending_call_steal_reply(pending);
01045 if (!reply) {
01046 if (data->callback) {
01047 data->callback(data->publisher->provider->subscriber, data->publisher->identifier, data->uri, data->uid, MICROFEED_ERROR_DBUS_MESSAGE_FAILED, "No reply from the publisher.", data->user_data);
01048 }
01049 } else if (dbus_message_get_type(reply) == DBUS_MESSAGE_TYPE_ERROR) {
01050 if (data->retry_counter < data->publisher->provider->subscriber->max_retries) {
01051 retrying = 1;
01052 if (data->retry_counter) {
01053
01054 }
01055 data->retry_counter++;
01056
01057 dbus_connection_send_with_reply(data->publisher->provider->subscriber->connection, data->message, &pending_call, MICROFEED_SUBSCRIBER_DBUS_METHOD_CALL_TIMEOUT);
01058 if (pending_call) {
01059 dbus_pending_call_set_notify(pending_call, handle_publisher_method_return, data, NULL);
01060 }
01061 } else if (data->callback) {
01062 if (!(error_name = dbus_message_get_error_name(reply))) {
01063 error_name = MICROFEED_ERROR_UNKNOWN;
01064 }
01065 dbus_error_init(&error);
01066 if (!dbus_message_get_args(reply, &error, DBUS_TYPE_STRING, &error_message, DBUS_TYPE_INVALID)) {
01067 error_message = NULL;
01068 }
01069 data->callback(data->publisher->provider->subscriber, data->publisher->identifier, data->uri, data->uid, error_name, error_message, data->user_data);
01070 }
01071 } else {
01072 if (!data->publisher->provider->unique_connection_name) {
01073 provider_set_unique_connection_name(data->publisher->provider, dbus_message_get_sender(reply));
01074 }
01075 if (data->callback) {
01076 data->callback(data->publisher->provider->subscriber, data->publisher->identifier, data->uri, data->uid, NULL, NULL, data->user_data);
01077 }
01078 }
01079 if (reply) {
01080 dbus_message_unref(reply);
01081 }
01082
01083 if (!retrying) {
01084 dbus_message_unref(data->message);
01085 publisher_unref(data->publisher);
01086 free(data->uri);
01087 free(data->uid);
01088 microfeed_memory_free(data);
01089 }
01090 }
01091
01092 static void call_publisher_method(Publisher* publisher, const char* uri, const char* uid, DBusMessage* message, MicrofeedSubscriberErrorCallback callback, void* user_data) {
01093 DBusPendingCall* pending_call;
01094 MethodReturnData* data;
01095
01096 dbus_connection_send_with_reply(publisher->provider->subscriber->connection, message, &pending_call, MICROFEED_SUBSCRIBER_DBUS_METHOD_CALL_TIMEOUT);
01097 if (pending_call) {
01098 data = microfeed_memory_allocate(MethodReturnData);
01099 data->message = dbus_message_copy(message);
01100 data->publisher = publisher_ref(publisher);
01101 if (uri) {
01102 data->uri = strdup(uri);
01103 } else {
01104 data->uri = NULL;
01105 }
01106 if (uid) {
01107 data->uid = strdup(uid);
01108 } else {
01109 data->uid = NULL;
01110 }
01111 data->callback = callback;
01112 data->user_data = user_data;
01113 dbus_pending_call_set_notify(pending_call, handle_publisher_method_return, data, NULL);
01114 }
01115 }
01116
01117 static void object_unregister(DBusConnection* connection, void* user_data) {
01118 }
01119
01120 static DBusHandlerResult object_message(DBusConnection* connection, DBusMessage* message, void* user_data) {
01121 DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01122 MicrofeedSubscriber* subscriber;
01123 const char* name;
01124 const char* old_owner;
01125 const char* new_owner;
01126 MicrofeedStoreIterator* publisher_iterator;
01127 MicrofeedStoreIterator* feed_iterator;
01128 Feed* feed;
01129 int i;
01130 Provider* provider;
01131 Publisher* publisher;
01132 DBusMessage* reply;
01133 DBusError error;
01134 const char* error_name;
01135 char* error_message;
01136 char* uri;
01137 char* uid;
01138 Subscription* s;
01139
01140 subscriber = (MicrofeedSubscriber*)user_data;
01141 if (dbus_message_is_signal(message, "org.freedesktop.DBus", "NameOwnerChanged") &&
01142 dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &name, DBUS_TYPE_STRING, &old_owner, DBUS_TYPE_STRING, &new_owner, DBUS_TYPE_INVALID) &&
01143 name[0] == ':' && new_owner[0] == 0 && !strcmp(name, old_owner) && (provider = microfeed_store_get(subscriber->providers_by_unique_connection_name, name, Provider))) {
01144 for (publisher_iterator = microfeed_store_iterate(provider->publishers_by_object_path, NULL);
01145 (publisher = microfeed_store_iterator_get(publisher_iterator, Publisher));
01146 microfeed_store_iterator_next(publisher_iterator)) {
01147 for (feed_iterator = microfeed_store_iterate(publisher->feeds, NULL);
01148 (feed = microfeed_store_iterator_get(feed_iterator, Feed));
01149 microfeed_store_iterator_next(feed_iterator)) {
01150 for (s = feed->subscriptions; s; s = s->next) {
01151 if (s->callbacks->error_occured) {
01152 s->callbacks->error_occured(subscriber, publisher->identifier, feed->uri, NULL, MICROFEED_ERROR_PROVIDER_CLOSED_CONNECTION, "Provider closed connection", s->user_data);
01153 }
01154 }
01155
01156 }
01157 microfeed_store_iterator_free(feed_iterator);
01158
01159 }
01160 provider_set_unique_connection_name(provider, NULL);
01161 microfeed_store_iterator_free(publisher_iterator);
01162 }
01163
01164 if ((provider = microfeed_store_get(subscriber->providers_by_unique_connection_name, dbus_message_get_sender(message), Provider)) &&
01165 (publisher = microfeed_store_get(provider->publishers_by_object_path, dbus_message_get_path(message), Publisher))) {
01166 publisher->last_activity = time(NULL);
01167 if (dbus_message_is_method_call(message, MICROFEED_DBUS_INTERFACE_SUBSCRIBER, MICROFEED_METHOD_NAME_PING)) {
01168 reply = dbus_message_new_method_return(message);
01169 dbus_connection_send(connection, reply, NULL);
01170 dbus_message_unref(reply);
01171 result = DBUS_HANDLER_RESULT_HANDLED;
01172 } else if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL && (dbus_message_has_interface(message, MICROFEED_DBUS_INTERFACE_ERROR) || dbus_message_has_interface(message, MICROFEED_DBUS_INTERFACE_ERROR_TO_DESTINATION))) {
01173 dbus_error_init(&error);
01174 if ((error_name = dbus_message_get_member(message)) && dbus_message_get_args(message, &error, DBUS_TYPE_STRING, &uri, DBUS_TYPE_STRING, &uid, DBUS_TYPE_STRING, &error_message, DBUS_TYPE_INVALID)) {
01175 if ((feed = microfeed_store_get(publisher->feeds, uri, Feed))) {
01176 for (s = feed->subscriptions; s; s = s->next) {
01177 if (s->callbacks->error_occured) {
01178 s->callbacks->error_occured(subscriber, publisher->identifier, uri, uid, error_name, error_message, s->user_data);
01179 }
01180 }
01181 }
01182 }
01183 } else {
01184 for (i = 0; signal_callbacks[i].name; i++) {
01185 if (dbus_message_is_signal(message, MICROFEED_DBUS_INTERFACE_PUBLISHER, signal_callbacks[i].name) ||
01186 dbus_message_is_signal(message, MICROFEED_DBUS_INTERFACE_PUBLISHER_TO_DESTINATION, signal_callbacks[i].name)) {
01187 signal_callbacks[i].callback(subscriber, publisher, message);
01188 result = DBUS_HANDLER_RESULT_HANDLED;
01189 break;
01190 }
01191 }
01192 }
01193 }
01194
01195 return result;
01196 }