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
00043 MicrofeedStore* subscribers;
00044 MicrofeedStore* feeds;
00045 MicrofeedFeed* settings_feed;
00046 MicrofeedFeed* images_feed;
00047 MicrofeedThreadPool* thread_pool;
00048 MicrofeedStore* timeouts;
00049 MicrofeedMutex* mutex;
00050 MicrofeedDatabase* timestamp_database;
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 unsigned long int interval;
00064 } Timeout;
00065
00066 typedef struct {
00067 const char* name;
00068 MicrofeedError* (*callback)(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message);
00069 } MethodCallback;
00070
00071 typedef struct {
00072 MicrofeedPublisher* publisher;
00073 Subscriber* subscriber;
00074 DBusMessage* message;
00075 MicrofeedError* (*callback)(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message);
00076 } MethodThreadData;
00077
00078 static void object_unregister(DBusConnection* connection, void* user_data);
00079 static DBusHandlerResult object_message(DBusConnection* connection, DBusMessage* message, void* user_data);
00080
00081 static Subscriber* subscriber_new(MicrofeedPublisher* publisher, const char* unique_connection_name);
00082 static void subscriber_free(Subscriber* subscriber);
00083 static const char* subscriber_get_unique_connection_name(Subscriber* subscriber);
00084
00085 static Timeout* timeout_new(MicrofeedPublisher* publisher, MicrofeedFeed* feed, unsigned long int interval);
00086 static void timeout_free(Timeout* timeout);
00087 static MicrofeedFeed* timeout_get_feed(Timeout* timeout);
00088
00089 static MicrofeedError* method_add_item(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message);
00090 static MicrofeedError* method_modify_item(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message);
00091 static MicrofeedError* method_remove_item(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message);
00092 static MicrofeedError* method_read_items(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message);
00093 static MicrofeedError* method_republish_items(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message);
00094 static MicrofeedError* method_send_item_data(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message);
00095 static MicrofeedError* method_mark_item(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message);
00096 static MicrofeedError* method_unmark_item(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message);
00097 static MicrofeedError* method_ping(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message);
00098 static MicrofeedError* method_subscribe_feed(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message);
00099 static MicrofeedError* method_unsubscribe_feed(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message);
00100 static MicrofeedError* method_update_feed(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message);
00101 static MicrofeedError* method_create_publisher(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message);
00102 static MicrofeedError* method_destroy_publisher(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message);
00103
00104 static MicrofeedError* settings_feed_modify_item(MicrofeedFeed* feed, MicrofeedItem* existing_item, MicrofeedItem* new_item, void* user_data);
00105 static MicrofeedError* images_feed_download_item_data(MicrofeedFeed* feed, const char* uid, void** data, size_t* length, void* user_data);
00106 static int timeout_handler(void* data);
00107 static void* method_thread(void* data);
00108 static void* update_thread(void* data);
00109 static void thread_exited(MicrofeedThread* thread, void* user_data);
00110 static MicrofeedFeed* get_or_instantiate_feed(MicrofeedPublisher* publisher, const char* uri);
00111 static void update_last_update_timestamp(MicrofeedFeed* feed);
00112 static void remove_data_from_store(void* data, void* user_data);
00113
00114 static MethodCallback method_callbacks[] = {
00115 { MICROFEED_METHOD_NAME_ADD_ITEM, method_add_item },
00116 { MICROFEED_METHOD_NAME_MODIFY_ITEM, method_modify_item },
00117 { MICROFEED_METHOD_NAME_REMOVE_ITEM, method_remove_item },
00118 { MICROFEED_METHOD_NAME_READ_ITEMS, method_read_items },
00119 { MICROFEED_METHOD_NAME_REPUBLISH_ITEMS, method_republish_items },
00120 { MICROFEED_METHOD_NAME_SEND_ITEM_DATA, method_send_item_data },
00121 { MICROFEED_METHOD_NAME_MARK_ITEM, method_mark_item },
00122 { MICROFEED_METHOD_NAME_UNMARK_ITEM, method_unmark_item },
00123 { MICROFEED_METHOD_NAME_PING, method_ping },
00124 { MICROFEED_METHOD_NAME_SUBSCRIBE_FEED, method_subscribe_feed },
00125 { MICROFEED_METHOD_NAME_UNSUBSCRIBE_FEED, method_unsubscribe_feed },
00126 { MICROFEED_METHOD_NAME_UPDATE_FEED, method_update_feed },
00127 { MICROFEED_METHOD_NAME_CREATE_PUBLISHER, method_create_publisher },
00128 { MICROFEED_METHOD_NAME_DESTROY_PUBLISHER, method_destroy_publisher },
00129 { NULL, NULL }
00130 };
00131
00132 static MicrofeedFeedCallbacks settings_feed_callbacks = {
00133 NULL,
00134 NULL,
00135 settings_feed_modify_item
00136 };
00137
00138 static MicrofeedFeedCallbacks images_feed_callbacks = {
00139 NULL,
00140 NULL,
00141 NULL,
00142 images_feed_download_item_data
00143 };
00144
00145 static DBusObjectPathVTable object_vtable = {
00146 object_unregister,
00147 object_message
00148 };
00149
00163 MicrofeedPublisher* microfeed_publisher_new(const char* publisher_identifier, const char* directory, DBusConnection* connection, MicrofeedPublisherCallbacks* callbacks, void* user_data) {
00164 MicrofeedPublisher* publisher;
00165 char* separator;
00166
00167 publisher = microfeed_memory_allocate(MicrofeedPublisher);
00168 publisher->identifier = strdup(publisher_identifier);
00169 if (!(separator = strchr(publisher->identifier, MICROFEED_PUBLISHER_IDENTIFIER_SEPARATOR_CHAR)) || separator[1] == 0) {
00170 free(publisher->identifier);
00171 microfeed_memory_free(publisher);
00172 publisher = NULL;
00173 } else {
00174 *separator = 0;
00175 publisher->object_path = microfeed_util_string_concatenate(MICROFEED_DBUS_OBJECT_PATH_PREFIX_PUBLISHER, publisher->identifier, NULL);
00176 *separator = MICROFEED_PUBLISHER_IDENTIFIER_SEPARATOR_CHAR;
00177 publisher->connection = connection;
00178 publisher->callbacks = *callbacks;
00179 publisher->user_data = user_data;
00180 publisher->image_properties = (char**)malloc(3 * sizeof(char*));
00181 publisher->image_properties[0] = strdup(MICROFEED_ITEM_PROPERTY_NAME_CONTENT_IMAGE);
00182 publisher->image_properties[1] = strdup(MICROFEED_ITEM_PROPERTY_NAME_USER_IMAGE);
00183 publisher->image_properties[2] = 0;
00184
00185 if (!dbus_connection_register_object_path(connection, publisher->object_path, &object_vtable, publisher)) {
00186
00187 return NULL;
00188 }
00189
00190 if (!(publisher->database_environment = microfeed_database_environment_new(publisher_identifier, directory))) {
00191
00192 return NULL;
00193 }
00194 publisher->subscribers = microfeed_store_new_sorted((MicrofeedStoreCompareKeysFunction)strcmp,
00195 (MicrofeedStoreGetKeyFunction)subscriber_get_unique_connection_name);
00196 publisher->feeds = microfeed_store_new_sorted((MicrofeedStoreCompareKeysFunction)strcmp,
00197 (MicrofeedStoreGetKeyFunction)microfeed_feed_get_uri);
00198
00199 publisher->settings_feed = microfeed_feed_new(publisher, MICROFEED_FEED_URI_SETTINGS, "Settings", MICROFEED_FEED_PERMISSION_NONE, &settings_feed_callbacks, NULL);
00200 microfeed_store_insert(publisher->feeds, publisher->settings_feed);
00201
00202 publisher->images_feed = microfeed_feed_new(publisher, MICROFEED_FEED_URI_IMAGES, "Images", MICROFEED_FEED_PERMISSION_NONE, &images_feed_callbacks, NULL);
00203 microfeed_store_insert(publisher->feeds, publisher->images_feed);
00204
00205 publisher->thread_pool = microfeed_thread_pool_new_with_exit_callback(microfeed_publisher_get_setting_value_integer(publisher, "threads.max", 10), thread_exited, publisher);
00206 publisher->timeouts = microfeed_store_new_sorted(microfeed_store_compare_keys_direct, (MicrofeedStoreGetKeyFunction)timeout_get_feed);
00207 publisher->mutex = microfeed_mutex_new();
00208 publisher->timestamp_database = microfeed_database_environment_get_database(publisher->database_environment, ":microfeed.timestamps", NULL);
00209 }
00210
00211 return publisher;
00212 }
00213
00219 void microfeed_publisher_free(MicrofeedPublisher* publisher) {
00220 dbus_connection_unregister_object_path(publisher->connection, publisher->object_path);
00221
00222 microfeed_feed_unref(publisher->settings_feed);
00223 microfeed_feed_unref(publisher->images_feed);
00224 microfeed_database_environment_free(publisher->database_environment);
00225
00226 free(publisher->identifier);
00227 free(publisher->object_path);
00228 free(publisher->image_properties);
00229 microfeed_store_free(publisher->subscribers);
00230 microfeed_store_free(publisher->feeds);
00231
00232
00233 microfeed_store_free(publisher->timeouts);
00234 microfeed_mutex_free(publisher->mutex);
00235 }
00236
00243 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) {
00244 MicrofeedItem* item;
00245 MicrofeedItem* existing_item;
00246
00247 item = microfeed_item_new(uid, time(NULL));
00248 microfeed_item_set_property(item, MICROFEED_ITEM_PROPERTY_NAME_SETTING_LENGTH, length);
00249 microfeed_item_set_property(item, MICROFEED_ITEM_PROPERTY_NAME_SETTING_TEXT, text);
00250 microfeed_item_set_property(item, MICROFEED_ITEM_PROPERTY_NAME_SETTING_TYPE, type);
00251 microfeed_item_set_property(item, MICROFEED_ITEM_PROPERTY_NAME_SETTING_UNIT, unit);
00252 if ((existing_item = microfeed_feed_get_item(publisher->settings_feed, uid))) {
00253 microfeed_item_set_property(item, MICROFEED_ITEM_PROPERTY_NAME_SETTING_VALUE, microfeed_item_get_property(existing_item, MICROFEED_ITEM_PROPERTY_NAME_SETTING_VALUE));
00254 } else {
00255 microfeed_item_set_property(item, MICROFEED_ITEM_PROPERTY_NAME_SETTING_VALUE, value);
00256 }
00257 microfeed_feed_replace_item(publisher->settings_feed, item);
00258 }
00259
00266 void microfeed_publisher_remove_setting(MicrofeedPublisher* publisher, const char* uid) {
00267 microfeed_feed_remove_item(publisher->settings_feed, uid);
00268 }
00269
00278 char* microfeed_publisher_get_setting_value(MicrofeedPublisher* publisher, const char* uid, const char* default_value) {
00279 const char* const_value;
00280 char* value;
00281 MicrofeedItem* item;
00282
00283 if ((item = microfeed_feed_get_item(publisher->settings_feed, uid))) {
00284 if ((const_value = microfeed_item_get_property(item, MICROFEED_ITEM_PROPERTY_NAME_SETTING_VALUE))) {
00285 value = strdup(const_value);
00286 } else {
00287 value = (default_value ? strdup(default_value) : NULL);
00288 }
00289 microfeed_item_free(item);
00290 } else {
00291 value = (default_value ? strdup(default_value) : NULL);
00292 }
00293
00294 return value;
00295 }
00296
00305 long int microfeed_publisher_get_setting_value_integer(MicrofeedPublisher* publisher, const char* uid, long int default_value) {
00306 long int value;
00307 MicrofeedItem* item;
00308 const char* string;
00309 char* end;
00310
00311 if ((item = microfeed_feed_get_item(publisher->settings_feed, uid))) {
00312 if ((string = microfeed_item_get_property(item, MICROFEED_ITEM_PROPERTY_NAME_SETTING_VALUE)) && *string != 0) {
00313 value = strtol(string, &end, 10);
00314 if (*end != 0) {
00315 value = default_value;
00316 }
00317 } else {
00318 value = default_value;
00319 }
00320 microfeed_item_free(item);
00321 } else {
00322 value = default_value;
00323 }
00324
00325 return value;
00326
00327 }
00328
00337 int microfeed_publisher_set_setting_value(MicrofeedPublisher* publisher, const char* uid, const char* value) {
00338 int retvalue = 0;
00339 MicrofeedItem* item;
00340
00341 if ((item = microfeed_feed_get_item(publisher->settings_feed, uid))) {
00342 microfeed_item_set_property(item, MICROFEED_ITEM_PROPERTY_NAME_SETTING_VALUE, value);
00343 microfeed_feed_replace_item(publisher->settings_feed, item);
00344 retvalue = 1;
00345 microfeed_item_free(item);
00346 }
00347
00348 return retvalue;
00349 }
00350
00351 MicrofeedDatabaseEnvironment* microfeed_publisher_get_database_environment(MicrofeedPublisher* publisher) {
00352
00353 return publisher->database_environment;
00354 }
00355
00356 void microfeed_publisher_handle_item_property_change(MicrofeedPublisher* publisher, MicrofeedItem* old_item, MicrofeedItem* new_item) {
00357 char** key;
00358 const char* old_value;
00359 const char* new_value;
00360
00361 microfeed_mutex_lock(publisher->mutex);
00362
00363 for (key = publisher->image_properties; *key; key++) {
00364 if (old_item && (old_value = microfeed_item_get_property(old_item, *key))) {
00365 if (new_item && (new_value = microfeed_item_get_property(new_item, *key))) {
00366 if (strcmp(old_value, new_value)) {
00367 microfeed_feed_unref_item_data(publisher->images_feed, old_value);
00368 microfeed_feed_ref_item_data(publisher->images_feed, new_value);
00369 }
00370 } else {
00371 microfeed_feed_unref_item_data(publisher->images_feed, old_value);
00372 }
00373 } else if (new_item && (new_value = microfeed_item_get_property(new_item, *key))) {
00374 microfeed_feed_ref_item_data(publisher->images_feed, new_value);
00375 }
00376 }
00377
00378 microfeed_mutex_unlock(publisher->mutex);
00379 }
00380
00381 void microfeed_publisher_send_item_signal(MicrofeedPublisher* publisher, const char* destination, const char* signal_name, const char* uri, MicrofeedItem* item) {
00382 DBusMessage* message;
00383 DBusMessageIter iter;
00384 MicrofeedItemIterator* item_iterator;
00385 const char* uid;
00386 dbus_uint64_t timestamp;
00387 char status;
00388 const char* key;
00389 const char* value;
00390
00391 printf("%s : %s (%s)\n", publisher->identifier, signal_name, destination);
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 printf("%s : %s (%s)\n", publisher->identifier, signal_name, destination);
00420
00421 message = dbus_message_new_signal(publisher->object_path, (destination ? MICROFEED_DBUS_INTERFACE_PUBLISHER_TO_DESTINATION : MICROFEED_DBUS_INTERFACE_PUBLISHER), signal_name);
00422 if (destination) {
00423 dbus_message_set_destination(message, destination);
00424 }
00425 dbus_message_append_args(message, DBUS_TYPE_STRING, &uri, DBUS_TYPE_STRING, &uid, DBUS_TYPE_INVALID);
00426 dbus_connection_send(publisher->connection, message, NULL);
00427 dbus_message_unref(message);
00428 }
00429
00430 void microfeed_publisher_send_status_changed_signal(MicrofeedPublisher* publisher, const char* destination, const char* uri, const char* uid, const char status) {
00431 DBusMessage* message;
00432
00433 printf("%s : %s (%s)\n", publisher->identifier, MICROFEED_SIGNAL_NAME_ITEM_STATUS_CHANGED, destination);
00434
00435 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);
00436 if (destination) {
00437 dbus_message_set_destination(message, destination);
00438 }
00439 dbus_message_append_args(message, DBUS_TYPE_STRING, &uri, DBUS_TYPE_STRING, &uid, DBUS_TYPE_BYTE, &status, DBUS_TYPE_INVALID);
00440 dbus_connection_send(publisher->connection, message, NULL);
00441 dbus_message_unref(message);
00442 }
00443
00444 void microfeed_publisher_send_feed_signal(MicrofeedPublisher* publisher, const char* destination, const char* signal_name, const char* uri) {
00445 DBusMessage* message;
00446
00447 printf("%s : %s (%s)\n", publisher->identifier, signal_name, destination);
00448
00449 message = dbus_message_new_signal(publisher->object_path, (destination ? MICROFEED_DBUS_INTERFACE_PUBLISHER_TO_DESTINATION : MICROFEED_DBUS_INTERFACE_PUBLISHER), signal_name);
00450 if (destination) {
00451 dbus_message_set_destination(message, destination);
00452 }
00453 dbus_message_append_args(message, DBUS_TYPE_STRING, &uri, DBUS_TYPE_INVALID);
00454 dbus_connection_send(publisher->connection, message, NULL);
00455 dbus_message_unref(message);
00456 }
00457
00458 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) {
00459 DBusMessage* message;
00460 DBusMessageIter iter;
00461 const char* string;
00462
00463 printf("%s : %s (%s)\n", publisher->identifier, error_name, destination);
00464
00465 message = dbus_message_new_signal(publisher->object_path, (destination ? MICROFEED_DBUS_INTERFACE_ERROR_TO_DESTINATION : MICROFEED_DBUS_INTERFACE_ERROR), error_name);
00466 if (destination) {
00467 dbus_message_set_destination(message, destination);
00468 }
00469 dbus_message_iter_init_append(message, &iter);
00470 string = (uri ? uri : "");
00471 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &string);
00472 string = (uid ? uid : "");
00473 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &string);
00474 string = (error_message ? error_message : "");
00475 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &string);
00476 dbus_connection_send(publisher->connection, message, NULL);
00477 dbus_message_unref(message);
00478 }
00479
00480 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) {
00481 DBusMessage* message;
00482 DBusMessageIter iter;
00483 DBusMessageIter subiter;
00484
00485 printf("%s : %s (%s)\n", publisher->identifier, MICROFEED_SIGNAL_NAME_ITEM_DATA, destination);
00486
00487 message = dbus_message_new_signal(publisher->object_path, (destination ? MICROFEED_DBUS_INTERFACE_PUBLISHER_TO_DESTINATION : MICROFEED_DBUS_INTERFACE_PUBLISHER), MICROFEED_SIGNAL_NAME_ITEM_DATA);
00488 if (destination) {
00489 dbus_message_set_destination(message,destination);
00490 }
00491 dbus_message_iter_init_append(message, &iter);
00492 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &uri);
00493 dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &uid);
00494 dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE_AS_STRING, &subiter);
00495 dbus_message_iter_append_fixed_array(&subiter, DBUS_TYPE_BYTE, &data, data_size);
00496 dbus_message_iter_close_container(&iter, &subiter);
00497 dbus_connection_send(publisher->connection, message, NULL);
00498 dbus_message_unref(message);
00499 }
00500
00501 const char* microfeed_publisher_get_object_path(MicrofeedPublisher* publisher) {
00502
00503 return publisher->object_path;
00504 }
00505
00506 const char* microfeed_publisher_get_identifier(MicrofeedPublisher* publisher) {
00507
00508 return publisher->identifier;
00509 }
00510
00511 void microfeed_publisher_remove_subscriber(MicrofeedPublisher* publisher, const char* unique_connection_name) {
00512 Subscriber* subscriber;
00513 MicrofeedStoreIterator* iterator;
00514 MicrofeedFeed* feed;
00515 char buffer[1024];
00516
00517 microfeed_mutex_lock(publisher->mutex);
00518
00519 if ((subscriber = microfeed_store_get(publisher->subscribers, unique_connection_name, Subscriber))) {
00520 for (iterator = microfeed_store_iterate(subscriber->feeds, NULL);
00521 (feed = (MicrofeedFeed*)microfeed_store_iterator_get(iterator, MicrofeedFeed));
00522 microfeed_store_iterator_next(iterator)) {
00523 microfeed_store_remove(subscriber->feeds, feed);
00524 microfeed_feed_unref(feed);
00525 }
00526
00527 snprintf(buffer, 1024, "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',method='NameOwnerChanged',arg0='%s'", unique_connection_name);
00528 dbus_bus_remove_match(subscriber->publisher->connection, buffer, NULL);
00529
00530 microfeed_store_remove(subscriber->publisher->subscribers, subscriber);
00531 subscriber_free(subscriber);
00532
00533 if (publisher->callbacks.no_more_subscribers &&
00534 microfeed_store_get_size(publisher->subscribers) == 0 &&
00535 microfeed_thread_pool_get_started_thread_count(publisher->thread_pool) == 0) {
00536 publisher->callbacks.no_more_subscribers(publisher, publisher->user_data);
00537 }
00538 }
00539
00540 microfeed_mutex_unlock(publisher->mutex);
00541 }
00542
00543 MicrofeedProvider* microfeed_publisher_get_provider(MicrofeedPublisher* publisher) {
00544
00545 return publisher->provider;
00546 }
00547
00548 void microfeed_publisher_set_provider(MicrofeedPublisher* publisher, MicrofeedProvider* provider) {
00549 publisher->provider = provider;
00550 }
00551
00552 static Subscriber* subscriber_new(MicrofeedPublisher* publisher, const char* unique_connection_name) {
00553 Subscriber* subscriber;
00554
00555 subscriber = (Subscriber*)microfeed_memory_allocate(Subscriber);
00556 subscriber->publisher = publisher;
00557 subscriber->unique_connection_name = strdup(unique_connection_name);
00558 subscriber->last_activity = time(NULL);
00559 subscriber->feeds = microfeed_store_new_sorted((MicrofeedStoreCompareKeysFunction)strcmp,
00560 (MicrofeedStoreGetKeyFunction)microfeed_feed_get_uri);
00561
00562 return subscriber;
00563 }
00564
00565 static void subscriber_free(Subscriber* subscriber) {
00566 free(subscriber->unique_connection_name);
00567 microfeed_store_free(subscriber->feeds);
00568
00569 microfeed_memory_free(subscriber);
00570 }
00571
00572 static const char* subscriber_get_unique_connection_name(Subscriber* subscriber) {
00573
00574 return subscriber->unique_connection_name;
00575 }
00576
00577 static Timeout* timeout_new(MicrofeedPublisher* publisher, MicrofeedFeed* feed, unsigned long int interval) {
00578 Timeout* timeout = NULL;
00579
00580 timeout = microfeed_memory_allocate(Timeout);
00581 timeout->feed = feed;
00582 timeout->interval = interval;
00583 timeout->implementation = publisher->callbacks.add_timeout(publisher, (timeout->interval ? timeout->interval * 60000 : 1000), timeout_handler, timeout, publisher->user_data);
00584
00585 return timeout;
00586 }
00587
00588 static void timeout_free(Timeout* timeout) {
00589 MicrofeedPublisher* publisher;
00590
00591 publisher = microfeed_feed_get_publisher(timeout->feed);
00592 publisher->callbacks.remove_timeout(publisher, timeout->implementation, publisher->user_data);
00593 }
00594
00595 static MicrofeedFeed* timeout_get_feed(Timeout* timeout) {
00596 return timeout->feed;
00597 }
00598
00599 static MicrofeedError* method_add_item(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message) {
00600 DBusMessageIter iter;
00601 const char* uri;
00602 const char* uid;
00603 MicrofeedFeed* feed;
00604 MicrofeedItem* item;
00605 const char* key;
00606 const char* value;
00607 MicrofeedError* error;
00608
00609 if (!dbus_message_iter_init(message, &iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
00610
00611 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected feed uri argument in AddItem method.");
00612 }
00613 dbus_message_iter_get_basic(&iter, &uri);
00614 if (!dbus_message_iter_next(&iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
00615
00616 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected temporary item uid argument in AddItem method.");
00617 }
00618 dbus_message_iter_get_basic(&iter, &uid);
00619 if (!(feed = get_or_instantiate_feed(publisher, uri))) {
00620
00621 return microfeed_error_new(MICROFEED_ERROR_NO_SUCH_FEED, "Trying to add an item into a feed that does not exist.");
00622 }
00623
00624 if ((item = microfeed_feed_get_item(feed, uid))) {
00625 microfeed_item_free(item);
00626
00627 return microfeed_error_new(MICROFEED_ERROR_ITEM_ALREADY_EXISTS, "Trying to add an item that already existed in a feed.");
00628 }
00629 item = microfeed_item_new(uid, time(NULL));
00630 while (dbus_message_iter_next(&iter)) {
00631 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
00632 microfeed_item_free(item);
00633
00634 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected string key in AddItem method.");
00635 }
00636 dbus_message_iter_get_basic(&iter, &key);
00637
00638 if (!dbus_message_iter_next(&iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
00639 microfeed_item_free(item);
00640
00641 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected string value in AddItem method.");
00642 }
00643 dbus_message_iter_get_basic(&iter, &value);
00644
00645 microfeed_item_set_property(item, key, value);
00646 }
00647
00648 error = microfeed_feed_call_modify_item_callback(feed, NULL, item);
00649 microfeed_item_free(item);
00650
00651 microfeed_feed_unref(feed);
00652
00653 return error;
00654 }
00655
00656 static MicrofeedError* method_modify_item(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message) {
00657 DBusMessageIter iter;
00658 const char* uri;
00659 const char* uid;
00660 MicrofeedFeed* feed;
00661 MicrofeedItem* existing_item;
00662 MicrofeedItem* new_item;
00663 const char* key;
00664 const char* value;
00665 MicrofeedError* error;
00666
00667 if (!dbus_message_iter_init(message, &iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
00668
00669 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected feed uri argument in ModifyItem method.");
00670 }
00671 dbus_message_iter_get_basic(&iter, &uri);
00672 if (!dbus_message_iter_next(&iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
00673
00674 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected item uid argument in ModifyItem method.");
00675 }
00676 dbus_message_iter_get_basic(&iter, &uid);
00677 if (!(feed = get_or_instantiate_feed(publisher, uri))) {
00678
00679 return microfeed_error_new(MICROFEED_ERROR_NO_SUCH_FEED, "Trying to modify an item of a feed that does not exist.");
00680 }
00681
00682 if (!(existing_item = microfeed_feed_get_item(feed, uid))) {
00683
00684 return microfeed_error_new(MICROFEED_ERROR_NO_SUCH_ITEM, "Trying to modify an item that does not exist.");
00685 }
00686
00687 new_item = microfeed_item_new(uid, 0);
00688 while (dbus_message_iter_next(&iter)) {
00689 if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
00690 microfeed_item_free(new_item);
00691
00692 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected string key in ModifyItem method.");
00693 }
00694 dbus_message_iter_get_basic(&iter, &key);
00695
00696 if (!dbus_message_iter_next(&iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
00697 microfeed_item_free(new_item);
00698
00699 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected string value in ModifyItem method.");
00700 }
00701 dbus_message_iter_get_basic(&iter, &value);
00702
00703 microfeed_item_set_property(new_item, key, value);
00704 }
00705
00706 error = microfeed_feed_call_modify_item_callback(feed, existing_item, new_item);
00707 microfeed_item_free(new_item);
00708
00709 microfeed_feed_unref(feed);
00710
00711 return error;
00712 }
00713
00714 static MicrofeedError* method_remove_item(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message) {
00715 MicrofeedError* error;
00716 DBusError dbus_error;
00717 const char* uri;
00718 const char* uid;
00719 MicrofeedFeed* feed;
00720 MicrofeedItem* item;
00721
00722 dbus_error_init(&dbus_error);
00723 if (!dbus_message_get_args(message, &dbus_error, DBUS_TYPE_STRING, &uri, DBUS_TYPE_STRING, &uid, DBUS_TYPE_INVALID)) {
00724 error = microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected feed uri and item uid arguments in RemoveItem method");
00725 } else if (!(feed = get_or_instantiate_feed(publisher, uri))) {
00726 error = microfeed_error_new(MICROFEED_ERROR_NO_SUCH_FEED, "Trying to remove an item of a feed that does not exist.");
00727 } else if (!(item = microfeed_feed_get_item(feed, uid))) {
00728 error = microfeed_error_new(MICROFEED_ERROR_NO_SUCH_ITEM, "Trying to remove an item that does not exist.");
00729 } else {
00730 error = microfeed_feed_call_modify_item_callback(feed, item, NULL);
00731 microfeed_item_free(item);
00732
00733 microfeed_feed_unref(feed);
00734 }
00735
00736 return error;
00737 }
00738
00739 static MicrofeedError* method_read_items(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message) {
00740 MicrofeedError* error;
00741 DBusMessageIter iter;
00742 const char* uri;
00743 const char* start_uid;
00744 const char* end_uid;
00745 MicrofeedFeed* feed;
00746
00747 if (!dbus_message_iter_init(message, &iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
00748
00749 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected feed uri argument in ReadItem method.");
00750 }
00751 dbus_message_iter_get_basic(&iter, &uri);
00752 if (!dbus_message_iter_next(&iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
00753
00754 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected start item uid argument in ReadItem method.");
00755 }
00756 dbus_message_iter_get_basic(&iter, &start_uid);
00757 if (!dbus_message_iter_next(&iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
00758
00759 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected end item uid argument in ReadItem method.");
00760 }
00761 dbus_message_iter_get_basic(&iter, &end_uid);
00762 if (!(feed = get_or_instantiate_feed(publisher, uri))) {
00763
00764 return microfeed_error_new(MICROFEED_ERROR_NO_SUCH_FEED, "Trying to read items of a feed that does not exist.");
00765 }
00766
00767 error = microfeed_feed_unset_item_statuses(feed, start_uid, end_uid, MICROFEED_ITEM_STATUS_UNREAD);
00768
00769 microfeed_feed_unref(feed);
00770
00771 return error;
00772 }
00773
00774 static MicrofeedError* method_republish_items(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message) {
00775 DBusMessageIter iter;
00776 const char* uri;
00777 const char* start_uid;
00778 const char* end_uid;
00779 dbus_uint16_t max_count;
00780 MicrofeedFeed* feed;
00781
00782 if (!dbus_message_iter_init(message, &iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
00783
00784 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected a feed uri argument in PublishItems method");
00785 }
00786 dbus_message_iter_get_basic(&iter, &uri);
00787 if (!dbus_message_iter_next(&iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
00788
00789 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected a start item uid argument in PublishItems method");
00790 }
00791 dbus_message_iter_get_basic(&iter, &start_uid);
00792 if (!dbus_message_iter_next(&iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
00793
00794 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected an end item uid argument in PublishItems method");
00795 }
00796 dbus_message_iter_get_basic(&iter, &end_uid);
00797 if (!dbus_message_iter_next(&iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_UINT16) {
00798
00799 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected an maximum count argument in PublishItems method");
00800 }
00801 dbus_message_iter_get_basic(&iter, &max_count);
00802
00803 if (!(feed = microfeed_store_get(subscriber->feeds, uri, MicrofeedFeed))) {
00804
00805 return microfeed_error_new(MICROFEED_ERROR_NO_SUCH_FEED, "Trying to republish items of a feed that is not subscribed.");
00806 }
00807
00808 microfeed_feed_republish(feed, (*start_uid ? start_uid : NULL), (*end_uid ? end_uid : NULL), max_count, subscriber->unique_connection_name);
00809
00810 return NULL;
00811 }
00812
00813 static MicrofeedError* method_send_item_data(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message) {
00814 MicrofeedError* error;
00815 DBusMessageIter iter;
00816 const char* uri;
00817 const char* uid;
00818 MicrofeedFeed* feed;
00819 void* data;
00820 size_t data_size;
00821 DBusMessage* reply;
00822
00823 if (!publisher->callbacks.download_image) {
00824
00825 return microfeed_error_new(MICROFEED_ERROR_NO_ITEM_DATA, "Publisher does not support image downloading");
00826 }
00827 if (!dbus_message_iter_init(message, &iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
00828
00829 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected a feed uri argument in GetItemData method");
00830 }
00831 dbus_message_iter_get_basic(&iter, &uri);
00832 if (!dbus_message_iter_next(&iter) || dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
00833
00834 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected an item uid argument in SendItemData method");
00835 }
00836 dbus_message_iter_get_basic(&iter, &uid);
00837
00838 if (!(feed = microfeed_store_get(subscriber->feeds, uri, MicrofeedFeed))) {
00839
00840 return microfeed_error_new(MICROFEED_ERROR_NO_SUCH_FEED, "Trying to get item data of a feed that is not subscribed.");
00841 }
00842
00843 error = microfeed_feed_send_item_data(feed, uid, subscriber->unique_connection_name);
00844
00845 return error;
00846 }
00847
00848 static MicrofeedError* method_mark_item(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message) {
00849 MicrofeedError* error = NULL;
00850 DBusError dbus_error;
00851 const char* uri;
00852 const char* uid;
00853 MicrofeedFeed* feed;
00854
00855 dbus_error_init(&dbus_error);
00856 if (!dbus_message_get_args(message, &dbus_error, DBUS_TYPE_STRING, &uri, DBUS_TYPE_STRING, &uid, DBUS_TYPE_INVALID)) {
00857 error = microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected feed uri and item uid arguments in MarkItem method");
00858 } else if (!(feed = get_or_instantiate_feed(publisher, uri))) {
00859 error = microfeed_error_new(MICROFEED_ERROR_NO_SUCH_FEED, "Trying to mark an item of a feed that does not exist.");
00860 } else {
00861 error = microfeed_feed_set_item_status(feed, uid, MICROFEED_ITEM_STATUS_MARKED);
00862
00863 microfeed_feed_unref(feed);
00864 }
00865
00866 return error;
00867 }
00868
00869 static MicrofeedError* method_unmark_item(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message) {
00870 MicrofeedError* error = NULL;
00871 DBusError dbus_error;
00872 const char* uri;
00873 const char* uid;
00874 MicrofeedFeed* feed;
00875
00876 dbus_error_init(&dbus_error);
00877 if (!dbus_message_get_args(message, &dbus_error, DBUS_TYPE_STRING, &uri, DBUS_TYPE_STRING, &uid, DBUS_TYPE_INVALID)) {
00878 error = microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected feed uri and item uid arguments in UnarkItem method");
00879 } else if (!(feed = get_or_instantiate_feed(publisher, uri))) {
00880 error = microfeed_error_new(MICROFEED_ERROR_NO_SUCH_FEED, "Trying to unmark an item of a feed that does not exist.");
00881 } else {
00882 error = microfeed_feed_unset_item_status(feed, uid, MICROFEED_ITEM_STATUS_MARKED);
00883
00884 microfeed_feed_unref(feed);
00885 }
00886
00887 return error;
00888 }
00889
00890 static MicrofeedError* method_ping(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message) {
00891
00892 return NULL;
00893 }
00894
00895 static MicrofeedError* method_subscribe_feed(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message) {
00896 MicrofeedFeed* feed;
00897 DBusError error;
00898 char* uri;
00899 DBusMessage* reply;
00900 Timeout* timeout;
00901 unsigned long int interval;
00902 time_t timestamp = 0;
00903 void* data;
00904 size_t data_size;
00905 time_t elapsed;
00906
00907 dbus_error_init(&error);
00908 if (!dbus_message_get_args(message, &error, DBUS_TYPE_STRING, &uri, DBUS_TYPE_INVALID)) {
00909
00910 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected feed uri argument in SubscribeFeed method");
00911 }
00912
00913 if (microfeed_store_get(subscriber->feeds, uri, MicrofeedFeed)) {
00914
00915 return microfeed_error_new(MICROFEED_ERROR_FEED_ALREADY_SUBSCRIBED, "Cannot subscribe the feed twice.");
00916 }
00917
00918 if (!(feed = get_or_instantiate_feed(publisher, uri))) {
00919
00920 return microfeed_error_new(MICROFEED_ERROR_NO_SUCH_FEED, "Cannot subscribe the feed.");
00921 }
00922
00923 microfeed_store_insert(subscriber->feeds, feed);
00924
00925 printf("%s > OK (early sending)\n", publisher->identifier);
00926 reply = dbus_message_new_method_return(message);
00927 dbus_connection_send(publisher->connection, reply, NULL);
00928 dbus_message_unref(reply);
00929
00930 microfeed_publisher_send_item_signal(publisher, subscriber->unique_connection_name, MICROFEED_SIGNAL_NAME_ITEM_ADDED, uri, microfeed_feed_get_metadata_item(feed));
00931
00932 if ((interval = (unsigned long int)microfeed_publisher_get_setting_value_integer(publisher, "update_interval", 0))) {
00933 if ((microfeed_database_get_data(publisher->timestamp_database, &uri, strlen(uri) + 1, &data, &data_size))) {
00934 if (data_size >= sizeof(time_t)) {
00935 timestamp = *((time_t*)data);
00936 }
00937 free(data);
00938 }
00939
00940 printf("LAST UPDATE: %ld\n", timestamp);
00941
00942 elapsed = time(NULL) - timestamp;
00943 if (elapsed > interval) {
00944 timeout = timeout_new(publisher, feed, 0);
00945 } else {
00946 timeout = timeout_new(publisher, feed, interval - elapsed);
00947 }
00948 microfeed_store_insert(publisher->timeouts, timeout);
00949 }
00950
00951 return (MicrofeedError*)-1;
00952 }
00953
00954 static MicrofeedError* method_unsubscribe_feed(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message) {
00955 DBusError error;
00956 char* uri;
00957 MicrofeedFeed* feed;
00958
00959 dbus_error_init(&error);
00960 if (!dbus_message_get_args(message, &error, DBUS_TYPE_STRING, &uri, DBUS_TYPE_INVALID)) {
00961
00962 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected feed uri argument in UnsubscribeFeed method");
00963 }
00964 if (!(feed = microfeed_store_remove_key(subscriber->feeds, uri, MicrofeedFeed))) {
00965
00966 return microfeed_error_new(MICROFEED_ERROR_FEED_NOT_SUBSCRIBED, "Trying to unsubscribe a feed that is not subscribed");
00967 }
00968
00969 microfeed_feed_unref(feed);
00970
00971 return NULL;
00972 }
00973
00974 static MicrofeedError* method_update_feed(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message) {
00975 MicrofeedFeed* feed;
00976 DBusError error;
00977 char* uri;
00978
00979 dbus_error_init(&error);
00980 if (!dbus_message_get_args(message, &error, DBUS_TYPE_STRING, &uri, DBUS_TYPE_INVALID)) {
00981
00982 return microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "Expected feed uri argument in UpdateFeed method");
00983 }
00984
00985 if (!(feed = get_or_instantiate_feed(publisher, uri))) {
00986
00987 return microfeed_error_new(MICROFEED_ERROR_FEED_NOT_SUBSCRIBED, "Trying to update a feed that is not subscribed");
00988 }
00989
00990 microfeed_feed_update(feed, subscriber->unique_connection_name);
00991 update_last_update_timestamp(feed);
00992
00993 microfeed_feed_unref(feed);
00994
00995 return NULL;
00996 }
00997
00998 static MicrofeedError* method_create_publisher(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message) {
00999
01000
01001 microfeed_publisher_add_setting(publisher, "archive_old_items", "Archive old items", "hours", "non-negative integer", "5", "5");
01002 microfeed_publisher_add_setting(publisher, "update_interval", "Update interval", "minutes", "non-negative integer", "5", "1");
01003
01004 publisher->callbacks.initialize_settings(publisher, publisher->user_data);
01005
01006 return NULL;
01007 }
01008
01009 static MicrofeedError* method_destroy_publisher(MicrofeedPublisher* publisher, Subscriber* subscriber, DBusMessage* message) {
01010 MicrofeedStoreIterator* subscriber_iterator;
01011 Subscriber* feed_subscriber;
01012 MicrofeedStoreIterator* feed_iterator;
01013 MicrofeedFeed* feed;
01014
01015 microfeed_mutex_lock(publisher->mutex);
01016
01017 dbus_connection_unregister_object_path(publisher->connection, publisher->object_path);
01018
01019 for (subscriber_iterator = microfeed_store_iterate(publisher->subscribers, NULL);
01020 (feed_subscriber = microfeed_store_iterator_get(subscriber_iterator, Subscriber));
01021 microfeed_store_iterator_next(subscriber_iterator)) {
01022 for (feed_iterator = microfeed_store_iterate(feed_subscriber->feeds, NULL);
01023 (feed = microfeed_store_iterator_get(feed_iterator, MicrofeedFeed));
01024 microfeed_store_iterator_next(feed_iterator)) {
01025 microfeed_feed_unref(feed);
01026 microfeed_publisher_send_error_signal(publisher, subscriber->unique_connection_name, MICROFEED_ERROR_NO_SUCH_PUBLISHER, NULL, NULL, "Publisher destroyed.");
01027 }
01028 }
01029 for (feed_iterator = microfeed_store_iterate(publisher->feeds, NULL);
01030 (feed = microfeed_store_iterator_get(feed_iterator, MicrofeedFeed));
01031 microfeed_store_iterator_next(feed_iterator)) {
01032 microfeed_feed_remove_free_callback(feed, remove_data_from_store, publisher->feeds);
01033 }
01034
01035 microfeed_mutex_unlock(publisher->mutex);
01036
01037 return NULL;
01038 }
01039
01040 static void object_unregister(DBusConnection* connection, void* user_data) {
01041 }
01042
01043 static DBusHandlerResult object_message(DBusConnection* connection, DBusMessage* message, void* user_data) {
01044 DBusHandlerResult result = DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
01045 MicrofeedPublisher* publisher;
01046 const char* unique_connection_name;
01047 int i;
01048 Subscriber* subscriber;
01049 char buffer[1024];
01050 MicrofeedError* error;
01051 MethodThreadData* mtd;
01052
01053 publisher = (MicrofeedPublisher*)user_data;
01054
01055 microfeed_mutex_lock(publisher->mutex);
01056
01057 unique_connection_name = dbus_message_get_sender(message);
01058 if (!(subscriber = (Subscriber*)microfeed_store_get(publisher->subscribers, unique_connection_name, Subscriber))) {
01059 subscriber = subscriber_new(publisher, unique_connection_name);
01060 microfeed_store_insert(publisher->subscribers, subscriber);
01061
01062 snprintf(buffer, 1024, "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',member='NameOwnerChanged',arg0='%s'", unique_connection_name);
01063 dbus_bus_add_match(connection, buffer, NULL);
01064 }
01065
01066 subscriber->last_activity = time(NULL);
01067 for (i = 0; method_callbacks[i].name; i++) {
01068 if (dbus_message_is_method_call(message, MICROFEED_DBUS_INTERFACE_PUBLISHER, method_callbacks[i].name)) {
01069 printf("%s < %s (%s)\n", publisher->identifier, method_callbacks[i].name, unique_connection_name);
01070
01071 mtd = microfeed_memory_allocate(MethodThreadData);
01072 mtd->publisher = publisher;
01073 mtd->subscriber = subscriber;
01074 mtd->callback = method_callbacks[i].callback;
01075 mtd->message = dbus_message_ref(message);
01076 microfeed_thread_pool_queue_thread_with_exit_callback(publisher->thread_pool, method_thread, mtd, thread_exited, publisher);
01077
01078 result = DBUS_HANDLER_RESULT_HANDLED;
01079 break;
01080 }
01081 }
01082
01083 if (result != DBUS_HANDLER_RESULT_HANDLED && microfeed_store_get_size(subscriber->feeds) == 0) {
01084 snprintf(buffer, 1024, "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',method='NameOwnerChanged',arg0='%s'", unique_connection_name);
01085 dbus_bus_remove_match(connection, buffer, NULL);
01086
01087 microfeed_store_remove(publisher->subscribers, subscriber);
01088 subscriber_free(subscriber);
01089 }
01090
01091 microfeed_mutex_unlock(publisher->mutex);
01092
01093 return result;
01094 }
01095
01096 static MicrofeedError* settings_feed_modify_item(MicrofeedFeed* feed, MicrofeedItem* existing_item, MicrofeedItem* new_item, void* user_data) {
01097 MicrofeedError* error = NULL;;
01098 MicrofeedPublisher* publisher;
01099 const char* value;
01100
01101 publisher = microfeed_feed_get_publisher(feed);
01102 if (!existing_item) {
01103 error = microfeed_error_new(MICROFEED_ERROR_NO_SUCH_ITEM, "No such setting.");
01104 } else {
01105 if ((value = microfeed_item_get_property(new_item, MICROFEED_ITEM_PROPERTY_NAME_SETTING_VALUE))) {
01106 if (publisher->callbacks.update_setting(publisher, microfeed_item_get_uid(new_item), value, publisher->user_data)) {
01107 microfeed_item_set_property(existing_item, MICROFEED_ITEM_PROPERTY_NAME_SETTING_VALUE, value);
01108 microfeed_feed_replace_item(feed, existing_item);
01109 }
01110
01111 } else {
01112 error = microfeed_error_new(MICROFEED_ERROR_INVALID_ARGUMENTS, "No setting.value property in settings item.");
01113 }
01114 }
01115
01116 return error;
01117 }
01118
01119 static MicrofeedError* images_feed_download_item_data(MicrofeedFeed* feed, const char* uid, void** data, size_t* length, void* user_data) {
01120 MicrofeedPublisher* publisher;
01121 MicrofeedError* error;
01122
01123 publisher = microfeed_feed_get_publisher(feed);
01124 error = publisher->callbacks.download_image(publisher, uid, data, length, publisher->user_data);
01125 if (!error) {
01126 microfeed_feed_unset_item_status(feed, uid, MICROFEED_ITEM_STATUS_UNREAD);
01127 }
01128
01129 return error;
01130 }
01131
01132 static int timeout_handler(void* data) {
01133 int retvalue = 1;
01134 Timeout* timeout;
01135 MicrofeedPublisher* publisher;
01136 MicrofeedFeed* feed;
01137 unsigned long int interval;
01138
01139 timeout = (Timeout*)data;
01140 feed = timeout->feed;
01141 publisher = microfeed_feed_get_publisher(feed);
01142
01143 interval = (unsigned long int)microfeed_publisher_get_setting_value_integer(publisher, "update_interval", 0);
01144 if (interval && interval != timeout->interval) {
01145 retvalue = 0;
01146 microfeed_store_remove(publisher->timeouts, timeout);
01147
01148 printf("INTERVAL: %ld\n", interval);
01149 if (interval) {
01150 timeout = timeout_new(publisher, feed, interval);
01151 microfeed_store_insert(publisher->timeouts, timeout);
01152 }
01153 }
01154
01155 microfeed_thread_pool_queue_thread_with_exit_callback(publisher->thread_pool, update_thread, feed, thread_exited, publisher);
01156
01157 return retvalue;
01158 }
01159
01160 static void* method_thread(void* data) {
01161 MethodThreadData* mtd;
01162 MicrofeedError* error;
01163 char buffer[1024];
01164 DBusMessage* reply;
01165
01166 mtd = (MethodThreadData*)data;
01167
01168 error = mtd->callback(mtd->publisher, mtd->subscriber, mtd->message);
01169
01170 microfeed_mutex_lock(mtd->publisher->mutex);
01171
01172 if (!error) {
01173 printf("%s > OK\n", mtd->publisher->identifier);
01174 reply = dbus_message_new_method_return(mtd->message);
01175 } else if (error == (MicrofeedError*)-1) {
01176 printf("%s > OK (sent already)\n", mtd->publisher->identifier);
01177 reply = NULL;
01178 } else {
01179 printf("%s > %s (%s)\n", mtd->publisher->identifier, microfeed_error_get_name(error), microfeed_error_get_message(error));
01180 snprintf(buffer, 1024, "%s.%s", MICROFEED_DBUS_INTERFACE_ERROR, microfeed_error_get_name(error));
01181 reply = dbus_message_new_error(mtd->message, buffer, microfeed_error_get_message(error));
01182 microfeed_error_free(error);
01183 }
01184 if (reply) {
01185 dbus_connection_send(mtd->publisher->connection, reply, NULL);
01186 dbus_message_unref(reply);
01187 }
01188
01189 if (microfeed_store_get_size(mtd->subscriber->feeds) == 0) {
01190 snprintf(buffer, 1024, "type='signal',sender='org.freedesktop.DBus',interface='org.freedesktop.DBus',method='NameOwnerChanged',arg0='%s'", dbus_message_get_sender(mtd->message));
01191 dbus_bus_remove_match(mtd->publisher->connection, buffer, NULL);
01192
01193 microfeed_store_remove(mtd->publisher->subscribers, mtd->subscriber);
01194 subscriber_free(mtd->subscriber);
01195 }
01196
01197 microfeed_mutex_unlock(mtd->publisher->mutex);
01198
01199 dbus_message_unref(mtd->message);
01200 microfeed_memory_free(mtd);
01201
01202 return NULL;
01203 }
01204
01205 static void* update_thread(void* data) {
01206 MicrofeedFeed* feed;
01207
01208 feed = (MicrofeedFeed*)data;
01209
01210 microfeed_feed_update(feed, NULL);
01211 update_last_update_timestamp(feed);
01212
01213 return NULL;
01214 }
01215
01216 static void thread_exited(MicrofeedThread* thread, void* user_data) {
01217 MicrofeedPublisher* publisher;
01218
01219 publisher = (MicrofeedPublisher*)user_data;
01220
01221 microfeed_mutex_lock(publisher->mutex);
01222
01223 if (publisher->callbacks.no_more_subscribers &&
01224 microfeed_store_get_size(publisher->subscribers) == 0 &&
01225 microfeed_thread_pool_get_started_thread_count(publisher->thread_pool) == 0) {
01226 publisher->callbacks.no_more_subscribers(publisher, publisher->user_data);
01227 }
01228
01229 microfeed_mutex_unlock(publisher->mutex);
01230 }
01231
01232 static MicrofeedFeed* get_or_instantiate_feed(MicrofeedPublisher* publisher, const char* uri) {
01233 MicrofeedFeed* feed;
01234
01235 microfeed_mutex_lock(publisher->mutex);
01236
01237 if (!(feed = microfeed_store_get(publisher->feeds, uri, MicrofeedFeed))) {
01238 if ((feed = publisher->callbacks.instantiate_feed(publisher, uri, publisher->user_data))) {
01239 microfeed_store_insert(publisher->feeds, feed);
01240 microfeed_feed_add_free_callback(feed, remove_data_from_store, publisher->feeds);
01241 }
01242 } else {
01243 microfeed_feed_ref(feed);
01244 }
01245
01246 microfeed_mutex_unlock(publisher->mutex);
01247
01248 return feed;
01249 }
01250
01251 static void update_last_update_timestamp(MicrofeedFeed* feed) {
01252 MicrofeedPublisher* publisher;
01253 time_t timestamp;
01254 const char* uri;
01255
01256 publisher = microfeed_feed_get_publisher(feed);
01257 timestamp = time(NULL);
01258 uri = microfeed_feed_get_uri(feed);
01259
01260 microfeed_mutex_lock(publisher->mutex);
01261
01262 microfeed_database_replace_data(publisher->timestamp_database, uri, strlen(uri) + 1, ×tamp, sizeof(time_t));
01263
01264 microfeed_mutex_unlock(publisher->mutex);
01265 }
01266
01267 static void remove_data_from_store(void* data, void* user_data) {
01268 MicrofeedStore* store;
01269
01270 store = (MicrofeedStore*)user_data;
01271 microfeed_store_remove(store, data);
01272 }