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