00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <microfeed-provider/microfeedprovider.h>
00020 #include <microfeed-provider/microfeedpublisher.h>
00021 #include <microfeed-common/microfeedmisc.h>
00022 #include <microfeed-common/microfeedthread.h>
00023 #include <microfeed-provider/microfeederror.h>
00024 #include <microfeed-common/microfeedprotocol.h>
00025
00026 #include <stdio.h>
00027 #include <stdlib.h>
00028 #include <string.h>
00029 #include <time.h>
00030
00031 typedef struct _Thread Thread;
00032
00033 struct _MicrofeedPublisher {
00034 char* identifier;
00035 char* object_path;
00036 DBusConnection* connection;
00037 MicrofeedPublisherCallbacks callbacks;
00038 void* user_data;
00039 MicrofeedDatabaseEnvironment* database_environment;
00040 char** image_properties;
00041 MicrofeedProvider* provider;
00042 DBusMessage* current_message;
00043
00044 MicrofeedStore* subscribers;
00045 MicrofeedStore* feeds;
00046 MicrofeedFeed* settings_feed;
00047 MicrofeedFeed* images_feed;
00048 MicrofeedThread* singleton_update_thread;
00049 MicrofeedThreadPool* thread_pool;
00050 MicrofeedStore* timeouts;
00051 };
00052
00053 typedef struct {
00054 MicrofeedPublisher* publisher;
00055 char* unique_connection_name;
00056 time_t last_activity;
00057 MicrofeedStore* feeds;
00058 } Subscriber;
00059
00060 typedef struct {
00061 MicrofeedFeed* feed;
00062 void* implementation;
00063 } Timeout;
00064
00065 typedef struct {
00066 const char* name;
00067 MicrofeedError* (*callback)(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message);
00068 } MethodCallback;
00069
00070 static void object_unregister(DBusConnection* connection, void* user_data);
00071 static DBusHandlerResult object_message(DBusConnection* connection, DBusMessage* message, void* user_data);
00072 static Subscriber* subscriber_new(MicrofeedPublisher* publisher, const char* unique_connection_name);
00073 static void subscriber_free(Subscriber* subscriber);
00074 static const char* subscriber_get_unique_connection_name(Subscriber* subscriber);
00075 static Timeout* timeout_new(MicrofeedPublisher* publisher, MicrofeedFeed* feed);
00076 static void timeout_free(Timeout* timeout);
00077 static MicrofeedFeed* timeout_get_feed(Timeout* timeout);
00078
00079 static MicrofeedError* method_add_item(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message);
00080 static MicrofeedError* method_modify_item(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message);
00081 static MicrofeedError* method_remove_item(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message);
00082 static MicrofeedError* method_read_items(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message);
00083 static MicrofeedError* method_republish_items(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message);
00084 static MicrofeedError* method_send_item_data(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message);
00085 static MicrofeedError* method_mark_item(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message);
00086 static MicrofeedError* method_unmark_item(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message);
00087 static MicrofeedError* method_ping(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message);
00088 static MicrofeedError* method_subscribe_feed(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message);
00089 static MicrofeedError* method_unsubscribe_feed(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message);
00090 static MicrofeedError* method_update_feed(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message);
00091 static MicrofeedError* method_create_publisher(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message);
00092 static MicrofeedError* method_destroy_publisher(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message);
00093
00094 static void reply_to_current_message(MicrofeedPublisher* publisher, MicrofeedError* error);
00095 static MicrofeedError* settings_feed_modify_item(MicrofeedFeed* feed, MicrofeedItem* existing_item, MicrofeedItem* new_item, void* user_data);
00096 static MicrofeedError* images_feed_download_item_data(MicrofeedFeed* feed, const char* uid, void** data, size_t* length, void* user_data);
00097 static void thread_exited(MicrofeedThread* thread, void* user_data);
00098 static void timeout_handler(void* data);
00099
00100 static MethodCallback method_callbacks[] = {
00101 { MICROFEED_METHOD_NAME_ADD_ITEM, method_add_item },
00102 { MICROFEED_METHOD_NAME_MODIFY_ITEM, method_modify_item },
00103 { MICROFEED_METHOD_NAME_REMOVE_ITEM, method_remove_item },
00104 { MICROFEED_METHOD_NAME_READ_ITEMS, method_read_items },
00105 { MICROFEED_METHOD_NAME_REPUBLISH_ITEMS, method_republish_items },
00106 { MICROFEED_METHOD_NAME_SEND_ITEM_DATA, method_send_item_data },
00107 { MICROFEED_METHOD_NAME_MARK_ITEM, method_mark_item },
00108 { MICROFEED_METHOD_NAME_UNMARK_ITEM, method_unmark_item },
00109 { MICROFEED_METHOD_NAME_PING, method_ping },
00110 { MICROFEED_METHOD_NAME_SUBSCRIBE_FEED, method_subscribe_feed },
00111 { MICROFEED_METHOD_NAME_UNSUBSCRIBE_FEED, method_unsubscribe_feed },
00112 { MICROFEED_METHOD_NAME_UPDATE_FEED, method_update_feed },
00113 { MICROFEED_METHOD_NAME_CREATE_PUBLISHER, method_create_publisher },
00114 { MICROFEED_METHOD_NAME_DESTROY_PUBLISHER, method_destroy_publisher },
00115 { NULL, NULL }
00116 };
00117
00118 static MicrofeedFeedCallbacks settings_feed_callbacks = {
00119 NULL,
00120 NULL,
00121 settings_feed_modify_item
00122 };
00123
00124 static MicrofeedFeedCallbacks images_feed_callbacks = {
00125 NULL,
00126 NULL,
00127 NULL,
00128 images_feed_download_item_data
00129 };
00130
00131 static DBusObjectPathVTable object_vtable = {
00132 object_unregister,
00133 object_message
00134 };
00135
00149 MicrofeedPublisher* microfeed_publisher_new(const char* publisher_identifier, const char* directory, DBusConnection* connection, MicrofeedPublisherCallbacks* callbacks, void* user_data) {
00150 MicrofeedPublisher* publisher;
00151 char* separator;
00152
00153 publisher = microfeed_memory_allocate(MicrofeedPublisher);
00154 publisher->identifier = strdup(publisher_identifier);
00155 if (!(separator = strchr(publisher->identifier, MICROFEED_PUBLISHER_IDENTIFIER_SEPARATOR_CHAR)) || separator[1] == 0) {
00156 free(publisher->identifier);
00157 microfeed_memory_free(publisher);
00158 publisher = NULL;
00159 } else {
00160 *separator = 0;
00161 publisher->object_path = microfeed_util_string_concatenate(MICROFEED_DBUS_OBJECT_PATH_PREFIX_PUBLISHER, publisher->identifier, NULL);
00162 *separator = MICROFEED_PUBLISHER_IDENTIFIER_SEPARATOR_CHAR;
00163 publisher->connection = connection;
00164 publisher->callbacks = *callbacks;
00165 publisher->user_data = user_data;
00166 publisher->image_properties = (char**)malloc(3 * sizeof(char*));
00167 publisher->image_properties[0] = strdup(MICROFEED_ITEM_PROPERTY_NAME_CONTENT_IMAGE);
00168 publisher->image_properties[1] = strdup(MICROFEED_ITEM_PROPERTY_NAME_USER_IMAGE);
00169 publisher->image_properties[2] = 0;
00170
00171 if (!dbus_connection_register_object_path(connection, publisher->object_path, &object_vtable, publisher)) {
00172
00173 return NULL;
00174 }
00175
00176 if (!(publisher->database_environment = microfeed_database_environment_new(publisher_identifier, directory))) {
00177
00178 return NULL;
00179 }
00180 publisher->subscribers = microfeed_store_new_sorted((MicrofeedStoreCompareKeysFunction)strcmp,
00181 (MicrofeedStoreGetKeyFunction)subscriber_get_unique_connection_name);
00182 publisher->feeds = microfeed_store_new_sorted((MicrofeedStoreCompareKeysFunction)strcmp,
00183 (MicrofeedStoreGetKeyFunction)microfeed_feed_get_uri);
00184
00185 publisher->settings_feed = microfeed_feed_new(publisher, MICROFEED_FEED_URI_SETTINGS, "Settings", MICROFEED_FEED_PERMISSION_NONE, &settings_feed_callbacks, NULL);
00186 microfeed_store_insert(publisher->feeds, publisher->settings_feed);
00187 microfeed_feed_add_subscriber(publisher->settings_feed, NULL);
00188
00189 publisher->images_feed = microfeed_feed_new(publisher, MICROFEED_FEED_URI_IMAGES, "Images", MICROFEED_FEED_PERMISSION_NONE, &images_feed_callbacks, NULL);
00190 microfeed_store_insert(publisher->feeds, publisher->images_feed);
00191 microfeed_feed_add_subscriber(publisher->images_feed, NULL);
00192
00193 publisher->thread_pool = microfeed_thread_pool_new_with_exit_callback(microfeed_publisher_get_setting_value_integer(publisher, "threads.max", 10), thread_exited, publisher);
00194 publisher->timeouts = microfeed_store_new_sorted(microfeed_store_compare_keys_direct, (MicrofeedStoreGetKeyFunction)timeout_get_feed);
00195 }
00196
00197 return publisher;
00198 }
00199
00205 void microfeed_publisher_free(MicrofeedPublisher* publisher) {
00206 dbus_connection_unregister_object_path(publisher->connection, publisher->object_path);
00207 microfeed_database_environment_free(publisher->database_environment);
00208 microfeed_feed_remove_subscriber(publisher->settings_feed, NULL);
00209 microfeed_feed_remove_subscriber(publisher->images_feed, NULL);
00210
00211 free(publisher->identifier);
00212 free(publisher->object_path);
00213 free(publisher->image_properties);
00214 microfeed_store_free(publisher->subscribers);
00215 microfeed_store_free(publisher->feeds);
00216
00217
00218
00219
00220 microfeed_thread_free(publisher->singleton_update_thread);
00221
00222 microfeed_store_free(publisher->timeouts);
00223 }
00224
00231 void microfeed_publisher_add_setting(MicrofeedPublisher* publisher, const char* uid, const char* text, const char* unit, const char* type, const char* length, const char* value) {
00232 MicrofeedItem* item;
00233 MicrofeedItem* existing_item;
00234
00235 item = microfeed_item_new(uid, time(NULL));
00236 microfeed_item_set_property(item, MICROFEED_ITEM_PROPERTY_NAME_SETTING_LENGTH, length);
00237 microfeed_item_set_property(item, MICROFEED_ITEM_PROPERTY_NAME_SETTING_TEXT, text);
00238 microfeed_item_set_property(item, MICROFEED_ITEM_PROPERTY_NAME_SETTING_TYPE, type);
00239 microfeed_item_set_property(item, MICROFEED_ITEM_PROPERTY_NAME_SETTING_UNIT, unit);
00240 if ((existing_item = microfeed_feed_get_item(publisher->settings_feed, uid))) {
00241 microfeed_item_set_property(item, MICROFEED_ITEM_PROPERTY_NAME_SETTING_VALUE, microfeed_item_get_property(existing_item, MICROFEED_ITEM_PROPERTY_NAME_SETTING_VALUE));
00242 } else {
00243 microfeed_item_set_property(item, MICROFEED_ITEM_PROPERTY_NAME_SETTING_VALUE, value);
00244 }
00245 microfeed_feed_replace_item(publisher->settings_feed, item);
00246 }
00247
00254 void microfeed_publisher_remove_setting(MicrofeedPublisher* publisher, const char* uid) {
00255 microfeed_feed_remove_item(publisher->settings_feed, uid);
00256 }
00257
00266 char* microfeed_publisher_get_setting_value(MicrofeedPublisher* publisher, const char* uid, const char* default_value) {
00267 const char* const_value;
00268 char* value;
00269 MicrofeedItem* item;
00270
00271 if ((item = microfeed_feed_get_item(publisher->settings_feed, uid))) {
00272 if ((const_value = microfeed_item_get_property(item, MICROFEED_ITEM_PROPERTY_NAME_SETTING_VALUE))) {
00273 value = strdup(const_value);
00274 } else {
00275 value = (default_value ? strdup(default_value) : NULL);
00276 }
00277 microfeed_item_free(item);
00278 } else {
00279 value = (default_value ? strdup(default_value) : NULL);
00280 }
00281
00282 return value;
00283 }
00284
00293 long int microfeed_publisher_get_setting_value_integer(MicrofeedPublisher* publisher, const char* uid, long int default_value) {
00294 long int value;
00295 MicrofeedItem* item;
00296 const char* string;
00297 char* end;
00298
00299 if ((item = microfeed_feed_get_item(publisher->settings_feed, uid))) {
00300 if ((string = microfeed_item_get_property(item, MICROFEED_ITEM_PROPERTY_NAME_SETTING_VALUE)) && *string != 0) {
00301 value = strtol(string, &end, 10);
00302 if (*end != 0) {
00303 value = default_value;
00304 }
00305 } else {
00306 value = default_value;
00307 }
00308 microfeed_item_free(item);
00309 } else {
00310 value = default_value;
00311 }
00312
00313 return value;
00314
00315 }
00316
00325 int microfeed_publisher_set_setting_value(MicrofeedPublisher* publisher, const char* uid, const char* value) {
00326 int retvalue = 0;
00327 MicrofeedItem* item;
00328
00329 if ((item = microfeed_feed_get_item(publisher->settings_feed, uid))) {
00330 microfeed_item_set_property(item, MICROFEED_ITEM_PROPERTY_NAME_SETTING_VALUE, value);
00331 microfeed_feed_replace_item(publisher->settings_feed, item);
00332 retvalue = 1;
00333 microfeed_item_free(item);
00334 }
00335
00336 return retvalue;
00337 }
00338
00339 MicrofeedThread* microfeed_publisher_queue_thread(MicrofeedPublisher* publisher, MicrofeedThreadFunction function, void* data) {
00340
00341 return microfeed_thread_pool_queue_thread(publisher->thread_pool, function, data);
00342 }
00343
00344 MicrofeedThread* microfeed_publisher_start_singleton_update_thread(MicrofeedPublisher* publisher, MicrofeedThreadFunction function, void* user_data) {
00345 if (!publisher->singleton_update_thread) {
00346 publisher->singleton_update_thread = microfeed_thread_new(function, user_data);
00347 }
00348
00349 return publisher->singleton_update_thread;
00350 }
00351
00352 MicrofeedThread* microfeed_publisher_get_singleton_update_thread(MicrofeedPublisher* publisher) {
00353
00354 return publisher->singleton_update_thread;
00355 }
00356
00357 MicrofeedDatabaseEnvironment* microfeed_publisher_get_database_environment(MicrofeedPublisher* publisher) {
00358
00359 return publisher->database_environment;
00360 }
00361
00362 void microfeed_publisher_handle_item_property_change(MicrofeedPublisher* publisher, MicrofeedItem* old_item, MicrofeedItem* new_item) {
00363 char** key;
00364 const char* old_value;
00365 const char* new_value;
00366
00367 for (key = publisher->image_properties; *key; key++) {
00368 if (old_item && (old_value = microfeed_item_get_property(old_item, *key))) {
00369 if (new_item && (new_value = microfeed_item_get_property(new_item, *key))) {
00370 if (strcmp(old_value, new_value)) {
00371 microfeed_feed_unref_item_data(publisher->images_feed, old_value);
00372 microfeed_feed_ref_item_data(publisher->images_feed, new_value);
00373 }
00374 } else {
00375 microfeed_feed_unref_item_data(publisher->images_feed, old_value);
00376 }
00377 } else if (new_item && (new_value = microfeed_item_get_property(new_item, *key))) {
00378 microfeed_feed_ref_item_data(publisher->images_feed, new_value);
00379 }
00380 }
00381 }
00382
00383 void microfeed_publisher_send_item_signal(MicrofeedPublisher* publisher, const char* destination, const char* signal_name, const char* uri, MicrofeedItem* item) {
00384 DBusMessage* message;
00385 DBusMessageIter iter;
00386 MicrofeedItemIterator* item_iterator;
00387 const char* uid;
00388 dbus_uint64_t timestamp;
00389 char status;
00390 const char* key;
00391 const char* value;
00392
00393 message = dbus_message_new_signal(publisher->object_path, (destination ? MICROFEED_DBUS_INTERFACE_PUBLISHER_TO_DESTINATION : MICROFEED_DBUS_INTERFACE_PUBLISHER), signal_name);
00394 if (destination) {
00395 dbus_message_set_destination(message,destination);
00396 }
00397 dbus_message_iter_init_append(message, &iter);
00398 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &uri);
00399 uid = microfeed_item_get_uid(item);
00400 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &uid);
00401 timestamp = (dbus_uint64_t)microfeed_item_get_timestamp(item);
00402 dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT64, ×tamp);
00403 status = (char)microfeed_item_get_status(item);
00404 dbus_message_iter_append_basic(&iter, DBUS_TYPE_BYTE, &status);
00405 for (item_iterator = microfeed_item_iterate_properties(item, NULL);
00406 microfeed_item_iterator_get(item_iterator, &key, &value);
00407 microfeed_item_iterator_next(item_iterator)) {
00408 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &key);
00409 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &value);
00410 }
00411 microfeed_item_iterator_free(item_iterator);
00412 dbus_connection_send(publisher->connection, message, NULL);
00413 dbus_message_unref(message);
00414 }
00415
00416 void microfeed_publisher_send_item_uid_signal(MicrofeedPublisher* publisher, const char* destination, const char* signal_name, const char* uri, const char* uid) {
00417 DBusMessage* message;
00418
00419 message = dbus_message_new_signal(publisher->object_path, (destination ? MICROFEED_DBUS_INTERFACE_PUBLISHER_TO_DESTINATION : MICROFEED_DBUS_INTERFACE_PUBLISHER), signal_name);
00420 if (destination) {
00421 dbus_message_set_destination(message, destination);
00422 }
00423 dbus_message_append_args(message, DBUS_TYPE_STRING, &uri, DBUS_TYPE_STRING, &uid, DBUS_TYPE_INVALID);
00424 dbus_connection_send(publisher->connection, message, NULL);
00425 dbus_message_unref(message);
00426 }
00427
00428 void microfeed_publisher_send_status_changed_signal(MicrofeedPublisher* publisher, const char* destination, const char* uri, const char* uid, const char status) {
00429 DBusMessage* message;
00430
00431 message = dbus_message_new_signal(publisher->object_path, (destination ? MICROFEED_DBUS_INTERFACE_PUBLISHER_TO_DESTINATION : MICROFEED_DBUS_INTERFACE_PUBLISHER), MICROFEED_SIGNAL_NAME_ITEM_STATUS_CHANGED);
00432 if (destination) {
00433 dbus_message_set_destination(message, destination);
00434 }
00435 dbus_message_append_args(message, DBUS_TYPE_STRING, &uri, DBUS_TYPE_STRING, &uid, DBUS_TYPE_BYTE, &status, DBUS_TYPE_INVALID);
00436 dbus_connection_send(publisher->connection, message, NULL);
00437 dbus_message_unref(message);
00438 }
00439
00440 void microfeed_publisher_send_feed_signal(MicrofeedPublisher* publisher, const char* destination, const char* signal_name, const char* uri) {
00441 DBusMessage* message;
00442
00443 message = dbus_message_new_signal(publisher->object_path, (destination ? MICROFEED_DBUS_INTERFACE_PUBLISHER_TO_DESTINATION : MICROFEED_DBUS_INTERFACE_PUBLISHER), signal_name);
00444 if (destination) {
00445 dbus_message_set_destination(message, destination);
00446 }
00447 dbus_message_append_args(message, DBUS_TYPE_STRING, &uri, DBUS_TYPE_INVALID);
00448 dbus_connection_send(publisher->connection, message, NULL);
00449 dbus_message_unref(message);
00450 }
00451
00452 void microfeed_publisher_send_error_signal(MicrofeedPublisher* publisher, const char* destination, const char* error_name, const char* uri, const char* uid, const char* error_message) {
00453 DBusMessage* message;
00454 DBusMessageIter iter;
00455 const char* string;
00456
00457 message = dbus_message_new_signal(publisher->object_path, (destination ? MICROFEED_DBUS_INTERFACE_ERROR_TO_DESTINATION : MICROFEED_DBUS_INTERFACE_ERROR), error_name);
00458 if (destination) {
00459 dbus_message_set_destination(message, destination);
00460 }
00461 dbus_message_iter_init_append(message, &iter);
00462 string = (uri ? uri : "");
00463 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &string);
00464 string = (uid ? uid : "");
00465 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &string);
00466 string = (error_message ? error_message : "");
00467 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &string);
00468 dbus_connection_send(publisher->connection, message, NULL);
00469 dbus_message_unref(message);
00470 }
00471
00472 void microfeed_publisher_send_item_data_signal(MicrofeedPublisher* publisher, const char* destination, const char* uri, const char* uid, const void* data, size_t data_size) {
00473 DBusMessage* message;
00474 DBusMessageIter iter;
00475 DBusMessageIter subiter;
00476
00477 message = dbus_message_new_signal(publisher->object_path, (destination ? MICROFEED_DBUS_INTERFACE_PUBLISHER_TO_DESTINATION : MICROFEED_DBUS_INTERFACE_PUBLISHER), MICROFEED_SIGNAL_NAME_ITEM_DATA);
00478 if (destination) {
00479 dbus_message_set_destination(message,destination);
00480 }
00481 dbus_message_iter_init_append(message, &iter);
00482 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &uri);
00483 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &uid);
00484 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &subiter);
00485 dbus_message_iter_append_fixed_array(&subiter, DBUS_TYPE_BYTE, &data, data_size);
00486 dbus_message_iter_close_container(&iter, &subiter);
00487 dbus_connection_send(publisher->connection, message, NULL);
00488 dbus_message_unref(message);
00489 }
00490
00491 const char* microfeed_publisher_get_object_path(MicrofeedPublisher* publisher) {
00492 return publisher->object_path;
00493 }
00494
00495 const char* microfeed_publisher_get_identifier(MicrofeedPublisher* publisher) {
00496 return publisher->identifier;
00497 }
00498
00499 void microfeed_publisher_remove_subscriber(MicrofeedPublisher* publisher, const char* unique_connection_name) {
00500 Subscriber* subscriber;
00501 MicrofeedStoreIterator* iterator;
00502 MicrofeedFeed* feed;
00503 char buffer[1024];
00504
00505 if ((subscriber = microfeed_store_get(publisher->subscribers, unique_connection_name, Subscriber))) {
00506 for (iterator = microfeed_store_iterate(subscriber->feeds, NULL);
00507 (feed = (MicrofeedFeed*)microfeed_store_iterator_get(iterator, MicrofeedFeed));
00508 microfeed_store_iterator_next(iterator)) {
00509 microfeed_feed_remove_subscriber(feed, unique_connection_name);
00510 microfeed_store_remove(subscriber->feeds, feed);
00511
00512 if (microfeed_feed_get_subscriber_count(feed) == 0) {
00513 microfeed_store_remove(publisher->feeds, feed);
00514 microfeed_feed_unref(feed);
00515 }
00516 }
00517
00518 snprintf(buffer, 1024, "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',method='NameOwnerChanged',arg0='%s'", unique_connection_name);
00519 dbus_bus_remove_match(subscriber->publisher->connection, buffer, NULL);
00520
00521 microfeed_store_remove(subscriber->publisher->subscribers, subscriber);
00522 subscriber_free(subscriber);
00523
00524 if (publisher->callbacks.no_more_subscribers &&
00525 microfeed_store_get_size(publisher->subscribers) == 0 &&
00526 microfeed_thread_pool_get_started_thread_count(publisher->thread_pool) == 0) {
00527 publisher->callbacks.no_more_subscribers(publisher, publisher->user_data);
00528 }
00529 }
00530 }
00531
00532 MicrofeedProvider* microfeed_publisher_get_provider(MicrofeedPublisher* publisher) {
00533
00534 return publisher->provider;
00535 }
00536
00537 void microfeed_publisher_set_provider(MicrofeedPublisher* publisher, MicrofeedProvider* provider) {
00538 publisher->provider = provider;
00539 }
00540
00541 static Subscriber* subscriber_new(MicrofeedPublisher* publisher, const char* unique_connection_name) {
00542 Subscriber* subscriber;
00543
00544 subscriber = (Subscriber*)microfeed_memory_allocate(Subscriber);
00545 subscriber->publisher = publisher;
00546 subscriber->unique_connection_name = strdup(unique_connection_name);
00547 subscriber->last_activity = time(NULL);
00548 subscriber->feeds = microfeed_store_new_sorted((MicrofeedStoreCompareKeysFunction)strcmp,
00549 (MicrofeedStoreGetKeyFunction)microfeed_feed_get_uri);
00550
00551 return subscriber;
00552 }
00553
00554 static void subscriber_free(Subscriber* subscriber) {
00555 free(subscriber->unique_connection_name);
00556 microfeed_store_free(subscriber->feeds);
00557
00558 microfeed_memory_free(subscriber);
00559 }
00560
00561 static const char* subscriber_get_unique_connection_name(Subscriber* subscriber) {
00562
00563 return subscriber->unique_connection_name;
00564 }
00565
00566 static Timeout* timeout_new(MicrofeedPublisher* publisher, MicrofeedFeed* feed) {
00567 Timeout* timeout = NULL;
00568 unsigned long int interval;
00569
00570 if ((interval = (unsigned long int)microfeed_publisher_get_setting_value_integer(publisher, "update_interval", 0))) {
00571 timeout = microfeed_memory_allocate(Timeout);
00572 timeout->feed = feed;
00573 timeout->implementation = publisher->callbacks.add_timeout(publisher, interval * 60000, timeout_handler, timeout, publisher->user_data);
00574 }
00575
00576 return timeout;
00577 }
00578
00579 static void timeout_free(Timeout* timeout) {
00580 MicrofeedPublisher* publisher;
00581
00582 publisher = microfeed_feed_get_publisher(timeout->feed);
00583 publisher->callbacks.remove_timeout(publisher, timeout->implementation, publisher->user_data);
00584 }
00585
00586 static MicrofeedFeed* timeout_get_feed(Timeout* timeout) {
00587 return timeout->feed;
00588 }
00589
00590 static MicrofeedError* method_add_item(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message) {
00591 DBusMessageIter iter;
00592 const char* uri;
00593 const char* uid;
00594 MicrofeedFeed* feed;
00595 MicrofeedItem* item;
00596 const char* key;
00597 const char* value;
00598
00599 if (!dbus_message_iter_init(message, &iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
00600
00601 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected feed uri argument in AddItem method.");
00602 }
00603 dbus_message_iter_get_basic(&iter, &uri);
00604 if (!dbus_message_iter_next(&iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
00605
00606 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected temporary item uid argument in AddItem method.");
00607 }
00608 dbus_message_iter_get_basic(&iter, &uid);
00609 if (!(feed = microfeed_store_get(subscriber->feeds, uri, MicrofeedFeed))) {
00610
00611 return microfeed_error_new(MICROFEED_ERROR_NO_SUCH_FEED, "Trying to add an item into a feed that does not exist.");
00612 }
00613
00614 if ((item = microfeed_feed_get_item(feed, uid))) {
00615 microfeed_item_free(item);
00616
00617 return microfeed_error_new(MICROFEED_ERROR_ITEM_ALREADY_EXISTS, "Trying to add an item that already existed in a feed.");
00618 }
00619 item = microfeed_item_new(uid, time(NULL));
00620 while (dbus_message_iter_next(&iter)) {
00621 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
00622 microfeed_item_free(item);
00623
00624 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected string key in AddItem method.");
00625 }
00626 dbus_message_iter_get_basic(&iter, &key);
00627
00628 if (!dbus_message_iter_next(&iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
00629 microfeed_item_free(item);
00630
00631 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected string value in AddItem method.");
00632 }
00633 dbus_message_iter_get_basic(&iter, &value);
00634
00635 microfeed_item_set_property(item, key, value);
00636 }
00637
00638 reply_to_current_message(publisher, NULL);
00639
00640 microfeed_feed_call_modify_item_callback(feed, NULL, item);
00641 microfeed_item_free(item);
00642
00643 return NULL;
00644 }
00645
00646 static MicrofeedError* method_modify_item(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message) {
00647 DBusMessageIter iter;
00648 const char* uri;
00649 const char* uid;
00650 MicrofeedFeed* feed;
00651 MicrofeedItem* existing_item;
00652 MicrofeedItem* new_item;
00653 const char* key;
00654 const char* value;
00655
00656 if (!dbus_message_iter_init(message, &iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
00657
00658 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected feed uri argument in ModifyItem method.");
00659 }
00660 dbus_message_iter_get_basic(&iter, &uri);
00661 if (!dbus_message_iter_next(&iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
00662
00663 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected item uid argument in ModifyItem method.");
00664 }
00665 dbus_message_iter_get_basic(&iter, &uid);
00666 if (!(feed = microfeed_store_get(subscriber->feeds, uri, MicrofeedFeed))) {
00667
00668 return microfeed_error_new(MICROFEED_ERROR_NO_SUCH_FEED, "Trying to modify an item of a feed that does not exist.");
00669 }
00670
00671 if (!(existing_item = microfeed_feed_get_item(feed, uid))) {
00672
00673 return microfeed_error_new(MICROFEED_ERROR_NO_SUCH_ITEM, "Trying to modify an item that does not exist.");
00674 }
00675
00676 new_item = microfeed_item_new(uid, 0);
00677 while (dbus_message_iter_next(&iter)) {
00678 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
00679 microfeed_item_free(new_item);
00680
00681 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected string key in ModifyItem method.");
00682 }
00683 dbus_message_iter_get_basic(&iter, &key);
00684
00685 if (!dbus_message_iter_next(&iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
00686 microfeed_item_free(new_item);
00687
00688 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected string value in ModifyItem method.");
00689 }
00690 dbus_message_iter_get_basic(&iter, &value);
00691
00692 microfeed_item_set_property(new_item, key, value);
00693 }
00694
00695 reply_to_current_message(publisher, NULL);
00696
00697 microfeed_feed_call_modify_item_callback(feed, existing_item, new_item);
00698 microfeed_item_free(new_item);
00699
00700 return NULL;
00701 }
00702
00703 static MicrofeedError* method_remove_item(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message) {
00704 MicrofeedError* error = NULL;
00705 DBusError dbus_error;
00706 const char* uri;
00707 const char* uid;
00708 MicrofeedFeed* feed;
00709 MicrofeedItem* item;
00710
00711 dbus_error_init(&dbus_error);
00712 if (!dbus_message_get_args(message, &dbus_error, DBUS_TYPE_STRING, &uri, DBUS_TYPE_STRING, &uid, DBUS_TYPE_INVALID)) {
00713 error = microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected feed uri and item uid arguments in RemoveItem method");
00714 } else if (!(feed = microfeed_store_get(subscriber->feeds, uri, MicrofeedFeed))) {
00715 error = microfeed_error_new(MICROFEED_ERROR_NO_SUCH_FEED, "Trying to remove an item of a feed that does not exist.");
00716 } else if (!(item = microfeed_feed_get_item(feed, uid))) {
00717 error = microfeed_error_new(MICROFEED_ERROR_NO_SUCH_ITEM, "Trying to remove an item that does not exist.");
00718 } else {
00719 reply_to_current_message(publisher, NULL);
00720
00721 microfeed_feed_call_modify_item_callback(feed, item, NULL);
00722 microfeed_item_free(item);
00723 }
00724
00725 return error;
00726 }
00727
00728 static MicrofeedError* method_read_items(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message) {
00729 DBusMessageIter iter;
00730 const char* uri;
00731 const char* start_uid;
00732 const char* end_uid;
00733 MicrofeedFeed* feed;
00734
00735 if (!dbus_message_iter_init(message, &iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
00736
00737 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected feed uri argument in ReadItem method.");
00738 }
00739 dbus_message_iter_get_basic(&iter, &uri);
00740 if (!dbus_message_iter_next(&iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
00741
00742 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected start item uid argument in ReadItem method.");
00743 }
00744 dbus_message_iter_get_basic(&iter, &start_uid);
00745 if (!dbus_message_iter_next(&iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
00746
00747 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected end item uid argument in ReadItem method.");
00748 }
00749 dbus_message_iter_get_basic(&iter, &end_uid);
00750 if (!(feed = microfeed_store_get(subscriber->feeds, uri, MicrofeedFeed))) {
00751
00752 return microfeed_error_new(MICROFEED_ERROR_NO_SUCH_FEED, "Trying to read items of a feed that does not exist.");
00753 }
00754
00755 reply_to_current_message(publisher, NULL);
00756
00757 microfeed_feed_unset_item_statuses(feed, start_uid, end_uid, MICROFEED_ITEM_STATUS_UNREAD);
00758
00759 return NULL;
00760 }
00761
00762 static MicrofeedError* method_republish_items(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message) {
00763 DBusMessageIter iter;
00764 const char* uri;
00765 const char* start_uid;
00766 const char* end_uid;
00767 dbus_uint16_t max_count;
00768 MicrofeedFeed* feed;
00769
00770 if (!dbus_message_iter_init(message, &iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
00771
00772 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected a feed uri argument in PublishItems method");
00773 }
00774 dbus_message_iter_get_basic(&iter, &uri);
00775 if (!dbus_message_iter_next(&iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
00776
00777 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected a start item uid argument in PublishItems method");
00778 }
00779 dbus_message_iter_get_basic(&iter, &start_uid);
00780 if (!dbus_message_iter_next(&iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
00781
00782 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected an end item uid argument in PublishItems method");
00783 }
00784 dbus_message_iter_get_basic(&iter, &end_uid);
00785 if (!dbus_message_iter_next(&iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT16) {
00786
00787 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected an maximum count argument in PublishItems method");
00788 }
00789 dbus_message_iter_get_basic(&iter, &max_count);
00790
00791 if (!(feed = microfeed_store_get(subscriber->feeds, uri, MicrofeedFeed))) {
00792
00793 return microfeed_error_new(MICROFEED_ERROR_NO_SUCH_FEED, "Trying to republish items of a feed that does not exist.");
00794 }
00795
00796 reply_to_current_message(publisher, NULL);
00797
00798 microfeed_feed_republish(feed, (*start_uid ? start_uid : NULL), (*end_uid ? end_uid : NULL), max_count, subscriber->unique_connection_name);
00799
00800 return NULL;
00801 }
00802
00803 static MicrofeedError* method_send_item_data(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message) {
00804 DBusMessageIter iter;
00805 const char* uri;
00806 const char* uid;
00807 MicrofeedFeed* feed;
00808
00809 if (!publisher->callbacks.download_image) {
00810
00811 return microfeed_error_new(MICROFEED_ERROR_NO_ITEM_DATA, "Publisher does not support image downloading");
00812 }
00813 if (!dbus_message_iter_init(message, &iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
00814
00815 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected a feed uri argument in SendItemData method");
00816 }
00817 dbus_message_iter_get_basic(&iter, &uri);
00818 if (!dbus_message_iter_next(&iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
00819
00820 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected an item uid argument in SendItemData method");
00821 }
00822 dbus_message_iter_get_basic(&iter, &uid);
00823
00824 if (!(feed = microfeed_store_get(subscriber->feeds, uri, MicrofeedFeed))) {
00825
00826 return microfeed_error_new(MICROFEED_ERROR_NO_SUCH_FEED, "Trying to republish items of a feed that does not exist.");
00827 }
00828
00829 reply_to_current_message(publisher, NULL);
00830
00831 microfeed_feed_send_item_data(feed, uid, subscriber->unique_connection_name);
00832
00833 return NULL;
00834 }
00835
00836 static MicrofeedError* method_mark_item(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message) {
00837 MicrofeedError* error = NULL;
00838 DBusError dbus_error;
00839 const char* uri;
00840 const char* uid;
00841 MicrofeedFeed* feed;
00842
00843 dbus_error_init(&dbus_error);
00844 if (!dbus_message_get_args(message, &dbus_error, DBUS_TYPE_STRING, &uri, DBUS_TYPE_STRING, &uid, DBUS_TYPE_INVALID)) {
00845 error = microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected feed uri and item uid arguments in MarkItem method");
00846 } else if (!(feed = microfeed_store_get(subscriber->feeds, uri, MicrofeedFeed))) {
00847 error = microfeed_error_new(MICROFEED_ERROR_NO_SUCH_FEED, "Trying to mark an item of a feed that does not exist.");
00848 } else {
00849 reply_to_current_message(publisher, NULL);
00850
00851 microfeed_feed_set_item_status(feed, uid, MICROFEED_ITEM_STATUS_MARKED);
00852 }
00853
00854 return error;
00855 }
00856
00857 static MicrofeedError* method_unmark_item(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message) {
00858 MicrofeedError* error = NULL;
00859 DBusError dbus_error;
00860 const char* uri;
00861 const char* uid;
00862 MicrofeedFeed* feed;
00863
00864 dbus_error_init(&dbus_error);
00865 if (!dbus_message_get_args(message, &dbus_error, DBUS_TYPE_STRING, &uri, DBUS_TYPE_STRING, &uid, DBUS_TYPE_INVALID)) {
00866 error = microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected feed uri and item uid arguments in UnarkItem method");
00867 } else if (!(feed = microfeed_store_get(subscriber->feeds, uri, MicrofeedFeed))) {
00868 error = microfeed_error_new(MICROFEED_ERROR_NO_SUCH_FEED, "Trying to unmark an item of a feed that does not exist.");
00869 } else {
00870 reply_to_current_message(publisher, NULL);
00871
00872 microfeed_feed_unset_item_status(feed, uid, MICROFEED_ITEM_STATUS_MARKED);
00873 }
00874
00875 return error;
00876 }
00877
00878 static MicrofeedError* method_ping(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message) {
00879
00880 return NULL;
00881 }
00882
00883 static MicrofeedError* method_subscribe_feed(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message) {
00884 MicrofeedFeed* feed;
00885 DBusError error;
00886 char* uri;
00887 Timeout* timeout;
00888 int new_feed = 0;
00889
00890 dbus_error_init(&error);
00891 if (!dbus_message_get_args(message, &error, DBUS_TYPE_STRING, &uri, DBUS_TYPE_INVALID)) {
00892
00893 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected feed uri argument in SubscribeFeed method");
00894 }
00895
00896 if (!(feed = microfeed_store_get(publisher->feeds, uri, MicrofeedFeed))) {
00897 new_feed = 1;
00898 if ((feed = publisher->callbacks.instantiate_feed(publisher, uri, publisher->user_data))) {
00899 microfeed_store_insert(publisher->feeds, feed);
00900 if ((timeout = timeout_new(publisher, feed))) {
00901 microfeed_store_insert(publisher->timeouts, timeout);
00902 }
00903 } else {
00904
00905 return microfeed_error_new(MICROFEED_ERROR_NO_SUCH_FEED, "Failed to subscribe a new feed");
00906 }
00907 }
00908 microfeed_store_insert(subscriber->feeds, feed);
00909
00910 reply_to_current_message(publisher, NULL);
00911
00912 microfeed_feed_add_subscriber(feed, subscriber->unique_connection_name);
00913 microfeed_publisher_send_item_signal(publisher, subscriber->unique_connection_name, MICROFEED_SIGNAL_NAME_ITEM_ADDED, uri, microfeed_feed_get_metadata_item(feed));
00914 if (new_feed) {
00915 microfeed_feed_update(feed, NULL);
00916 }
00917
00918 return NULL;
00919 }
00920
00921 static MicrofeedError* method_unsubscribe_feed(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message) {
00922 DBusError error;
00923 char* uri;
00924 MicrofeedFeed* feed;
00925 Timeout* timeout;
00926
00927 dbus_error_init(&error);
00928 if (!dbus_message_get_args(message, &error, DBUS_TYPE_STRING, &uri, DBUS_TYPE_INVALID)) {
00929
00930 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected feed uri argument in UnsubscribeFeed method");
00931 }
00932 if (!(feed = microfeed_store_remove_key(subscriber->feeds, uri, MicrofeedFeed))) {
00933
00934 return microfeed_error_new(MICROFEED_ERROR_FEED_NOT_SUBSCRIBED, "Trying to unsubscribe a feed that is not subscribed");
00935 }
00936
00937 reply_to_current_message(publisher, NULL);
00938
00939 microfeed_feed_remove_subscriber(feed, subscriber->unique_connection_name);
00940 if (microfeed_feed_get_subscriber_count(feed) == 0) {
00941 if ((timeout = microfeed_store_get(publisher->timeouts, feed, Timeout))) {
00942 timeout_free(timeout);
00943 }
00944 microfeed_store_remove(publisher->feeds, feed);
00945 microfeed_feed_unref(feed);
00946 }
00947
00948 return NULL;
00949 }
00950
00951 static MicrofeedError* method_update_feed(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message) {
00952 MicrofeedFeed* feed;
00953 DBusError error;
00954 char* uri;
00955
00956 dbus_error_init(&error);
00957 if (!dbus_message_get_args(message, &error, DBUS_TYPE_STRING, &uri, DBUS_TYPE_INVALID)) {
00958
00959 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected feed uri argument in UpdateFeed method");
00960 }
00961
00962 if (!(feed = microfeed_store_get(subscriber->feeds, uri, MicrofeedFeed))) {
00963
00964 return microfeed_error_new(MICROFEED_ERROR_FEED_NOT_SUBSCRIBED, "Trying to update a feed that is not subscribed");
00965 }
00966
00967 reply_to_current_message(publisher, NULL);
00968
00969 microfeed_feed_update(feed, subscriber->unique_connection_name);
00970
00971 return NULL;
00972 }
00973
00974 static MicrofeedError* method_create_publisher(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message) {
00975
00976
00977 reply_to_current_message(publisher, NULL);
00978
00979 microfeed_publisher_add_setting(publisher, "archive_old_items", "Archive old items", "hours", "non-negative integer", "5", "5");
00980 microfeed_publisher_add_setting(publisher, "update_interval", "Update interval", "minutes", "non-negative integer", "5", "1");
00981
00982 publisher->callbacks.initialize_settings(publisher, publisher->user_data);
00983
00984 return NULL;
00985 }
00986
00987 static MicrofeedError* method_destroy_publisher(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message) {
00988 MicrofeedStoreIterator* subscriber_iterator;
00989 Subscriber* feed_subscriber;
00990 MicrofeedStoreIterator* feed_iterator;
00991 MicrofeedFeed* feed;
00992
00993 reply_to_current_message(publisher, NULL);
00994
00995 dbus_connection_unregister_object_path(publisher->connection, publisher->object_path);
00996
00997 for (subscriber_iterator = microfeed_store_iterate(publisher->subscribers, NULL);
00998 (feed_subscriber = microfeed_store_iterator_get(subscriber_iterator, Subscriber));
00999 microfeed_store_iterator_next(subscriber_iterator)) {
01000 for (feed_iterator = microfeed_store_iterate(feed_subscriber->feeds, NULL);
01001 (feed = microfeed_store_iterator_get(feed_iterator, MicrofeedFeed));
01002 microfeed_store_iterator_next(feed_iterator)) {
01003 microfeed_feed_remove_subscriber(feed, subscriber->unique_connection_name);
01004 microfeed_publisher_send_error_signal(publisher, subscriber->unique_connection_name, MICROFEED_ERROR_NO_SUCH_PUBLISHER, NULL, NULL, "Publisher destroyed.");
01005 }
01006 }
01007 for (feed_iterator = microfeed_store_iterate(publisher->feeds, NULL);
01008 (feed = microfeed_store_iterator_get(feed_iterator, MicrofeedFeed));
01009 microfeed_store_iterator_next(feed_iterator)) {
01010 microfeed_feed_unref(feed);
01011 }
01012
01013 return NULL;
01014 }
01015
01016 static void object_unregister(DBusConnection* connection, void* user_data) {
01017 }
01018
01019 static DBusHandlerResult object_message(DBusConnection* connection, DBusMessage* message, void* user_data) {
01020 DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01021 MicrofeedPublisher* publisher;
01022 const char* unique_connection_name;
01023 int i;
01024 Subscriber* subscriber;
01025 char buffer[1024];
01026 MicrofeedError* error;
01027
01028 publisher = (MicrofeedPublisher*)user_data;
01029 unique_connection_name = dbus_message_get_sender(message);
01030 if (!(subscriber = (Subscriber*)microfeed_store_get(publisher->subscribers, unique_connection_name, Subscriber))) {
01031 subscriber = subscriber_new(publisher, unique_connection_name);
01032 microfeed_store_insert(publisher->subscribers, subscriber);
01033
01034 snprintf(buffer, 1024, "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',arg0='%s'", unique_connection_name);
01035 dbus_bus_add_match(connection, buffer, NULL);
01036 }
01037
01038 subscriber->last_activity = time(NULL);
01039 for (i = 0; method_callbacks[i].name; i++) {
01040 if (dbus_message_is_method_call(message, MICROFEED_DBUS_INTERFACE_PUBLISHER, method_callbacks[i].name)) {
01041 printf("%s (%s)\n", method_callbacks[i].name, unique_connection_name);
01042 publisher->current_message = message;
01043 error = method_callbacks[i].callback(publisher, subscriber, message);
01044 reply_to_current_message(publisher, error);
01045 if (error) {
01046 microfeed_error_free(error);
01047 }
01048 result = DBUS_HANDLER_RESULT_HANDLED;
01049 break;
01050 }
01051 }
01052
01053 if (microfeed_store_get_size(subscriber->feeds) == 0) {
01054 snprintf(buffer, 1024, "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',method='NameOwnerChanged',arg0='%s'", unique_connection_name);
01055 dbus_bus_remove_match(connection, buffer, NULL);
01056
01057 microfeed_store_remove(publisher->subscribers, subscriber);
01058 subscriber_free(subscriber);
01059 }
01060
01061 if (publisher->callbacks.no_more_subscribers &&
01062 microfeed_store_get_size(publisher->subscribers) == 0 &&
01063 microfeed_thread_pool_get_started_thread_count(publisher->thread_pool) == 0) {
01064 publisher->callbacks.no_more_subscribers(publisher, publisher->user_data);
01065 }
01066
01067 return result;
01068 }
01069
01070 static void reply_to_current_message(MicrofeedPublisher* publisher, MicrofeedError* error) {
01071 char buffer[1024];
01072 DBusMessage* reply;
01073
01074 if (publisher->current_message) {
01075 if (error) {
01076 snprintf(buffer, 1024, "%s.%s", MICROFEED_DBUS_INTERFACE_ERROR, microfeed_error_get_name(error));
01077 reply = dbus_message_new_error(publisher->current_message, buffer, microfeed_error_get_message(error));
01078 } else {
01079 reply = dbus_message_new_method_return(publisher->current_message);
01080 }
01081 dbus_connection_send(publisher->connection, reply, NULL);
01082 dbus_message_unref(reply);
01083 publisher->current_message = NULL;
01084 }
01085 }
01086
01087 static MicrofeedError* settings_feed_modify_item(MicrofeedFeed* feed, MicrofeedItem* existing_item, MicrofeedItem* new_item, void* user_data) {
01088 MicrofeedError* error = NULL;;
01089 MicrofeedPublisher* publisher;
01090 const char* value;
01091
01092 publisher = microfeed_feed_get_publisher(feed);
01093 if (!existing_item) {
01094 error = microfeed_error_new(MICROFEED_ERROR_NO_SUCH_ITEM, "No such setting.");
01095 } else {
01096 if ((value = microfeed_item_get_property(new_item, MICROFEED_ITEM_PROPERTY_NAME_SETTING_VALUE))) {
01097 if (publisher->callbacks.update_setting(publisher, microfeed_item_get_uid(new_item), value, publisher->user_data)) {
01098 microfeed_item_set_property(existing_item, MICROFEED_ITEM_PROPERTY_NAME_SETTING_VALUE, value);
01099 microfeed_feed_replace_item(feed, existing_item);
01100 }
01101
01102 } else {
01103 error = microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "No setting.value property in settings item.");
01104 }
01105 }
01106
01107 return error;
01108 }
01109
01110 static MicrofeedError* images_feed_download_item_data(MicrofeedFeed* feed, const char* uid, void** data, size_t* length, void* user_data) {
01111 MicrofeedPublisher* publisher;
01112 MicrofeedError* error;
01113
01114 publisher = microfeed_feed_get_publisher(feed);
01115 error = publisher->callbacks.download_image(publisher, uid, data, length, publisher->user_data);
01116 if (!error) {
01117 microfeed_feed_unset_item_status(feed, uid, MICROFEED_ITEM_STATUS_UNREAD);
01118 }
01119
01120 return error;
01121 }
01122
01123 static void thread_exited(MicrofeedThread* thread, void* user_data) {
01124 MicrofeedPublisher* publisher;
01125
01126 publisher = (MicrofeedPublisher*)user_data;
01127 if (publisher->callbacks.no_more_subscribers &&
01128 microfeed_store_get_size(publisher->subscribers) == 0 &&
01129 microfeed_thread_pool_get_started_thread_count(publisher->thread_pool) == 0) {
01130 publisher->callbacks.no_more_subscribers(publisher, publisher->user_data);
01131 }
01132 }
01133
01134 static void timeout_handler(void* data) {
01135 Timeout* timeout;
01136
01137 timeout = (Timeout*)data;
01138 microfeed_feed_update(timeout->feed, NULL);
01139 }