예제 #1
0
void
subscription_update (subscriptionPtr subscription, guint flags)
{
	updateRequestPtr		request;
	GTimeVal			now;
	
	if (!subscription)
		return;
		
	if (subscription->updateJob)
		return;
	
	debug1 (DEBUG_UPDATE, "Scheduling %s to be updated", node_get_title (subscription->node));
	 
	if (subscription_can_be_updated (subscription)) {
		liferea_shell_set_status_bar (_("Updating \"%s\""), node_get_title (subscription->node));

		g_get_current_time (&now);
		subscription_reset_update_counter (subscription, &now);

		request = update_request_new ();
		request->updateState = update_state_copy (subscription->updateState);
		request->options = update_options_copy (subscription->updateOptions);
		request->source = g_strdup (subscription_get_source (subscription));
		if (subscription_get_filter (subscription))
			request->filtercmd = g_strdup (subscription_get_filter (subscription));

		if (SUBSCRIPTION_TYPE (subscription)->prepare_update_request (subscription, request))
			subscription->updateJob = update_execute_request (subscription, request, subscription_process_update_result, subscription, flags);
		else
			update_request_free (request);
	}
}
예제 #2
0
void
subscription_update_favicon (subscriptionPtr subscription)
{
	debug1 (DEBUG_UPDATE, "trying to download favicon.ico for \"%s\"", node_get_title (subscription->node));
	liferea_shell_set_status_bar (_("Updating favicon for \"%s\""), node_get_title (subscription->node));
	g_get_current_time (&subscription->updateState->lastFaviconPoll);
	favicon_download (subscription,
	                  node_get_base_url (subscription->node),
			  subscription_get_source (subscription),
			  subscription->updateOptions,		// FIXME: correct?
	                  subscription_favicon_downloaded, 
			  (gpointer)subscription->node);
}
예제 #3
0
void
feed_list_view_add_duplicate_url_subscription (subscriptionPtr tempSubscription, nodePtr exNode)
{
	GtkWidget	*dialog;
	GtkWindow	*mainwindow;
	gchar		*text;

	text = g_strdup_printf (
			_("Are you sure that you want to add a new subscription with URL \"%s\"? Another subscription with the same URL already exists (\"%s\")."),
			tempSubscription->source,
			node_get_title (exNode)
	);

	mainwindow = GTK_WINDOW (liferea_shell_get_window ());
	dialog = gtk_message_dialog_new (mainwindow,
									 GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
									 GTK_MESSAGE_QUESTION,
									 GTK_BUTTONS_NONE,
									 "%s", text);
	gtk_dialog_add_buttons (GTK_DIALOG (dialog),
							_("_Cancel"), GTK_RESPONSE_CANCEL,
							_("_Add"), GTK_RESPONSE_ACCEPT,
							NULL);
	gtk_window_set_title (GTK_WINDOW (dialog), _("Adding Duplicate Subscription Confirmation"));
	gtk_window_set_transient_for (GTK_WINDOW (dialog), mainwindow);

	g_free (text);

	gtk_widget_show_all (dialog);

	g_signal_connect (G_OBJECT (dialog), "response",
					  G_CALLBACK (feed_list_view_add_duplicate_url_cb), tempSubscription);
}
예제 #4
0
/* 
 * Check if folder of a node changed in Google Reader and move
 * node to the folder with the same name.
 */
static void
aol_source_update_folder (xmlNodePtr match, AolSourcePtr gsource, nodePtr node)
{
	xmlNodePtr	xml;
	xmlChar		*label;
	const gchar	*ptitle;
	nodePtr		parent;
	
	/* check if label of a feed changed */ 
	parent = node->parent;
	ptitle = node_get_title (parent);
	xml = xpath_find (match, "./list[@name='categories']/object/string[@name='label']");
	if (xml) {
		label = xmlNodeListGetString (xml->doc,	xml->xmlChildrenNode, 1);
		if (parent == gsource->root || ! g_str_equal (label, ptitle)) {
			debug2 (DEBUG_UPDATE, "GSource feed label changed for %s to '%s'", node->id, label);
			parent = aol_source_find_or_create_folder ((gchar*)label, gsource->root);
			node_reparent (node, parent);
		}
		xmlFree (label);
	} else {
		/* if feed has no label and parent is not gsource root, reparent to gsource root */
		if (parent != gsource->root)
			node_reparent (node, gsource->root);
	}
}
예제 #5
0
파일: feedlist.c 프로젝트: dmitryvk/liferea
void
feedlist_selection_changed (nodePtr node)
{
	debug_enter ("feedlist_selection_changed");

	debug1 (DEBUG_GUI, "new selected node: %s", node?node_get_title (node):"none");
	if (node != SELECTED) {

		/* When the user selects a feed in the feed list we
		   assume that he got notified of the new items or
		   isn't interested in the event anymore... */
		if (0 != feedlist->priv->newCount)
			feedlist_reset_new_item_count ();

		/* Unload visible items. */
		itemlist_unload (TRUE);
	
		/* Load items of new selected node. */
		SELECTED = node;
		if (SELECTED) {
			itemlist_set_view_mode (node_get_view_mode (SELECTED));		
			itemlist_load (SELECTED);
		} else {
			itemview_clear ();
		}
	}

	debug_exit ("feedlist_selection_changed");
}
예제 #6
0
파일: itemlist.c 프로젝트: skagedal/liferea
/** 
 * To be called whenever a node was selected and should
 * replace the current itemlist.
 */
void
itemlist_load (nodePtr node) 
{
	itemSetPtr	itemSet;
	gint		folder_display_mode;
	gboolean	folder_display_hide_read;

	debug_enter ("itemlist_load");

	g_return_if_fail (NULL != node);
	
	debug1 (DEBUG_GUI, "loading item list with node \"%s\"", node_get_title (node));

	g_assert (!itemlist->priv->guids);
	g_assert (!itemlist->priv->filter);

	/* 1. Filter check. Don't continue if folder is selected and 
	   no folder viewing is configured. If folder viewing is enabled
	   set up a "unread items only" rule depending on the prefences. */

	/* for folders and other heirarchic nodes do filtering */
	if (IS_FOLDER (node) || node->children) {
		liferea_shell_update_allitems_actions (FALSE, 0 != node->unreadCount);

		conf_get_int_value (FOLDER_DISPLAY_MODE, &folder_display_mode);
		if (!folder_display_mode)
			return;
	
		conf_get_bool_value (FOLDER_DISPLAY_HIDE_READ, &folder_display_hide_read);
		if (folder_display_hide_read) {
			itemlist->priv->filter = g_new0(struct itemSet, 1);
			itemlist->priv->filter->anyMatch = TRUE;
			itemset_add_rule (itemlist->priv->filter, "unread", "", TRUE);
		}
	} else {
예제 #7
0
static void
feed_list_view_selection_changed_cb (GtkTreeSelection *selection, gpointer data)
{
	GtkTreeIter		iter;
	GtkTreeModel	*model;
	nodePtr			node;

	if (gtk_tree_selection_get_selected (selection, &model, &iter)) {
	 	gtk_tree_model_get (model, &iter, FS_PTR, &node, -1);

		debug1 (DEBUG_GUI, "feed list selection changed to \"%s\"", node_get_title (node));

		/* 1.) update feed list and item list states */
		g_signal_emit_by_name (FEED_LIST_VIEW (flv), "selection-changed", node->id);

		/* 2.) Refilter the GtkTreeView to get rid of nodes with 0 unread
		   messages when in reduced mode. */
		gtk_tree_model_filter_refilter (GTK_TREE_MODEL_FILTER (flv->filter));

		if (node) {
			gboolean allowModify = (NODE_SOURCE_TYPE (node->source->root)->capabilities & NODE_SOURCE_CAPABILITY_WRITABLE_FEEDLIST);
			liferea_shell_update_update_menu ((NODE_TYPE (node)->capabilities & NODE_CAPABILITY_UPDATE) ||
			                                  (NODE_TYPE (node)->capabilities & NODE_CAPABILITY_UPDATE_CHILDS));
			liferea_shell_update_feed_menu (allowModify, TRUE, allowModify);
		} else {
			liferea_shell_update_feed_menu (TRUE, FALSE, FALSE);
		}
	} else {
		/* If we cannot get the new selection we keep the old one
		   this happens when we're doing drag&drop for example. */
	}
}
예제 #8
0
/* 
 * Find a node by the name under root or create it.
 */
static nodePtr
theoldreader_source_find_or_create_folder (const gchar *name, nodePtr root)
{
	nodePtr		folder = NULL;
	GSList		*iter_parent;

	/* find a node by the name under root */
	iter_parent = root->children;
	while (iter_parent) {
		if (g_str_equal (name, node_get_title (iter_parent->data))) {
			folder = (nodePtr)iter_parent->data;
			break;
		}
		iter_parent = g_slist_next (iter_parent);
	}
	
	/* if not found, create new folder */
	if (!folder) {
		folder = node_new (folder_get_node_type ());
		node_set_title (folder, name);
		node_set_parent (folder, root, -1);
		feedlist_node_imported (folder);
		subscription_update (folder->subscription, FEED_REQ_RESET_TITLE | FEED_REQ_PRIORITY_HIGH);
	}
	
	return folder;
}
예제 #9
0
void
feed_list_node_remove (nodePtr node)
{
	GtkWidget	*dialog;
	GtkWindow	*mainwindow;
	gchar		*text;
	
	g_assert (node == feedlist_get_selected ());

	liferea_shell_set_status_bar ("%s \"%s\"", _("Deleting entry"), node_get_title (node));
	text = g_strdup_printf (IS_FOLDER (node)?_("Are you sure that you want to delete \"%s\" and its contents?"):_("Are you sure that you want to delete \"%s\"?"), node_get_title (node));

	mainwindow = GTK_WINDOW (liferea_shell_get_window ());
	dialog = gtk_message_dialog_new (mainwindow,
	                                 GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
	                                 GTK_MESSAGE_QUESTION,
	                                 GTK_BUTTONS_NONE,
	                                 "%s", text);
	gtk_dialog_add_buttons (GTK_DIALOG (dialog),
	                        "_Cancel", GTK_RESPONSE_CANCEL,
	                        "_Delete", GTK_RESPONSE_ACCEPT,
	                        NULL);
	gtk_window_set_title (GTK_WINDOW (dialog), _("Deletion Confirmation"));
	gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
	gtk_window_set_transient_for (GTK_WINDOW (dialog), mainwindow);

	g_free (text);
	
	gtk_widget_show_all (dialog);

	g_signal_connect (G_OBJECT (dialog), "response",
	                  G_CALLBACK (feed_list_node_remove_cb), node);
}
예제 #10
0
/** Use to create new search folders and to edit existing ones */
SearchFolderDialog *
search_folder_dialog_new (nodePtr node) 
{
	GtkWidget		*dialog;
	SearchFolderDialog	*sfd;
	
	sfd = SEARCH_FOLDER_DIALOG (g_object_new (SEARCH_FOLDER_DIALOG_TYPE, NULL));
	sfd->priv->node = node;
	sfd->priv->vfolder = (vfolderPtr)node->data;
	sfd->priv->re = rule_editor_new (sfd->priv->vfolder->itemset);
	
	/* Create the dialog */
	dialog = liferea_dialog_new (NULL, "vfolderdialog");
	
	/* Setup search folder name */
	sfd->priv->nameEntry = liferea_dialog_lookup (dialog, "searchNameEntry");
	gtk_entry_set_text (GTK_ENTRY (sfd->priv->nameEntry), node_get_title (node));
	
	/* Set up rule match type */
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (liferea_dialog_lookup (dialog, sfd->priv->vfolder->itemset->anyMatch?"anyRuleRadioBtn":"allRuleRadioBtn")), TRUE);
	
	/* Set up rule list vbox */
	gtk_container_add (GTK_CONTAINER (liferea_dialog_lookup (dialog, "ruleview_vfolder_dialog")), rule_editor_get_widget (sfd->priv->re));

	/* bind buttons */
	g_signal_connect (liferea_dialog_lookup (dialog, "addrulebtn"), "clicked", G_CALLBACK (on_addrulebtn_clicked), sfd);
	g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (on_propdialog_response), sfd);
	
	return sfd;
}
예제 #11
0
파일: node.c 프로젝트: lwindolf/liferea
void
node_reparent (nodePtr node, nodePtr new_parent)
{
	nodePtr old_parent;

	g_assert (NULL != new_parent);
	g_assert (NULL != node);

	debug2 (DEBUG_GUI, "Reparenting node '%s' to a parent '%s'", node_get_title(node), node_get_title(new_parent));

	old_parent = node->parent;
	if (NULL != old_parent)
		old_parent->children = g_slist_remove (old_parent->children, node);

	new_parent->children = g_slist_insert (new_parent->children, node, -1);
	node->parent = new_parent;

	feed_list_view_remove_node (node);
	feed_list_view_add_node (node);
}
예제 #12
0
static void ui_update_merge_request(nodePtr node, GtkTreeStore *store, GHashTable *hash) {
	GtkTreeIter	*iter;

	if(NULL != (iter = (GtkTreeIter *)g_hash_table_lookup(hash, (gpointer)node->id)))
		return;

	iter = g_new0(GtkTreeIter, 1);
	gtk_tree_store_append(store, iter, NULL);
	gtk_tree_store_set(store, iter, UM_REQUEST_TITLE, node_get_title(node), 
	                                UM_FAVICON, node_get_icon(node),
	                                -1);
	g_hash_table_insert(hash, (gpointer)node->id, (gpointer)iter);
}
예제 #13
0
void
feed_list_view_rename_node (nodePtr node)
{
	GtkWidget	*nameentry, *dialog;

	dialog = liferea_dialog_new ("rename_node");

	nameentry = liferea_dialog_lookup (dialog, "nameentry");
	gtk_entry_set_text (GTK_ENTRY (nameentry), node_get_title (node));
	g_signal_connect (G_OBJECT (dialog), "response",
	                  G_CALLBACK (on_nodenamedialog_response), node);
	gtk_widget_show (dialog);
}
예제 #14
0
static void
google_source_check_for_removal (nodePtr node, gpointer user_data)
{
	gchar		*expr = NULL;

	if (g_str_equal (node->subscription->source, GOOGLE_READER_BROADCAST_FRIENDS_URL)) 
		return ; 

	if (IS_FEED (node)) {
		expr = g_strdup_printf ("/object/list[@name='subscriptions']/object/string[@name='id'][. = 'feed/%s']", node->subscription->source);
	} else {
		g_warning ("opml_source_check_for_removal(): This should never happen...");
		return;
	}
	
	if (!xpath_find ((xmlNodePtr)user_data, expr)) {
		debug1 (DEBUG_UPDATE, "removing %s...", node_get_title (node));
		feedlist_node_removed (node);
	} else {
		debug1 (DEBUG_UPDATE, "keeping %s...", node_get_title (node));
	}
	g_free (expr);
}
예제 #15
0
static void
theoldreader_source_check_for_removal (nodePtr node, gpointer user_data)
{
	gchar	*expr = NULL;

	if (IS_FEED (node)) {
		expr = g_strdup_printf ("/object/list[@name='subscriptions']/object/string[@name='id'][. = 'feed/%s']", node->subscription->source);
	} else if (IS_FOLDER (node)) {
		node_foreach_child_data (node, theoldreader_source_check_for_removal, user_data);
		expr = g_strdup_printf ("/object/list[@name='subscriptions']/object/list[@name='categories']/object[string='%s']", node->title);
	} else {
		g_warning ("theoldreader_source_check_for_removal(): This should never happen...");
		return;
	}
	
	if (!xpath_find ((xmlNodePtr)user_data, expr)) {
		debug1 (DEBUG_UPDATE, "removing %s...", node_get_title (node));
		feedlist_node_removed (node);
	} else {
		debug1 (DEBUG_UPDATE, "keeping %s...", node_get_title (node));
	}
	g_free (expr);
}
예제 #16
0
void
feed_list_node_rename (nodePtr node)
{
	GtkWidget	*nameentry;
	
	if (!nodenamedialog || !G_IS_OBJECT (nodenamedialog))
		nodenamedialog = liferea_dialog_new (NULL, "nodenamedialog");

	nameentry = liferea_dialog_lookup (nodenamedialog, "nameentry");
	gtk_entry_set_text (GTK_ENTRY (nameentry), node_get_title (node));
	g_signal_connect (G_OBJECT (nodenamedialog), "response", 
	                  G_CALLBACK (on_nodenamedialog_response), node);
	gtk_widget_show (nodenamedialog);
}
예제 #17
0
파일: vfolder.c 프로젝트: dmitryvk/liferea
static void
vfolder_import (nodePtr node,
                nodePtr parent,
                xmlNodePtr cur,
                gboolean trusted) 
{
	vfolderPtr vfolder;

	debug1 (DEBUG_CACHE, "import vfolder: title=%s", node_get_title (node));

	vfolder = vfolder_new (node);
	vfolder->itemset = db_search_folder_load (node->id);
	
	vfolder_import_rules (cur, vfolder);
}
예제 #18
0
파일: vfolder.c 프로젝트: dmitryvk/liferea
static void
vfolder_import_rules (xmlNodePtr cur,
                      vfolderPtr vfolder)
{
	xmlChar		*matchType, *type, *ruleId, *value, *additive;
	
	matchType = xmlGetProp (cur, BAD_CAST"matchType");
	if (matchType) {
		/* currently we only OR or AND the rules,
		   "any" is the value for OR'ing, "all" for AND'ing */
		vfolder->itemset->anyMatch = (0 != xmlStrcmp (matchType, BAD_CAST"all"));
	} else {
		vfolder->itemset->anyMatch = TRUE;
	}
	xmlFree (matchType);

	/* process any children */
	cur = cur->xmlChildrenNode;
	while (cur) {
		if (!xmlStrcmp (cur->name, BAD_CAST"outline")) {
			type = xmlGetProp (cur, BAD_CAST"type");
			if (type && !xmlStrcmp (type, BAD_CAST"rule")) {

				ruleId = xmlGetProp (cur, BAD_CAST"rule");
				value = xmlGetProp (cur, BAD_CAST"value");
				additive = xmlGetProp (cur, BAD_CAST"additive");

				if (ruleId && value) {			
					debug2 (DEBUG_CACHE, "loading rule \"%s\" \"%s\"", ruleId, value);

					if (additive && !xmlStrcmp (additive, BAD_CAST"true"))
						itemset_add_rule (vfolder->itemset, ruleId, value, TRUE);
					else
						itemset_add_rule (vfolder->itemset, ruleId, value, FALSE);
				} else {
					g_warning ("ignoring invalid rule entry for vfolder \"%s\"...\n", node_get_title (vfolder->node));
				}
				
				xmlFree (ruleId);
				xmlFree (value);
				xmlFree (additive);
			}
			xmlFree (type);
		}
		cur = cur->next;
	}
}
예제 #19
0
static void
auth_dialog_load (AuthDialog *ad,
                     subscriptionPtr subscription,
                     gint flags)
{
	AuthDialogPrivate	*ui_data = ad->priv;
	gchar			*promptStr;
	gchar			*source = NULL;
	xmlURIPtr		uri;
	
	subscription->activeAuth = TRUE;
	
	ui_data->subscription = subscription;
	ui_data->flags = flags;
	
	ui_data->username = liferea_dialog_lookup (ui_data->dialog, "usernameEntry");
	ui_data->password = liferea_dialog_lookup (ui_data->dialog, "passwordEntry");
	
	uri = xmlParseURI (BAD_CAST subscription_get_source (ui_data->subscription));
	
	if (uri) {
		if (uri->user) {
			gchar *user = uri->user;
			gchar *pass = strstr (user, ":");
			if(pass) {
				pass[0] = '\0';
				pass++;
				gtk_entry_set_text (GTK_ENTRY (ui_data->password), pass);
			}
			gtk_entry_set_text (GTK_ENTRY (ui_data->username), user);
			xmlFree (uri->user);
			uri->user = NULL;
		}
		xmlFree (uri->user);
		uri->user = NULL;
		source = xmlSaveUri (uri);
		xmlFreeURI (uri);
	}
	
	promptStr = g_strdup_printf ( _("Enter the username and password for \"%s\" (%s):"),
	                             node_get_title (ui_data->subscription->node), source?source:_("Unknown source"));
	gtk_label_set_text (GTK_LABEL (liferea_dialog_lookup (ui_data->dialog, "prompt")), promptStr);
	g_free (promptStr);
	if (source)
		xmlFree (source);
}
예제 #20
0
/**
 * To be called whenever an itemset was updated. If it is the
 * displayed itemset it will be merged against the item list
 * tree view.
 */
void
itemlist_merge_itemset (itemSetPtr itemSet) 
{
	gint	folder_display_mode;

	debug_enter ("itemlist_merge_itemset");
	
	debug_start_measurement (DEBUG_GUI);
	
	/* No node check when loading search results directly */
	if (!itemlist_priv.isSearchResult) {
		nodePtr node = node_from_id (itemSet->nodeId);

		if (!itemlist_priv.currentNode)
			return; /* Nothing to do if nothing is displayed */
		
		if (!IS_VFOLDER (itemlist_priv.currentNode) &&
		    (itemlist_priv.currentNode != node) && 
		    !node_is_ancestor (itemlist_priv.currentNode, node))
			return; /* Nothing to do if the item set does not belong to this node, or this is a search folder */

		conf_get_int_value (FOLDER_DISPLAY_MODE, &folder_display_mode);
		if (IS_FOLDER (itemlist_priv.currentNode) && !folder_display_mode)
			return; /* Bail out if it is a folder without the recursive display preference set */
			
		debug1 (DEBUG_GUI, "reloading item list with node \"%s\"", node_get_title (node));
	} else {
		/* If we are loading a search result we must never merge 
		   anything besides the search items. In fact if we already
		   have items we just return. */
		if (itemlist_priv.searchResultComplete)
			return;
			
		itemlist_priv.searchResultComplete = TRUE;
	}

	/* merge items into item view */
	itemset_foreach (itemSet, itemlist_merge_item);
	
	itemview_update ();
	
	debug_end_measurement (DEBUG_GUI, "itemlist merge");

	debug_exit ("itemlist_merge_itemset");
}
예제 #21
0
/* Checks whether updating a feed makes sense. */
static gboolean
subscription_can_be_updated (subscriptionPtr subscription)
{
	if (subscription->updateJob) {
		liferea_shell_set_status_bar (_("Subscription \"%s\" is already being updated!"), node_get_title (subscription->node));
		return FALSE;
	}
	
	if (subscription->discontinued) {
		liferea_shell_set_status_bar (_("The subscription \"%s\" was discontinued. Liferea won't update it anymore!"), node_get_title (subscription->node));
		return FALSE;
	}

	if (!subscription_get_source (subscription)) {
		g_warning ("Feed source is NULL! This should never happen - cannot update!");
		return FALSE;
	}
	return TRUE;
}	
예제 #22
0
void
on_action_mark_all_read (GSimpleAction *action, GVariant *parameter, gpointer user_data)
{
	nodePtr 	feedlist;
	gboolean 	confirm_mark_read;
	gboolean 	do_mark_read = TRUE;

	if (!g_strcmp0 (g_action_get_name (G_ACTION (action)), "mark-all-feeds-read"))
		feedlist = feedlist_get_root ();
	else if (user_data)
		feedlist = (nodePtr) user_data;
	else
		feedlist = feedlist_get_selected ();

	conf_get_bool_value (CONFIRM_MARK_ALL_READ, &confirm_mark_read);

	if (confirm_mark_read) {
		gint result;
		GtkMessageDialog *confirm_dialog = GTK_MESSAGE_DIALOG (liferea_dialog_new ("mark_read_dialog"));
		GtkWidget *dont_ask_toggle = liferea_dialog_lookup (GTK_WIDGET (confirm_dialog), "dontAskAgainToggle");
		const gchar *feed_title = (feedlist_get_root () == feedlist) ? _("all feeds"):node_get_title (feedlist);
		gchar *primary_message = g_strdup_printf (_("Mark %s as read ?"), feed_title);

		g_object_set (confirm_dialog, "text", primary_message, NULL);
		g_free (primary_message);
		gtk_message_dialog_format_secondary_text (confirm_dialog, _("Are you sure you want to mark all items in %s as read ?"), feed_title);

		conf_bind (CONFIRM_MARK_ALL_READ, dont_ask_toggle, "active", G_SETTINGS_BIND_DEFAULT | G_SETTINGS_BIND_INVERT_BOOLEAN);

		result = gtk_dialog_run (GTK_DIALOG (confirm_dialog));
		if (result != GTK_RESPONSE_OK)
			do_mark_read = FALSE;
		gtk_widget_destroy (GTK_WIDGET (confirm_dialog));
	}

	if (do_mark_read)
		feedlist_mark_all_read (feedlist);
}
예제 #23
0
파일: node.c 프로젝트: lwindolf/liferea
static xmlDocPtr
node_to_xml (nodePtr node)
{
	xmlDocPtr	doc;
	xmlNodePtr	rootNode;
	gchar		*tmp;

	doc = xmlNewDoc("1.0");
	rootNode = xmlNewDocNode(doc, NULL, "node", NULL);
	xmlDocSetRootElement(doc, rootNode);

	xmlNewTextChild(rootNode, NULL, "title", node_get_title(node));

	tmp = g_strdup_printf("%u", node->unreadCount);
	xmlNewTextChild(rootNode, NULL, "unreadCount", tmp);
	g_free(tmp);

	tmp = g_strdup_printf("%u", g_slist_length(node->children));
	xmlNewTextChild(rootNode, NULL, "children", tmp);
	g_free(tmp);

	return doc;
}
예제 #24
0
void
feed_list_node_add (nodePtr node)
{
	gint		position;
	GtkTreeIter	*iter, *parentIter = NULL;

	debug2 (DEBUG_GUI, "adding node \"%s\" as child of parent=\"%s\"", node_get_title(node), (NULL != node->parent)?node_get_title(node->parent):"feed list root");

	g_assert (NULL != node->parent);
	g_assert (NULL == feed_list_node_to_iter (node->id));

	/* if parent is NULL we have the root folder and don't create a new row! */
	iter = (GtkTreeIter *)g_new0 (GtkTreeIter, 1);
	
	/* if reduced feedlist, show flat treeview */
	if (feedlist_reduced_unread)
		parentIter = NULL;
	else if (node->parent != feedlist_get_root ())
		parentIter = feed_list_node_to_iter (node->parent->id);

	position = g_slist_index (node->parent->children, node);

	if (feedlist_reduced_unread || position < 0)
		gtk_tree_store_append (feedstore, iter, parentIter);
	else
		gtk_tree_store_insert (feedstore, iter, parentIter, position);

	gtk_tree_store_set (feedstore, iter, FS_PTR, node, -1);
	feed_list_node_add_iter (node->id, iter);
	feed_list_node_update (node->id);
	
	if (node->parent != feedlist_get_root ())
		feed_list_node_check_if_folder_is_empty (node->parent->id);

	if (IS_FOLDER (node))
		feed_list_node_check_if_folder_is_empty (node->id);
}
예제 #25
0
파일: itemlist.c 프로젝트: skagedal/liferea
/* Helper method checking if the passed item set is relevant
   for the currently item list content. */
static gboolean
itemlist_itemset_is_valid (itemSetPtr itemSet)
{
	gint	folder_display_mode;
	nodePtr node;

	node = node_from_id (itemSet->nodeId);

	if (!itemlist->priv->currentNode)
		return FALSE; /* Nothing to do if nothing is displayed */
		
	if (!IS_VFOLDER (itemlist->priv->currentNode) &&
	    (itemlist->priv->currentNode != node) && 
	    !node_is_ancestor (itemlist->priv->currentNode, node))
		return FALSE; /* Nothing to do if the item set does not belong to this node, or this is a search folder */

	conf_get_int_value (FOLDER_DISPLAY_MODE, &folder_display_mode);
	if (IS_FOLDER (itemlist->priv->currentNode) && !folder_display_mode)
		return FALSE; /* Bail out if it is a folder without the recursive display preference set */
		
	debug1 (DEBUG_GUI, "reloading item list with node \"%s\"", node_get_title (node));

	return TRUE;
}
예제 #26
0
파일: vfolder.c 프로젝트: dmitryvk/liferea
static void
vfolder_export (nodePtr node,
                xmlNodePtr cur,
                gboolean trusted)
{
	vfolderPtr	vfolder = (vfolderPtr) node->data;
	xmlNodePtr	ruleNode;
	rulePtr		rule;
	GSList		*iter;

	debug_enter ("vfolder_export");
	
	g_assert (TRUE == trusted);
	
	xmlNewProp (cur, BAD_CAST"matchType", BAD_CAST (vfolder->itemset->anyMatch?"any":"all"));

	iter = vfolder->itemset->rules;
	while (iter) {
		rule = iter->data;
		ruleNode = xmlNewChild (cur, NULL, BAD_CAST"outline", NULL);
		xmlNewProp (ruleNode, BAD_CAST"type", BAD_CAST "rule");
		xmlNewProp (ruleNode, BAD_CAST"text", BAD_CAST rule->ruleInfo->title);
		xmlNewProp (ruleNode, BAD_CAST"rule", BAD_CAST rule->ruleInfo->ruleId);
		xmlNewProp (ruleNode, BAD_CAST"value", BAD_CAST rule->value);
		if (rule->additive)
			xmlNewProp (ruleNode, BAD_CAST"additive", BAD_CAST "true");
		else
			xmlNewProp (ruleNode, BAD_CAST"additive", BAD_CAST "false");

		iter = g_slist_next (iter);
	}
	
	debug1 (DEBUG_CACHE, "adding vfolder: title=%s", node_get_title (node));

	debug_exit ("vfolder_export");
}
예제 #27
0
static void
subscription_prop_dialog_load (SubscriptionPropDialog *spd, 
                               subscriptionPtr subscription) 
{
	gint 		interval;
	gint		default_update_interval;
	gint		defaultInterval, spinSetInterval;
	gchar 		*defaultIntervalStr;
	nodePtr		node = subscription->node;
	feedPtr		feed = (feedPtr)node->data;

	spd->priv->subscription = subscription;

	/* General */
	gtk_entry_set_text(GTK_ENTRY(spd->priv->feedNameEntry), node_get_title(node));

	spd->priv->refreshInterval = liferea_dialog_lookup(spd->priv->dialog,"refreshIntervalSpinButton");
	
	interval = subscription_get_update_interval(subscription);
	defaultInterval = subscription_get_default_update_interval(subscription);
	conf_get_int_value (DEFAULT_UPDATE_INTERVAL, &default_update_interval);
	spinSetInterval = defaultInterval > 0 ? defaultInterval : default_update_interval;
	
	if (-2 >= interval) {
		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (liferea_dialog_lookup(spd->priv->dialog, "updateIntervalNever")), TRUE);
	} else if (-1 == interval) {
		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (liferea_dialog_lookup(spd->priv->dialog, "updateIntervalDefault")), TRUE);
	} else {
		gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (liferea_dialog_lookup(spd->priv->dialog, "updateIntervalSpecific")), TRUE);
		spinSetInterval = interval;
	}
	
	/* Set refresh interval spin button and combo box */
	if (spinSetInterval % 1440 == 0) {	/* days */
		gtk_combo_box_set_active (GTK_COMBO_BOX (spd->priv->refreshIntervalUnit), 2);
		spinSetInterval /= 1440;
	} else if (spinSetInterval % 60 == 0) {	/* hours */
		gtk_combo_box_set_active (GTK_COMBO_BOX (spd->priv->refreshIntervalUnit), 1);
		spinSetInterval /= 60;
	} else {
		gtk_combo_box_set_active (GTK_COMBO_BOX (spd->priv->refreshIntervalUnit), 0);
	}
	gtk_spin_button_set_value (GTK_SPIN_BUTTON (spd->priv->refreshInterval), spinSetInterval);

	gtk_widget_set_sensitive (spd->priv->refreshInterval, interval > 0);
	gtk_widget_set_sensitive (spd->priv->refreshIntervalUnit, interval > 0);
	
	/* setup info label about default update interval */
	if(-1 != defaultInterval)
		defaultIntervalStr = g_strdup_printf(ngettext("The provider of this feed suggests an update interval of %d minute.", 
		                                              "The provider of this feed suggests an update interval of %d minutes.",
		                                              defaultInterval), defaultInterval);
	else
		defaultIntervalStr = g_strdup(_("This feed specifies no default update interval."));

	gtk_label_set_text(GTK_LABEL(liferea_dialog_lookup(spd->priv->dialog, "feedUpdateInfo")), defaultIntervalStr);
	g_free(defaultIntervalStr);

	/* Source (only for feeds) */
	if (SUBSCRIPTION_TYPE(subscription) == feed_get_subscription_type ()) {
		if(subscription_get_source(subscription)[0] == '|') {
			gtk_entry_set_text(GTK_ENTRY(spd->priv->sourceEntry), &(subscription_get_source(subscription)[1]));
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(spd->priv->cmdRadio), TRUE);
			ui_subscription_prop_enable_httpauth(spd->priv, FALSE);
			gtk_widget_set_sensitive(spd->priv->selectFile, TRUE);
		} else if(strstr(subscription_get_source(subscription), "://") != NULL) {
			xmlURIPtr uri = xmlParseURI(BAD_CAST subscription_get_source(subscription));
			xmlChar *parsedUrl;
			if(uri) {
				if(uri->user) {
					gchar *user = uri->user;
					gchar *pass = strstr(user, ":");
					if(pass) {
						pass[0] = '\0';
						pass++;
						gtk_entry_set_text(GTK_ENTRY(spd->priv->password), pass);
					}
					gtk_entry_set_text(GTK_ENTRY(spd->priv->username), user);
					xmlFree(uri->user);
					uri->user = NULL;
					gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(spd->priv->authcheckbox), TRUE);
				}
				parsedUrl = xmlSaveUri(uri);
				gtk_entry_set_text(GTK_ENTRY(spd->priv->sourceEntry), parsedUrl);
				xmlFree(parsedUrl);
				xmlFreeURI(uri);
			} else {
				gtk_entry_set_text(GTK_ENTRY(spd->priv->sourceEntry), subscription_get_source(subscription));
			}
			ui_subscription_prop_enable_httpauth(spd->priv, TRUE);
			gtk_widget_set_sensitive(spd->priv->selectFile, FALSE);
		} else {
			/* File */
			gtk_entry_set_text(GTK_ENTRY(spd->priv->sourceEntry), subscription_get_source(subscription));
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(spd->priv->fileRadio), TRUE);
			ui_subscription_prop_enable_httpauth(spd->priv, FALSE);
			gtk_widget_set_sensitive(spd->priv->selectFile, TRUE);
		}

		if(subscription_get_filter(subscription)) {
			gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(liferea_dialog_lookup(spd->priv->dialog, "filterCheckbox")), TRUE);
			gtk_entry_set_text(GTK_ENTRY(liferea_dialog_lookup(spd->priv->dialog, "filterEntry")), subscription_get_filter(subscription));
		}
	}

	/* Archive */
	if(feed->cacheLimit == CACHE_DISABLE) {
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(liferea_dialog_lookup(spd->priv->dialog, "feedCacheDisable")), TRUE);
	} else if(feed->cacheLimit == CACHE_DEFAULT) {
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(liferea_dialog_lookup(spd->priv->dialog, "feedCacheDefault")), TRUE);
	} else if(feed->cacheLimit == CACHE_UNLIMITED) {
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(liferea_dialog_lookup(spd->priv->dialog, "feedCacheUnlimited")), TRUE);
	} else {
		gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(liferea_dialog_lookup(spd->priv->dialog, "feedCacheLimited")), TRUE);
		gtk_spin_button_set_value(GTK_SPIN_BUTTON(liferea_dialog_lookup(spd->priv->dialog, "cacheItemLimit")), feed->cacheLimit);
	}

	gtk_widget_set_sensitive(liferea_dialog_lookup(spd->priv->dialog, "cacheItemLimit"), feed->cacheLimit > 0);

	on_feed_prop_filtercheck(GTK_TOGGLE_BUTTON(liferea_dialog_lookup(spd->priv->dialog, "filterCheckbox")), spd->priv);
	
	/* Download */
	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(liferea_dialog_lookup(spd->priv->dialog, "dontUseProxyCheck")), subscription->updateOptions->dontUseProxy);

	/* Advanced */	
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (liferea_dialog_lookup (spd->priv->dialog, "enclosureDownloadCheck")), feed->encAutoDownload);
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (liferea_dialog_lookup (spd->priv->dialog, "loadItemLinkCheck")), node->loadItemLink);
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (liferea_dialog_lookup (spd->priv->dialog, "ignoreCommentFeeds")), feed->ignoreComments);
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (liferea_dialog_lookup (spd->priv->dialog, "enforcePopupCheck")), feed->enforcePopup);
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (liferea_dialog_lookup (spd->priv->dialog, "preventPopupCheck")), feed->preventPopup);
	gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (liferea_dialog_lookup (spd->priv->dialog, "markAsReadCheck")), feed->markAsRead);

	/* Remove tabs we do not need... */
	if (SUBSCRIPTION_TYPE(subscription) != feed_get_subscription_type ()) {
		/* Remove "Allgemein", "Source" and "Download" tab */
		gtk_notebook_remove_page (GTK_NOTEBOOK (liferea_dialog_lookup (spd->priv->dialog, "subscriptionPropNotebook")), 0);
		gtk_notebook_remove_page (GTK_NOTEBOOK (liferea_dialog_lookup (spd->priv->dialog, "subscriptionPropNotebook")), 0);
		gtk_notebook_remove_page (GTK_NOTEBOOK (liferea_dialog_lookup (spd->priv->dialog, "subscriptionPropNotebook")), 1);
	}
}
예제 #28
0
void
feed_list_node_update (const gchar *nodeId)
{
	GtkTreeIter	*iter;
	gchar		*label, *count = NULL;
	guint		labeltype;
	nodePtr		node;

	static gchar	*countColor = NULL;

	node = node_from_id (nodeId);
	iter = feed_list_node_to_iter (nodeId);
	if (!iter)
		return;

	/* Initialize unread item color Pango CSS */
	if (!countColor) {
		const gchar *bg = NULL, *fg = NULL;

		bg = render_get_theme_color ("FEEDLIST_UNREAD_BG");
		fg = render_get_theme_color ("FEEDLIST_UNREAD_FG");
		if (fg && bg) {
			countColor = g_strdup_printf ("foreground='#%s' background='#%s'", fg, bg);
			debug1 (DEBUG_HTML, "Feed list unread CSS: %s\n", countColor);
		}
	}

	labeltype = NODE_TYPE (node)->capabilities;
	labeltype &= (NODE_CAPABILITY_SHOW_UNREAD_COUNT |
        	      NODE_CAPABILITY_SHOW_ITEM_COUNT);

	if (node->unreadCount == 0 && (labeltype & NODE_CAPABILITY_SHOW_UNREAD_COUNT))
		labeltype -= NODE_CAPABILITY_SHOW_UNREAD_COUNT;

	label = g_markup_escape_text (node_get_title (node), -1);
	switch (labeltype) {
		case NODE_CAPABILITY_SHOW_UNREAD_COUNT |
		     NODE_CAPABILITY_SHOW_ITEM_COUNT:
	     		/* treat like show unread count */
		case NODE_CAPABILITY_SHOW_UNREAD_COUNT:
			count = g_strdup_printf ("<span weight='bold' %s> %u </span>", countColor?countColor:"", node->unreadCount);
			break;
		case NODE_CAPABILITY_SHOW_ITEM_COUNT:
			count = g_strdup_printf ("<span weight='bold' %s> %u </span>", countColor?countColor:"", node->itemCount);
		     	break;
		default:
			break;
	}

	/* Extra message for search folder rebuilds */
	if (IS_VFOLDER (node) && node->data) {
		if (((vfolderPtr)node->data)->reloading) {
			gchar *tmp = label;
			label = g_strdup_printf (_("%s\n<i>Rebuilding</i>"), label);
			g_free (tmp);
		}
	}

	gtk_tree_store_set (feedstore, iter,
	                    FS_LABEL, label,
	                    FS_UNREAD, node->unreadCount,
	                    FS_ICON, node->available?node_get_icon (node):icon_get (ICON_UNAVAILABLE),
	                    FS_COUNT, count,
	                    -1);
	g_free (label);

	if (node->parent)
		feed_list_node_update (node->parent->id);
}
예제 #29
0
static void
notif_libnotify_node_has_new_items (nodePtr node, gboolean enforced)
{
	itemSetPtr	itemSet;
	GList		*iter;

	NotifyNotification *n;

	gchar		*labelSummary_p;
	gint		item_count = 0;

	gboolean	show_popup_windows;

	conf_get_bool_value(SHOW_POPUP_WINDOWS, &show_popup_windows);

	if (!show_popup_windows && !enforced)
		return;

	/* Count updated feed */
	itemSet = node_get_itemset (node);
	iter = itemSet->ids;
	while (iter) {
		itemPtr item = item_load (GPOINTER_TO_UINT (iter->data));
		if (item->popupStatus && !item->readStatus)
			item_count++;
		item_unload (item);
		iter = g_list_next (iter);
	}
	itemset_free (itemSet);

	if (item_count == 0)
		return;

	labelSummary_p = g_strdup_printf (ngettext ("<b>%s</b> has <b>%d</b> update", "<b>%s</b> has <b>%d</b> updates", item_count), 
	                                  node_get_title (node), item_count);
	n = notify_notification_new (_("Feed Update"), labelSummary_p, "liferea", NULL);
	g_free (labelSummary_p);

 	if (supports_append) {
 		notify_notification_set_hint_string(n, "append", "allow");
 	} else {
		notify_notification_set_icon_from_pixbuf (n, node_get_icon (node));
	}
	
	notify_notification_set_timeout (n, NOTIFY_EXPIRES_DEFAULT);
	if (supports_actions) {
		notify_notification_add_action (n, "show_details", _("Show details"),
	                                (NotifyActionCallback)notif_libnotify_callback_show_details,
	                                node->id, NULL);
		notify_notification_add_action (n, "open", _("Open feed"),
	                                (NotifyActionCallback)notif_libnotify_callback_open,
	                                node->id, NULL);
		notify_notification_add_action (n, "mark_read", _("Mark all as read"),
	                                (NotifyActionCallback)notif_libnotify_callback_mark_read,
	                                node->id, NULL);
	}
	notify_notification_set_category (n, "feed");

	notify_notification_attach_to_status_icon (n, ui_tray_get_status_icon ());

	if (!notify_notification_show (n, NULL))
		g_warning ("notif_libnotify.c - failed to send notification via libnotify");
}
예제 #30
0
static void
notif_libnotify_callback_show_details (NotifyNotification *n, gchar *action, gpointer user_data)
{
	nodePtr node_p;

	GList *list_p;
	itemPtr item_p;

	gchar *labelText_p;
	gchar *labelText_now_p = NULL;
	gchar *labelText_prev_p;

	gchar *labelHeadline_p;
	const gchar *labelURL_p;

	gint item_count = 0;

	g_assert (action != NULL);
	g_assert (strcmp(action, "show_details") == 0);
	node_p = node_from_id (user_data);

	if (node_p) {
		itemSetPtr itemSet = node_get_itemset (node_p);

		labelText_now_p = g_strdup ("");

		/* Gather the feed's headlines */
		list_p = itemSet->ids;
		while (list_p) {
			item_p = item_load (GPOINTER_TO_UINT (list_p->data));
			if (item_p->popupStatus && !item_p->readStatus) {
				item_p->popupStatus = FALSE;
				item_count += 1;

				labelHeadline_p = g_strdup (item_get_title (item_p));
				if (labelHeadline_p == NULL ) {
					labelHeadline_p = g_strdup_printf (_("This news entry has no headline"));
				}

				labelURL_p = item_get_base_url (item_p);
				if (labelURL_p) {
					labelText_p = g_strdup_printf ("%s <a href='%s'>%s</a>\n", labelHeadline_p, labelURL_p, _("Visit"));
				} else {
					labelText_p = g_strdup_printf ("%s\n", labelHeadline_p);
				}

				labelText_prev_p = labelText_now_p;
				labelText_now_p = g_strconcat(labelText_now_p, labelText_p, NULL);

				g_free(labelHeadline_p);
				g_free(labelText_p);
				g_free(labelText_prev_p);
			}
			item_unload (item_p);
			list_p = g_list_next (list_p);
		}
		itemset_free (itemSet);

		if (item_count == 0) {
			g_free (labelText_now_p);
			return;
		}
	} else {
		ui_show_error_box(_("This feed does not exist anymore!"));
	}

	notify_notification_close (n, NULL);

	if (node_p) {
//		notify_notification_update ( n, node_get_title(node_p), labelText_now_p, NULL);
//		notify_notification_clear_actions(n);

		n = notify_notification_new (node_get_title (node_p), labelText_now_p, NULL, NULL);

		notify_notification_set_icon_from_pixbuf (n, node_get_icon (node_p));
		notify_notification_set_category (n, "feed");
		notify_notification_set_timeout (n, NOTIFY_EXPIRES_NEVER);

		if (supports_actions) {
			notify_notification_add_action (n, "open", _("Open feed"),
							(NotifyActionCallback)notif_libnotify_callback_open,
							node_p->id, NULL);
			notify_notification_add_action (n, "mark_read", _("Mark all as read"),
							(NotifyActionCallback)notif_libnotify_callback_mark_read,
							node_p->id, NULL);
		}

		notify_notification_attach_to_status_icon (n, ui_tray_get_status_icon ());

		if (!notify_notification_show (n, NULL)) {
			g_warning ("libnotify.c - failed to update notification via libnotify\n");
		}

		g_free (labelText_now_p);
	}
}