1 /* 2 * @file node_source.h generic node source interface 3 * 4 * Copyright (C) 2005-2014 Lars Windolf <lars.windolf@gmx.de> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License, or 9 * (at your option) any later version. 10 * 11 * This program is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with this program; if not, write to the Free Software 18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 19 */ 20 21 #ifndef _NODE_SOURCE_H 22 #define _NODE_SOURCE_H 23 24 #include <glib.h> 25 #include <gmodule.h> 26 #include "node.h" 27 #include "node_type.h" 28 #include "subscription_type.h" 29 #include "fl_sources/google_reader_api.h" 30 31 /* Liferea allows to have different sources in the feed list. These 32 sources are called "node sources" henceforth. Node sources can 33 (but do not need to) be single instance only. Node sources do 34 provide a subtree of the feed list that can be read-only 35 or not. A node source might allow or not allow to add sub folders 36 and reorder (DnD) folder contents. A node source might allow 37 hierarchic grouping of its subtree or not. These properties 38 are determined by the node source type capability flags. 39 40 The node source concept itself is a node type. The implementation 41 of this node type can be found in node_source.c. 42 43 The default node source type must be capable of serving as the root 44 node for all other source types. This mean it has to ensure to load 45 all other node source instances at their insertion nodes in 46 the feed list. 47 48 Each source type has to be able to serve user requests and is 49 responsible for keeping its feed list node's states up-to-date. 50 A source type implementation can omit all callbacks marked as 51 optional. */ 52 53 typedef enum { 54 NODE_SOURCE_CAPABILITY_IS_ROOT = (1<<0), /*<< flag only for default feed list source */ 55 NODE_SOURCE_CAPABILITY_DYNAMIC_CREATION = (1<<1), /*<< feed list source is user created */ 56 NODE_SOURCE_CAPABILITY_WRITABLE_FEEDLIST = (1<<2), /*<< the feed list tree of the source can be changed */ 57 NODE_SOURCE_CAPABILITY_ADD_FEED = (1<<3), /*<< feeds can be added to the source */ 58 NODE_SOURCE_CAPABILITY_ADD_FOLDER = (1<<4), /*<< folders can be added to the source */ 59 NODE_SOURCE_CAPABILITY_HIERARCHIC_FEEDLIST = (1<<5), /*<< the feed list tree of the source can have hierarchic folders */ 60 NODE_SOURCE_CAPABILITY_ITEM_STATE_SYNC = (1<<6), /*<< the item state can and should be sync'ed with remote */ 61 NODE_SOURCE_CAPABILITY_CONVERT_TO_LOCAL = (1<<7), /*<< node sources of this type can be converted to internal subscription lists */ 62 NODE_SOURCE_CAPABILITY_GOOGLE_READER_API = (1<<8), /*<< node sources of this type are Google Reader clones */ 63 NODE_SOURCE_CAPABILITY_CAN_LOGIN = (1<<9) /*<< node source needs login (means loginState member is to be used) */ 64 } nodeSourceCapability; 65 66 /* Node source state model */ 67 typedef enum { 68 NODE_SOURCE_STATE_NONE = 0, /*<< no authentication tried so far */ 69 NODE_SOURCE_STATE_IN_PROGRESS, /*<< authentication in progress */ 70 NODE_SOURCE_STATE_ACTIVE, /*<< authentication succeeded */ 71 NODE_SOURCE_STATE_NO_AUTH, /*<< authentication has failed */ 72 NODE_SOURCE_STATE_MIGRATE, /*<< source will be migrated, do not do anything anymore! */ 73 } nodeSourceState; 74 75 /* Node source subscription update flags */ 76 typedef enum { 77 /* 78 * Update only the subscription list, and not each node underneath it. 79 * Note: Uses higher 16 bits to avoid conflict. 80 */ 81 NODE_SOURCE_UPDATE_ONLY_LIST = (1<<16), 82 /* 83 * Only login, do not do any updates. 84 */ 85 NODE_SOURCE_UPDATE_ONLY_LOGIN = (1<<17) 86 } nodeSourceUpdate; 87 88 /* 89 * Number of auth failures after which we stop bothering the user while 90 * auto-updating until he manually updates again. 91 */ 92 #define NODE_SOURCE_MAX_AUTH_FAILURES 3 93 94 /* feed list node source type */ 95 typedef struct nodeSourceType { 96 const gchar *id; /*<< a unique feed list source type identifier */ 97 const gchar *name; /*<< a descriptive source name (for preferences and menus) */ 98 gulong capabilities; /*<< bitmask of feed list source capabilities */ 99 googleReaderApi api; /*<< OPTIONAL endpoint definitions for Google Reader like JSON API */ 100 101 /* The subscription type for all child nodes that are subscriptions */ 102 subscriptionTypePtr feedSubscriptionType; 103 104 /* The subscription type for the source itself (can be NULL) */ 105 subscriptionTypePtr sourceSubscriptionType; 106 107 /* source type loading and unloading methods */ 108 void (*source_type_init)(void); 109 void (*source_type_deinit)(void); 110 111 /* 112 * This OPTIONAL callback is used to create an instance 113 * of the implemented source type. It is to be called by 114 * the parent source node_request_add_*() implementation. 115 * Mandatory for all sources except the root source. 116 */ 117 void (*source_new)(void); 118 119 /* 120 * This OPTIONAL callback is used to delete an instance 121 * of the implemented source type. It is to be called 122 * by the parent source node_remove() implementation. 123 * Mandatory for all sources except the root provider source. 124 */ 125 void (*source_delete)(nodePtr node); 126 127 /* 128 * This MANDATORY method is called when the source is to 129 * create the feed list subtree attached to the source root 130 * node. 131 */ 132 void (*source_import)(nodePtr node); 133 134 /* 135 * This MANDATORY method is called when the source is to 136 * save it's feed list subtree (if necessary at all). This 137 * is not a request to save the data of the attached nodes! 138 */ 139 void (*source_export)(nodePtr node); 140 141 /* 142 * This MANDATORY method is called to get an OPML representation 143 * of the feedlist of the given node source. Returns a newly 144 * allocated filename string that is to be freed by the 145 * caller. 146 */ 147 gchar * (*source_get_feedlist)(nodePtr node); 148 149 /* 150 * This MANDATARY method is called to request the source to update 151 * its subscriptions list and the child subscriptions according 152 * the its update interval. 153 */ 154 void (*source_auto_update)(nodePtr node); 155 156 /* 157 * Frees all data of the given node source instance. To be called 158 * during node_free() for a source node. 159 */ 160 void (*free) (nodePtr node); 161 162 /* 163 * Changes the flag state of an item. This is to allow node source type 164 * implementations to synchronize remote item states. 165 * 166 * This is an OPTIONAL method. 167 */ 168 void (*item_set_flag) (nodePtr node, itemPtr item, gboolean newState); 169 170 /* 171 * Mark an item as read. This is to allow node source type 172 * implementations to synchronize remote item states. 173 * 174 * This is an OPTIONAL method. 175 */ 176 void (*item_mark_read) (nodePtr node, itemPtr item, gboolean newState); 177 178 /* 179 * Add a new folder to the feed list provided by node 180 * source. OPTIONAL, but must be implemented when 181 * NODE_SOURCE_CAPABILITY_WRITABLE_FEEDLIST and 182 * NODE_SOURCE_CAPABILITY_HIERARCHIC_FEEDLIST are set. 183 */ 184 nodePtr (*add_folder) (nodePtr node, const gchar *title); 185 186 /* 187 * Add a new subscription to the feed list provided 188 * by the node source. OPTIONAL method, that must be implemented 189 * when NODE_SOURCE_CAPABILITY_WRITABLE_FEEDLIST is set. 190 * 191 * The implementation could propagate the added subscription 192 * to a remote feed list service. 193 * 194 * The implementation MUST create and return a new child node 195 * setup with the given subscription which might be changed as necessary. 196 * 197 * The returned node will be automatically added to the feed list UI. 198 * Initial update and state saving will be triggered automatically. 199 */ 200 nodePtr (*add_subscription) (nodePtr node, struct subscription *subscription); 201 202 /* 203 * Removes an existing node (subscription or folder) from the feed list 204 * provided by the node source. OPTIONAL method that must be 205 * implemented when NODE_SOURCE_CAPABILITY_WRITABLE_FEEDLIST is set. 206 */ 207 void (*remove_node) (nodePtr node, nodePtr child); 208 209 /* 210 * Converts all subscriptions to default source subscriptions. 211 * 212 * This is an OPTIONAL method. 213 */ 214 void (*convert_to_local) (nodePtr node); 215 216 } *nodeSourceTypePtr; 217 218 /* feed list source instance */ 219 typedef struct nodeSource { 220 nodeSourceTypePtr type; /*<< node source type of this source instance */ 221 nodePtr root; /*<< insertion node of this node source instance */ 222 GQueue *actionQueue; /*<< queue for async actions */ 223 gint loginState; /*<< The current login state */ 224 225 gchar *authToken; /*<< The authorization token */ 226 gint authFailures; /*<< Number of authentication failures */ 227 } *nodeSourcePtr; 228 229 /* Use this to cast the node source type from a node structure. */ 230 #define NODE_SOURCE_TYPE(node) ((nodeSourcePtr)(node->source))->type 231 232 #define NODE_SOURCE_TYPE_DUMMY_ID "fl_dummy" 233 234 /** 235 * node_source_root_from_node: (skip) 236 * @node: any child node 237 * 238 * Get the root node of a feed list source for any given child node. 239 * 240 * Returns: node source root node 241 */ 242 nodePtr node_source_root_from_node (nodePtr node); 243 244 /** 245 * node_source_setup_root: (skip) 246 * 247 * Scans the source type list for the root source provider. 248 * If found creates a new root source and starts it's import. 249 * 250 * Returns: a newly created root node 251 */ 252 nodePtr node_source_setup_root (void); 253 254 /** 255 * node_source_new: (skip) 256 * @node: a newly created node 257 * @nodeSourceType: the node source type 258 * @url: subscription URL 259 * 260 * Creates a new source and assigns it to the given new node. 261 * To be used to prepare a source node before adding it to the 262 * feed list. This method takes care of setting the proper source 263 * subscription type and setting up the subscription if url != NULL. 264 * The caller needs set additional auth info for the subscription. 265 */ 266 void node_source_new (nodePtr node, nodeSourceTypePtr nodeSourceType, const gchar *url); 267 268 /** 269 * node_source_set_state: (skip) 270 * @node: the node source node 271 * @newState: the new state 272 * 273 * Change state of the node source by node 274 */ 275 void node_source_set_state (nodePtr node, gint newState); 276 277 /** 278 * node_source_set_auth_token: (skip) 279 * @node: a node 280 * @token: a string 281 * 282 * Store any type of authentication token (e.g. a cookie or session id) 283 * 284 * FIXME: maybe drop this in favour of node metadata 285 */ 286 void node_source_set_auth_token (nodePtr node, gchar *token); 287 288 /** 289 * node_source_update: (skip) 290 * @node: the source node 291 * 292 * Force the source to update its subscription list and 293 * the child subscriptions themselves. 294 */ 295 void node_source_update (nodePtr node); 296 297 /** 298 * node_source_auto_update: (skip) 299 * @node: the source node 300 * 301 * Request the source to update its subscription list and 302 * the child subscriptions if necessary according to the 303 * update interval of the source. 304 */ 305 void node_source_auto_update (nodePtr node); 306 307 /** 308 * node_source_add_subscription: (skip) 309 * @node: the source node 310 * @subscription: the new subscription 311 * 312 * Called when a new subscription has been added to the node source. 313 * 314 * Returns: a new node intialized with the new subscription 315 */ 316 nodePtr node_source_add_subscription (nodePtr node, struct subscription *subscription); 317 318 /** 319 * node_source_remove_node: (skip) 320 * @node: the source node 321 * @child: the child node to remove 322 * 323 * Called when an existing subscription is to be removed from a node source. 324 */ 325 void node_source_remove_node (nodePtr node, nodePtr child); 326 327 /** 328 * node_source_add_folder: (skip) 329 * @node: the source node 330 * @title: the folder title 331 * 332 * Called when a new folder is to be added to a node source feed list. 333 * 334 * Returns: a new node representing the new folder 335 */ 336 nodePtr node_source_add_folder (nodePtr node, const gchar *title); 337 338 /** 339 * node_source_update_folder: (skip) 340 * @node: any node 341 * @folder: the target folder 342 * 343 * Called to update a nodes folder. If current folder != given folder 344 * the node will be reparented. 345 */ 346 void node_source_update_folder (nodePtr node, nodePtr folder); 347 348 /** 349 * node_source_find_or_create_folder: (skip) 350 * @parent: Parent folder (or source root node) 351 * @id: Folder/category id (or NULL) 352 * @label: Folder display name 353 * 354 * Find a folder by the name under parent or create it. 355 * 356 * If a node source doesn't provide ids the category display name should be 357 * used as id. The worst thing happening then is to evenly named categories 358 * being merged into one (which the user can easily workaround by renaming 359 * on the remote side). 360 * 361 * Returns: a valid nodePtr 362 */ 363 nodePtr node_source_find_or_create_folder (nodePtr parent, const gchar *id, const gchar *label); 364 365 /** 366 * node_source_item_mark_read: (skip) 367 * @node: the source node 368 * @item: the affected item 369 * @newState: the new item read state 370 * 371 * Called when the read state of an item changes. 372 */ 373 void node_source_item_mark_read (nodePtr node, itemPtr item, gboolean newState); 374 375 /** 376 * node_source_set_item_flag: (skip) 377 * @node: the source node 378 * @item: the affected item 379 * @newState: the new item flag state 380 * 381 * Called when the flag state of an item changes. 382 */ 383 void node_source_item_set_flag (nodePtr node, itemPtr item, gboolean newState); 384 385 /** 386 * node_source_convert_to_local: (skip) 387 * @node: the source node 388 * 389 * Converts all subscriptions to default source subscriptions. 390 */ 391 void node_source_convert_to_local (nodePtr node); 392 393 /** 394 * node_source_type_register: (skip) 395 * @type: the type to register 396 * 397 * Registers a new node source type. Needs to be called before feed list import! 398 * To be used only via NodeSourceTypeActivatable 399 */ 400 gboolean node_source_type_register (nodeSourceTypePtr type); 401 402 403 /* implementation of the node type interface */ 404 405 #define IS_NODE_SOURCE(node) (node->type == node_source_get_node_type ()) 406 407 /** 408 * node_source_get_node_type: (skip) 409 * 410 * Returns: the node source node type implementation. 411 */ 412 nodeTypePtr node_source_get_node_type (void); 413 414 #endif 415