Пример #1
0
/* opening or creation of database */
void
db_init (void)
{
	gint		res;
		
	debug_enter ("db_init");

	db_open ();

	/* create info table/check versioning info */				   
	debug1 (DEBUG_DB, "current DB schema version: %d", db_get_schema_version ());

	if (-1 == db_get_schema_version ()) {
		/* no schema version available -> first installation without tables... */
		db_set_schema_version (SCHEMA_TARGET_VERSION);
		/* nothing exists yet, tables will be created below */
	}

	if (SCHEMA_TARGET_VERSION < db_get_schema_version ())
		g_error ("Fatal: The cache database was created by a newer version of Liferea than this one!");

	if (SCHEMA_TARGET_VERSION > db_get_schema_version ()) {		
		/* do table migration */
		if (db_get_schema_version () < 5)
			g_error ("This version of Liferea doesn't support migrating from such an old DB file!");

		if (db_get_schema_version () == 5 || db_get_schema_version () == 6) {
			debug0 (DEBUG_DB, "dropping triggers in preparation of database migration");
			db_exec ("BEGIN; "
			         "DROP TRIGGER item_removal; "
				 "DROP TRIGGER item_insert; "
				 "END;");
		}

		if (db_get_schema_version () == 5) {
				/* 1.4.9 -> 1.4.10 adding parent_item_id to itemset relation */
			debug0 (DEBUG_DB, "migrating from schema version 5 to 6 (this drops all comments)");
			db_exec ("BEGIN; "
			         "DELETE FROM itemsets WHERE comment = 1; "
				 "DELETE FROM items WHERE comment = 1; "
			         "CREATE TEMPORARY TABLE itemsets_backup(item_id,node_id,read,comment); "
				 "INSERT INTO itemsets_backup SELECT item_id,node_id,read,comment FROM itemsets; "
				 "DROP TABLE itemsets; "
				 "CREATE TABLE itemsets ("
		        	 "   item_id		INTEGER,"
				 "   parent_item_id     INTEGER,"
		        	 "   node_id		TEXT,"
		        	 "   read		INTEGER,"
				 "   comment            INTEGER,"
		        	 "   PRIMARY KEY (item_id, node_id)"
		        	 "); "
				 "INSERT INTO itemsets SELECT item_id,0,node_id,read,comment FROM itemsets_backup; "
				 "DROP TABLE itemsets_backup; "
				 "REPLACE INTO info (name, value) VALUES ('schemaVersion',6); "
				 "END;");
		}

		if (db_get_schema_version () == 6) {
			/* 1.4.15 -> 1.4.16 adding parent_node_id to itemset relation */
			debug0 (DEBUG_DB, "migrating from schema version 6 to 7 (this drops all comments)");
			db_exec ("BEGIN; "
			         "DELETE FROM itemsets WHERE comment = 1; "
				 "DELETE FROM items WHERE comment = 1; "
			         "CREATE TEMPORARY TABLE itemsets_backup(item_id,node_id,read,comment); "
				 "INSERT INTO itemsets_backup SELECT item_id,node_id,read,comment FROM itemsets; "
				 "DROP TABLE itemsets; "
				 "CREATE TABLE itemsets ("
		        	 "   item_id		INTEGER,"
				 "   parent_item_id     INTEGER,"
		        	 "   node_id		TEXT,"
				 "   parent_node_id     TEXT,"
		        	 "   read		INTEGER,"
				 "   comment            INTEGER,"
		        	 "   PRIMARY KEY (item_id, node_id)"
		        	 "); "
				 "INSERT INTO itemsets SELECT item_id,0,node_id,node_id,read,comment FROM itemsets_backup; "
				 "DROP TABLE itemsets_backup; "
				 "REPLACE INTO info (name, value) VALUES ('schemaVersion',7); "
				 "END;");
		}
		
		if (db_get_schema_version () == 7) {
			/* 1.7.1 -> 1.7.2 dropping the itemsets and attention_stats relation */
			db_exec ("BEGIN; "
			         "CREATE TEMPORARY TABLE items_backup("
			         "   item_id, "
			         "   title, "
			         "   read, "
			         "   updated, "
			         "   popup, "
			         "   marked, "
			         "   source, "
			         "   source_id, "
			         "   valid_guid, "
			         "   description, "
			         "   date, "
			         "   comment_feed_id, "
			         "   comment); "
			         "INSERT into items_backup SELECT ROWID, title, read, updated, popup, marked, source, source_id, valid_guid, description, date, comment_feed_id, comment FROM items; "
			         "DROP TABLE items; "
		                 "CREATE TABLE items ("
		        	 "   item_id		INTEGER,"
				 "   parent_item_id     INTEGER,"
		        	 "   node_id		TEXT,"
				 "   parent_node_id     TEXT,"
		        	 "   title		TEXT,"
		        	 "   read		INTEGER,"
		        	 "   updated		INTEGER,"
		        	 "   popup		INTEGER,"
		        	 "   marked		INTEGER,"
		        	 "   source		TEXT,"
		        	 "   source_id		TEXT,"
		        	 "   valid_guid		INTEGER,"
		        	 "   description	TEXT,"
		        	 "   date		INTEGER,"
		        	 "   comment_feed_id	INTEGER,"
				 "   comment            INTEGER,"
				 "   PRIMARY KEY (item_id)"
		        	 ");"
			         "INSERT INTO items SELECT itemsets.item_id, parent_item_id, node_id, parent_node_id, title, itemsets.read, updated, popup, marked, source, source_id, valid_guid, description, date, comment_feed_id, itemsets.comment FROM items_backup JOIN itemsets ON itemsets.item_id = items_backup.item_id; "
			         "DROP TABLE items_backup; "
			         "DROP TABLE itemsets; "
			         "REPLACE INTO info (name, value) VALUES ('schemaVersion',8); "
			         "END;" );

			db_exec ("DROP TABLE attention_stats");	/* this is unconditional, no checks and backups needed */
		}

		if (db_get_schema_version () == 8) {
			gchar *sql;
			sqlite3_stmt *stmt;
			
			/* 1.7.3 -> 1.7.4 change search folder handling */
			db_exec ("BEGIN; "
			         "DROP TABLE view_state; "
			         "DROP TABLE update_state; "
				 "CREATE TABLE search_folder_items ("
				 "   node_id            STRING,"
	         		 "   item_id		INTEGER,"
				 "   PRIMARY KEY (node_id, item_id)"
				 ");"
			         "REPLACE INTO info (name, value) VALUES ('schemaVersion',9); "
			         "END;" );
			         
			debug0 (DEBUG_DB, "Removing all views.");
			sql = sqlite3_mprintf("SELECT name FROM sqlite_master WHERE type='view';");
			res = sqlite3_prepare_v2 (db, sql, -1, &stmt, NULL);
			sqlite3_free (sql);
			if (SQLITE_OK != res) {
				debug1 (DEBUG_DB, "Could not determine views (error=%d)", res);
			} else {
				sqlite3_reset (stmt);

					while (sqlite3_step (stmt) == SQLITE_ROW) {
						const gchar *viewName = sqlite3_column_text (stmt, 0) + strlen("view_");
						gchar *copySql = g_strdup_printf("INSERT INTO search_folder_items (node_id, item_id) SELECT '%s',item_id FROM view_%s;", viewName, viewName);
						
						db_exec (copySql);
						db_view_remove (viewName);
						
						g_free (copySql);
					}
			
				sqlite3_finalize (stmt);
			}
		}

		if (db_get_schema_version () == 9) {
			/* A parent node id to search folder relation to allow cleanups */
			db_exec ("BEGIN; "
			         "DROP TABLE search_folder_items; "
				 "CREATE TABLE search_folder_items ("
				 "   node_id            STRING,"
				 "   parent_node_id     STRING,"
	         		 "   item_id		INTEGER,"
				 "   PRIMARY KEY (node_id, item_id)"
				 ");"
			         "REPLACE INTO info (name, value) VALUES ('schemaVersion',10); "
			         "END;" );

			searchFolderRebuild = TRUE;
		}
	}

	if (SCHEMA_TARGET_VERSION != db_get_schema_version ())
		g_error ("Fatal: DB schema version not up-to-date! Running with --debug-db could give some hints about the problem!");
	
	/* Vacuuming... */

	db_vacuum ();
	
	/* Schema creation */
		
	debug_start_measurement (DEBUG_DB);
	db_begin_transaction ();

	/* 1. Create tables if they do not exist yet */
	db_exec ("CREATE TABLE items ("
        	 "   item_id		INTEGER,"
		 "   parent_item_id     INTEGER,"
        	 "   node_id		TEXT," /* FIXME: migrate node ids to real integers */
		 "   parent_node_id     TEXT," /* FIXME: migrate node ids to real integers */
        	 "   title		TEXT,"
        	 "   read		INTEGER,"
        	 "   updated		INTEGER,"
        	 "   popup		INTEGER,"
        	 "   marked		INTEGER,"
        	 "   source		TEXT,"
        	 "   source_id		TEXT,"
        	 "   valid_guid		INTEGER,"
        	 "   description	TEXT,"
        	 "   date		INTEGER,"
        	 "   comment_feed_id	TEXT,"
		 "   comment            INTEGER,"
		 "   PRIMARY KEY (item_id)"
        	 ");");

	db_exec ("CREATE INDEX items_idx ON items (source_id);");
	db_exec ("CREATE INDEX items_idx2 ON items (comment_feed_id);");
	db_exec ("CREATE INDEX items_idx3 ON items (node_id);");
	db_exec ("CREATE INDEX items_idx4 ON items (item_id);");
	db_exec ("CREATE INDEX items_idx5 ON items (parent_item_id);");
	db_exec ("CREATE INDEX items_idx6 ON items (parent_node_id);");
		
	db_exec ("CREATE TABLE metadata ("
        	 "   item_id		INTEGER,"
        	 "   nr              	INTEGER,"
        	 "   key             	TEXT,"
        	 "   value           	TEXT,"
        	 "   PRIMARY KEY (item_id, nr)"
        	 ");");

	db_exec ("CREATE INDEX metadata_idx ON metadata (item_id);");
		
	db_exec ("CREATE TABLE subscription ("
        	 "   node_id            STRING,"
		 "   source             STRING,"
		 "   orig_source        STRING,"
		 "   filter_cmd         STRING,"
		 "   update_interval	INTEGER,"
		 "   default_interval   INTEGER,"
		 "   discontinued       INTEGER,"
		 "   available          INTEGER,"
        	 "   PRIMARY KEY (node_id)"
		 ");");

	db_exec ("CREATE TABLE subscription_metadata ("
        	 "   node_id            STRING,"
		 "   nr                 INTEGER,"
		 "   key                TEXT,"
		 "   value              TEXT,"
		 "   PRIMARY KEY (node_id, nr)"
		 ");");

	db_exec ("CREATE INDEX subscription_metadata_idx ON subscription_metadata (node_id);");

	db_exec ("CREATE TABLE node ("
        	 "   node_id		STRING,"
        	 "   parent_id		STRING,"
        	 "   title		STRING,"
		 "   type		INTEGER,"
		 "   expanded           INTEGER,"
		 "   view_mode		INTEGER,"
		 "   sort_column	INTEGER,"
		 "   sort_reversed	INTEGER,"
		 "   PRIMARY KEY (node_id)"
        	 ");");

	db_exec ("CREATE TABLE search_folder_items ("
	         "   node_id            STRING,"
	         "   parent_node_id     STRING,"
	         "   item_id		INTEGER,"
		 "   PRIMARY KEY (node_id, item_id)"
		 ");");

	db_end_transaction ();
	debug_end_measurement (DEBUG_DB, "table setup");
		
	/* 2. Removing old triggers */
	db_exec ("DROP TRIGGER item_insert;");
	db_exec ("DROP TRIGGER item_update;");
	db_exec ("DROP TRIGGER item_removal;");
	db_exec ("DROP TRIGGER subscription_removal;");
		
	/* 3. Cleanup of DB */

	/* Note: do not check on subscriptions here, as non-subscription node
	   types (e.g. news bin) do contain items too. */
	debug0 (DEBUG_DB, "Checking for items without a feed list node...\n");
	db_exec ("DELETE FROM items WHERE comment = 0 AND node_id NOT IN "
        	 "(SELECT node_id FROM node);");
        	 
        debug0 (DEBUG_DB, "Checking for comments without parent item...\n");
	db_exec ("BEGIN; "
	         "   CREATE TEMP TABLE tmp_id ( id );"
	         "   INSERT INTO tmp_id SELECT item_id FROM items WHERE comment = 1 AND parent_item_id NOT IN (SELECT item_id FROM items WHERE comment = 0);"
	         /* limit to 1000 items as it is very slow */
	         "   DELETE FROM items WHERE item_id IN (SELECT id FROM tmp_id LIMIT 1000);"
	         "   DROP TABLE tmp_id;"
		 "END;");
        
	debug0 (DEBUG_DB, "Checking for search folder items without a feed list node...\n");
	db_exec ("DELETE FROM search_folder_items WHERE parent_node_id NOT IN "
        	 "(SELECT node_id FROM node);");

	debug0 (DEBUG_DB, "Checking for search folder items without a search folder...\n");
	db_exec ("DELETE FROM search_folder_items WHERE node_id NOT IN "
        	 "(SELECT node_id FROM node);");

	debug0 (DEBUG_DB, "Checking for search folder with comments...\n");
	db_exec ("DELETE FROM search_folder_items WHERE comment = 1;");
			  
	debug0 (DEBUG_DB, "DB cleanup finished. Continuing startup.");
		
	/* 4. Creating triggers (after cleanup so it is not slowed down by triggers) */

	/* This trigger does explicitely not remove comments! */
	db_exec ("CREATE TRIGGER item_removal DELETE ON items "
        	 "BEGIN "
		 "   DELETE FROM metadata WHERE item_id = old.item_id; "
		 "   DELETE FROM search_folder_items WHERE item_id = old.item_id; "
        	 "END;");
		
	db_exec ("CREATE TRIGGER subscription_removal DELETE ON subscription "
        	 "BEGIN "
		 "   DELETE FROM node WHERE node_id = old.node_id; "
		 "   DELETE FROM subscription_metadata WHERE node_id = old.node_id; "
		 "   DELETE FROM search_folder_items WHERE parent_node_id = old.node_id; "
        	 "END;");

	/* Note: view counting triggers are set up in the view preparation code (see db_view_create()) */		
	/* prepare statements */
	
	db_new_statement ("itemsetLoadStmt",
	                  "SELECT item_id FROM items WHERE node_id = ?");

	db_new_statement ("itemsetLoadOffsetStmt",
			  "SELECT item_id FROM items WHERE comment = 0 LIMIT ? OFFSET ?");
		       
	db_new_statement ("itemsetReadCountStmt",
	                  "SELECT COUNT(item_id) FROM items "
		          "WHERE read = 0 AND node_id = ?");
	       
	db_new_statement ("itemsetItemCountStmt",
	                  "SELECT COUNT(item_id) FROM items "
		          "WHERE node_id = ?");
		       
	db_new_statement ("itemsetRemoveStmt",
	                  "DELETE FROM items WHERE item_id = ? OR (comment = 1 AND parent_item_id = ?)");
			
	db_new_statement ("itemsetRemoveAllStmt",
	                  "DELETE FROM items WHERE node_id = ? OR (comment = 1 AND parent_node_id = ?)");

	db_new_statement ("itemsetMarkAllPopupStmt",
	                  "UPDATE items SET popup = 0 WHERE node_id = ?");

	db_new_statement ("itemLoadStmt",
	                  "SELECT "
	                  "title,"
	                  "read,"
	                  "updated,"
	                  "popup,"
	                  "marked,"
	                  "source,"
	                  "source_id,"
	                  "valid_guid,"
	                  "description,"
	                  "date,"
		          "comment_feed_id,"
		          "comment,"
		          "item_id,"
			  "parent_item_id, "
		          "node_id, "
			  "parent_node_id "
	                  " FROM items WHERE item_id = ?");      
	
	db_new_statement ("itemUpdateStmt",
	                  "REPLACE INTO items ("
	                  "title,"
	                  "read,"
	                  "updated,"
	                  "popup,"
	                  "marked,"
	                  "source,"
	                  "source_id,"
	                  "valid_guid,"
	                  "description,"
	                  "date,"
		          "comment_feed_id,"
		          "comment,"
	                  "item_id,"
	                  "parent_item_id,"
	                  "node_id,"
	                  "parent_node_id"
	                  ") values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
			
	db_new_statement ("itemStateUpdateStmt",
			  "UPDATE items SET read=?, marked=?, updated=? "
			  "WHERE item_id=?");

	db_new_statement ("duplicatesFindStmt",
	                  "SELECT item_id FROM items WHERE source_id = ?");
			 
	db_new_statement ("duplicateNodesFindStmt",
	                  "SELECT node_id FROM items WHERE item_id IN "
			  "(SELECT item_id FROM items WHERE source_id = ?)");
		       
	db_new_statement ("duplicatesMarkReadStmt",
 	                  "UPDATE items SET read = 1, updated = 0 WHERE source_id = ?");
						
	db_new_statement ("metadataLoadStmt",
	                  "SELECT key,value,nr FROM metadata WHERE item_id = ? ORDER BY nr");
			
	db_new_statement ("metadataUpdateStmt",
	                  "REPLACE INTO metadata (item_id,nr,key,value) VALUES (?,?,?,?)");
			
	db_new_statement ("subscriptionUpdateStmt",
	                  "REPLACE INTO subscription ("
			  "node_id,"
			  "source,"
			  "orig_source,"
			  "filter_cmd,"
			  "update_interval,"
			  "default_interval,"
			  "discontinued,"
			  "available"
			  ") VALUES (?,?,?,?,?,?,?,?)");
			 
	db_new_statement ("subscriptionRemoveStmt",
	                  "DELETE FROM subscription WHERE node_id = ?");
			 
	db_new_statement ("subscriptionLoadStmt",
	                  "SELECT "
			  "node_id,"
			  "source,"
			  "orig_source,"
			  "filter_cmd,"
			  "update_interval,"
			  "default_interval,"
			  "discontinued,"
			  "available "
			  "FROM subscription");
	
	db_new_statement ("subscriptionMetadataLoadStmt",
	                  "SELECT key,value,nr FROM subscription_metadata WHERE node_id = ? ORDER BY nr");
			
	db_new_statement ("subscriptionMetadataUpdateStmt",
	                  "REPLACE INTO subscription_metadata (node_id,nr,key,value) VALUES (?,?,?,?)");
	
	db_new_statement ("nodeUpdateStmt",
	                  "REPLACE INTO node (node_id,parent_id,title,type,expanded,view_mode,sort_column,sort_reversed) VALUES (?,?,?,?,?,?,?,?)");
	                  
	db_new_statement ("itemUpdateSearchFoldersStmt",
	                  "REPLACE INTO search_folder_items (node_id, parent_node_id, item_id) VALUES (?,?,?)");

	db_new_statement ("itemRemoveFromSearchFolderStmt",
	                  "DELETE FROM search_folder_items WHERE node_id =? AND item_id = ?;");
	                  
	db_new_statement ("searchFolderLoadStmt",
	                  "SELECT item_id FROM search_folder_items WHERE node_id = ?;");

	db_new_statement ("searchFolderCountStmt",
	                  "SELECT count(item_id) FROM search_folder_items WHERE node_id = ?;");

	db_new_statement ("nodeIdListStmt",
	                  "SELECT node_id FROM node;");

	db_new_statement ("nodeRemoveStmt",
	                  "DELETE FROM node WHERE node_id = ?;");
			  
	g_assert (sqlite3_get_autocommit (db));
	
	debug_exit ("db_init");
}
Пример #2
0
void main(void)
{
  debug_printf("hello world\n");
  debug_exit(0);
}
/*
 * Class:     org_jnetpcap_packet_JScanner
 * Method:    loadScanners
 * Signature: (I[Lorg/jnetpcap/packet/JHeaderScanner;)V
 */
JNIEXPORT void JNICALL Java_org_jnetpcap_packet_JScanner_loadScanners
(JNIEnv *env, jobject obj, jobjectArray jascanners) {

#ifdef DEBUG
	debug_enter("loadScanners");
#endif

	scanner_t *scanner = (scanner_t *)getJMemoryPhysical(env, obj);
	if (scanner == NULL) {
		return;
	}

	jsize size = env->GetArrayLength(jascanners);

#ifdef DEBUG
	debug_trace("load", "loaded %d scanners", (int)size);
#endif

	if (size != MAX_ID_COUNT) {
		throwException(env,
				ILLEGAL_ARGUMENT_EXCEPTION,
				"size of array must be MAX_ID_COUNT size");
#ifdef DEBUG
		debug_error("IllegalArgumentException",
				"size of array must be MAX_ID_COUNT size");
#endif
		return;
	}

	for (int i = 0; i < MAX_ID_COUNT; i ++) {
		jobject loc_ref = env->GetObjectArrayElement(jascanners, (jsize) i);
		if (loc_ref == NULL) {

			/*
			 * If we don't have a java header scanner, then setup the native
			 * scanner in its place. Any unused java scanner slot will be filled
			 * with native scanner.
			 */
			scanner->sc_scan_table[i] = native_protocols[i];
			//			printf("loadScanners::native(%s)\n", id2str(i));fflush(stdout);
		} else {

			//			printf("loadScanners::java(%s)\n", id2str(i));fflush(stdout);


			if (scanner->sc_java_header_scanners[i] != NULL) {
				env->DeleteGlobalRef(scanner->sc_java_header_scanners[i]);
				scanner->sc_java_header_scanners[i] = NULL;
			}

			/*
			 * Record the java header scanner and replace the native scanner with
			 * our java scanner in dispatch table.
			 */
			scanner->sc_java_header_scanners[i] = env->NewGlobalRef(loc_ref);
			scanner->sc_scan_table[i] = callJavaHeaderScanner;

			env->DeleteLocalRef(loc_ref);
		}
	}

#ifdef DEBUG
	debug_exit("loadScanners");
#endif

}
Пример #4
0
void
liferea_shell_create (GtkApplication *app, const gchar *overrideWindowState)
{
	GtkUIManager	*ui_manager;
	GtkAccelGroup	*accel_group;
	GError		*error = NULL;	
	gboolean	toggle;
	gchar		*id;
	
	debug_enter ("liferea_shell_create");

	g_object_new (LIFEREA_SHELL_TYPE, NULL);

	shell->priv->window = GTK_WINDOW (liferea_shell_lookup ("mainwindow"));

	gtk_window_set_application (GTK_WINDOW (shell->priv->window), app);
	
	/* 1.) menu creation */
	
	debug0 (DEBUG_GUI, "Setting up menues");

	shell->priv->itemlist = itemlist_create ();

	/* Prepare some toggle button states */	
	conf_get_bool_value (REDUCED_FEEDLIST, &toggle);
	liferea_shell_feedlist_toggle_entries[0].is_active = toggle;

	ui_manager = gtk_ui_manager_new ();

	shell->priv->generalActions = gtk_action_group_new ("GeneralActions");
	gtk_action_group_set_translation_domain (shell->priv->generalActions, PACKAGE);
	gtk_action_group_add_actions (shell->priv->generalActions, liferea_shell_action_entries, G_N_ELEMENTS (liferea_shell_action_entries), shell->priv);
	gtk_action_group_add_toggle_actions (shell->priv->generalActions, liferea_shell_action_toggle_entries, G_N_ELEMENTS (liferea_shell_action_toggle_entries), shell->priv);
	gtk_action_group_add_radio_actions (shell->priv->generalActions, liferea_shell_view_radio_entries, G_N_ELEMENTS (liferea_shell_view_radio_entries), itemlist_get_view_mode (), (GCallback)on_view_activate, (gpointer)TRUE);
	gtk_action_group_add_toggle_actions (shell->priv->generalActions, liferea_shell_feedlist_toggle_entries, G_N_ELEMENTS (liferea_shell_feedlist_toggle_entries), shell->priv);
	gtk_ui_manager_insert_action_group (ui_manager, shell->priv->generalActions, 0);

	shell->priv->addActions = gtk_action_group_new ("AddActions");
	gtk_action_group_set_translation_domain (shell->priv->addActions, PACKAGE);
	gtk_action_group_add_actions (shell->priv->addActions, liferea_shell_add_action_entries, G_N_ELEMENTS (liferea_shell_add_action_entries), shell->priv);
	gtk_ui_manager_insert_action_group (ui_manager, shell->priv->addActions, 0);

	shell->priv->feedActions = gtk_action_group_new ("FeedActions");
	gtk_action_group_set_translation_domain (shell->priv->feedActions, PACKAGE);
	gtk_action_group_add_actions (shell->priv->feedActions, liferea_shell_feed_action_entries, G_N_ELEMENTS (liferea_shell_feed_action_entries), shell->priv);
	gtk_ui_manager_insert_action_group (ui_manager, shell->priv->feedActions, 0);

	shell->priv->readWriteActions = gtk_action_group_new("ReadWriteActions");
	gtk_action_group_set_translation_domain (shell->priv->readWriteActions, PACKAGE);
	gtk_action_group_add_actions (shell->priv->readWriteActions, liferea_shell_read_write_action_entries, G_N_ELEMENTS (liferea_shell_read_write_action_entries), shell->priv);
	gtk_ui_manager_insert_action_group (ui_manager, shell->priv->readWriteActions, 0);

	shell->priv->itemActions = gtk_action_group_new ("ItemActions");
	gtk_action_group_set_translation_domain (shell->priv->itemActions, PACKAGE);
	gtk_action_group_add_actions (shell->priv->itemActions, liferea_shell_item_action_entries, G_N_ELEMENTS (liferea_shell_item_action_entries), shell->priv);
	gtk_ui_manager_insert_action_group (ui_manager, shell->priv->itemActions, 0);

	accel_group = gtk_ui_manager_get_accel_group (ui_manager);
	gtk_window_add_accel_group (GTK_WINDOW (shell->priv->window), accel_group);
	g_object_unref (accel_group);

	g_signal_connect (gtk_accel_map_get (), "changed", G_CALLBACK (on_accel_change), NULL);

	if (!gtk_ui_manager_add_ui_from_string (ui_manager, liferea_shell_ui_desc, -1, &error))
		g_error ("building menus failed: %s", error->message);

	shell->priv->menubar = gtk_ui_manager_get_widget (ui_manager, "/MainwindowMenubar");
	shell->priv->toolbar = gtk_ui_manager_get_widget (ui_manager, "/maintoolbar");

	/* Ensure GTK3 toolbar shadows... */
	gtk_style_context_add_class (gtk_widget_get_style_context (shell->priv->toolbar), "primary-toolbar");

	/* what a pain, why is there no markup for this option? */
	g_object_set (G_OBJECT (gtk_ui_manager_get_widget (ui_manager, "/maintoolbar/newFeedButton")), "is_important", TRUE, NULL);
	g_object_set (G_OBJECT (gtk_ui_manager_get_widget (ui_manager, "/maintoolbar/nextUnreadButton")), "is_important", TRUE, NULL);
	g_object_set (G_OBJECT (gtk_ui_manager_get_widget (ui_manager, "/maintoolbar/MarkAsReadButton")), "is_important", TRUE, NULL);
	g_object_set (G_OBJECT (gtk_ui_manager_get_widget (ui_manager, "/maintoolbar/UpdateAllButton")), "is_important", TRUE, NULL);
	g_object_set (G_OBJECT (gtk_ui_manager_get_widget (ui_manager, "/maintoolbar/SearchButton")), "is_important", TRUE, NULL);

	/* 2.) setup containers */
	
	debug0 (DEBUG_GUI, "Setting up widget containers");

	gtk_box_pack_start (GTK_BOX (liferea_shell_lookup ("vbox1")), shell->priv->toolbar, FALSE, FALSE, 0);
	gtk_box_reorder_child (GTK_BOX (liferea_shell_lookup ("vbox1")), shell->priv->toolbar, 0);
	gtk_box_pack_start (GTK_BOX (liferea_shell_lookup ("vbox1")), shell->priv->menubar, FALSE, FALSE, 0);
	gtk_box_reorder_child (GTK_BOX (liferea_shell_lookup ("vbox1")), shell->priv->menubar, 0);

	gtk_widget_show_all(GTK_WIDGET(shell->priv->toolbar));

	g_signal_connect ((gpointer) liferea_shell_lookup ("itemtabs"), "key_press_event",
	                  G_CALLBACK (on_key_press_event_null_cb), NULL);

	g_signal_connect ((gpointer) liferea_shell_lookup ("itemtabs"), "key_release_event",
	                  G_CALLBACK (on_key_press_event_null_cb), NULL);
	
	g_signal_connect ((gpointer) liferea_shell_lookup ("itemtabs"), "scroll_event",
	                  G_CALLBACK (on_notebook_scroll_event_null_cb), NULL);
	
	g_signal_connect (G_OBJECT (shell->priv->window), "delete_event", G_CALLBACK(on_close), shell->priv);
	g_signal_connect (G_OBJECT (shell->priv->window), "window_state_event", G_CALLBACK(on_window_state_event), shell->priv);
	g_signal_connect (G_OBJECT (shell->priv->window), "key_press_event", G_CALLBACK(on_key_press_event), shell->priv);
	
	/* 3.) setup status bar */
	
	debug0 (DEBUG_GUI, "Setting up status bar");
	
	shell->priv->statusbar = GTK_STATUSBAR (liferea_shell_lookup ("statusbar"));
	shell->priv->statusbarLocked = FALSE;
	shell->priv->statusbarLockTimer = 0;
	shell->priv->statusbar_feedsinfo = gtk_label_new("");
	gtk_widget_show(shell->priv->statusbar_feedsinfo);
	gtk_box_pack_start (GTK_BOX (shell->priv->statusbar), shell->priv->statusbar_feedsinfo, FALSE, FALSE, 5);

	/* 4.) setup tabs */
	
	debug0 (DEBUG_GUI, "Setting up tabbed browsing");	
	shell->priv->tabs = browser_tabs_create (GTK_NOTEBOOK (liferea_shell_lookup ("browsertabs")));
	
	/* 5.) setup feed list */

	debug0 (DEBUG_GUI, "Setting up feed list");
	shell->priv->feedlistView = GTK_TREE_VIEW (liferea_shell_lookup ("feedlist"));
	feed_list_view_init (shell->priv->feedlistView);

	/* 6.) setup menu sensivity */
	
	debug0 (DEBUG_GUI, "Initialising menues");
		
	/* On start, no item or feed is selected, so Item menu should be insensitive: */
	liferea_shell_update_item_menu (FALSE);

	/* necessary to prevent selection signals when filling the feed list
	   and setting the 2/3 pane mode view */
	gtk_widget_set_sensitive (GTK_WIDGET (shell->priv->feedlistView), FALSE);
	
	/* 7.) setup item view */
	
	debug0 (DEBUG_GUI, "Setting up item view");

	shell->priv->itemview = itemview_create (GTK_WIDGET (shell->priv->window));

        /* 8.) load icons as required */
        
        debug0 (DEBUG_GUI, "Loading icons");
        
        icons_load ();
	
	/* 9.) update and restore all menu elements */

	liferea_shell_update_toolbar ();
	liferea_shell_update_history_actions ();
	liferea_shell_setup_URL_receiver ();
	liferea_shell_restore_state (overrideWindowState);
	
	gtk_widget_set_sensitive (GTK_WIDGET (shell->priv->feedlistView), TRUE);

	/* 10.) After main window is realized get theme colors and set up feed
 	        list and tray icon */
	render_init_theme_colors (GTK_WIDGET (shell->priv->window));

	shell->priv->feedlist = feedlist_create ();
	g_signal_connect (shell->priv->feedlist, "new-items",
	                  G_CALLBACK (liferea_shell_update_unread_stats), shell->priv->feedlist);

	/* 11.) Restore latest selection */

	// FIXME: Move to feed list code
	if (conf_get_str_value (LAST_NODE_SELECTED, &id)) {
		feed_list_view_select (node_from_id (id));
		g_free (id);
	}

	/* 12. Setup shell plugins */

	shell->priv->extensions = peas_extension_set_new (PEAS_ENGINE (liferea_plugins_engine_get_default ()),
		                             LIFEREA_TYPE_SHELL_ACTIVATABLE, "shell", shell, NULL);

	g_signal_connect (shell->priv->extensions, "extension-added", G_CALLBACK (on_extension_added), shell);
	g_signal_connect (shell->priv->extensions, "extension-removed",	G_CALLBACK (on_extension_removed), shell);

	peas_extension_set_call (shell->priv->extensions, "activate");

	/* 14. Rebuild search folders if needed */
	if (searchFolderRebuild)
		vfolder_foreach (vfolder_rebuild);

	debug_exit ("liferea_shell_create");
}
/**
 * Adjusts for a packet that has been truncated. Sets appropriate flags in the
 * header flags field, resets lengths of prefix, header, gap, payload and 
 * postfix appropriately to account for shortened packet.
 */
void adjustForTruncatedPacket(scan_t *scan) {
#ifdef DEBUG
	debug_enter("adjustForTruncatedPacket");
	debug_trace("packet", "%ld", scan->scanner->sc_cur_frame_num);
#endif

	/*
	 * Adjust for truncated packets. We check the end of the header record
	 * against the buf_len. If the end is past the buf_len, that means that we
	 * need to start trucating in the following order: 
	 * postfix, payload, gap, header, prefix
	 * 
	 * +-------------------------------------------+
	 * | prefix | header | gap | payload | postfix |
	 * +-------------------------------------------+
	 * 
	 */
	register int start = scan->offset + scan->hdr_prefix + scan->length
			+ scan->hdr_gap + scan->hdr_payload;

	register int end = start + scan->hdr_postfix;
	register int buf_len = scan->buf_len;

#ifdef DEBUG
	debug_scan((char *)id2str(scan->id), scan);
	debug_trace(id2str(scan->id), "offset=%d, pre=%d, len=%d, gap=%d, pay=%d, post=%d",
			scan->offset,
			scan->hdr_prefix,
			scan->length,
			scan->hdr_gap,
			scan->hdr_payload,
			scan->hdr_postfix);
	debug_trace(id2str(scan->id), "start=%d end=%d buf_len=%d", start, end, buf_len);
#endif

	if (end > buf_len) { // Check if postfix extends past the end of packet

		/*
		 * Because postfix is at the end, whenever the packet is truncated
		 * postfix is always truncated, unless it wasn't set
		 */
		if (scan->hdr_postfix > 0) {
			scan->hdr_flags |= HEADER_FLAG_PREFIX_TRUNCATED;
			scan->hdr_postfix = (start > scan->mem_len) ? 0 : scan->mem_len
					- start;
			scan->hdr_postfix = (scan->hdr_postfix < 0) ? 0 : scan->hdr_postfix;
#ifdef DEBUG
			debug_scan("adjust postfix", scan);
#endif
		}

		/* Position at payload and process */
		start -= scan->hdr_payload;
		end = start + scan->hdr_payload;

		if (end > buf_len) {
			scan->hdr_flags |= HEADER_FLAG_PAYLOAD_TRUNCATED;
			scan->hdr_payload = (start > buf_len) ? 0 : buf_len - start;
			scan->hdr_payload = (scan->hdr_payload < 0) ? 0 : scan->hdr_payload;

#ifdef DEBUG
			debug_scan("adjust payload", scan);
			debug_trace("adjust payload", "start=%d end=%d", start, end);
#endif

			/* Position at gap and process */
			start -= scan->hdr_gap;
			end = start + scan->hdr_gap;
			if (scan->hdr_gap > 0 && end > buf_len) {

				scan->hdr_flags |= HEADER_FLAG_GAP_TRUNCATED;
				scan->hdr_gap = (start > buf_len) ? 0 : buf_len - start;
				scan->hdr_gap = (scan->hdr_gap < 0) ? 0 : scan->hdr_gap;
#ifdef DEBUG
				debug_scan("adjust gap", scan);
#endif
			}

			/* Position at header and process */
			start -= scan->length;
			end = start + scan->length;

			if (end > buf_len) {
				scan->hdr_flags |= HEADER_FLAG_HEADER_TRUNCATED;
				scan->length = (start > buf_len) ? 0 : buf_len - start;
				scan->length = (scan->length < 0) ? 0 : scan->length;
#ifdef DEBUG
				debug_scan("adjust header", scan);
#endif

				/* Position at prefix and process */
				start -= scan->hdr_prefix;
				end = start + scan->hdr_prefix;

				if (0 && scan->hdr_prefix > 0 && end > buf_len) {
					scan->hdr_flags |= HEADER_FLAG_PREFIX_TRUNCATED;
					scan->hdr_prefix = (start > buf_len) ? 0 : buf_len - start;
					scan->hdr_prefix = (scan->hdr_prefix < 0) ? 0
							: scan->hdr_prefix;
#ifdef DEBUG
					debug_scan("adjust prefix", scan);
#endif

				}
			}
		}
	}

#ifdef DEBUG
	debug_exit("adjustForTruncatedPacket");
#endif
#undef DEBUG
}
/**
 * Prepares a scan of packet buffer
 */
int scanJPacket(JNIEnv *env, jobject obj, jobject jpacket, jobject jstate,
		scanner_t *scanner, int first_id, char *buf, int buf_length,
		uint32_t wirelen) {

#ifdef DEBUG
	debug_enter("scanJPacket");
#endif

	/* Check if we need to wrap our entry buffer around */
	if (scanner->sc_offset > scanner->sc_len - sizeof(header_t)
			* MAX_ENTRY_COUNT) {
		scanner->sc_offset = 0;
	}

	packet_state_t *packet = (packet_state_t *) (((char *) scanner->sc_packet)
			+ scanner->sc_offset);

	/*
	 * Peer JPacket.state to packet_state_t structure
	 */
	//	setJMemoryPhysical(env, jstate, toLong(packet));
	//	env->SetObjectField(jstate, jmemoryKeeperFID, obj); // Set it to JScanner
	jmemoryPeer(env, jstate, packet, sizeof(packet_state_t), obj);

	/*
	 * Reset the entire packet_state_t structure
	 */
	memset(packet, 0, sizeof(packet_state_t));

	/* 
	 * Initialize the packet_state_t structure for new packet entry. We need to 
	 * initialize everything since we may be wrapping around and writting over 
	 * previously stored data.
	 */
	packet->pkt_header_count = 0;
	packet->pkt_frame_num = scanner->sc_cur_frame_num++;
	packet->pkt_wirelen = (uint32_t) wirelen;
	packet->pkt_caplen = (uint32_t) buf_length;
	packet->pkt_flags = 0;

	if (buf_length != wirelen) {
		packet->pkt_flags |= PACKET_FLAG_TRUNCATED;
	}

#ifdef DEBUG
	debug_trace("before scan", "buf_len=%d wire_len=%d", buf_length, wirelen);
#endif

	scan(env, obj, jpacket, scanner, packet, first_id, buf, buf_length, wirelen);

#ifdef DEBUG
	debug_trace("after scan", "buf_len=%d wire_len=%d", buf_length, wirelen);
#endif

	const size_t len = sizeof(packet_state_t) + (sizeof(header_t)
			* packet->pkt_header_count);

	scanner->sc_offset += len;

	jmemoryResize(env, jstate, len);

#ifdef DEBUG
	debug_exit("scanJPacket");
#endif

}
/**
 * Record state of the header in the packet state structure.
 */
void record_header(scan_t *scan) {

#ifdef DEBUG
	debug_enter("record_header");
	debug_scan("top", scan);
#endif

	/*
	 * Check if already recorded
	 */
	if (scan->is_recorded) {
#ifdef DEBUG
		debug_exit("record_header");
#endif
		return;
	}

	register int offset = scan->offset;
	register header_t *header = scan->header;
	register int buf_len = scan->buf_len;
	packet_state_t *packet = scan->packet;

	/*
	 * Decrease wire-length by postfix amount so that next header's payload
	 * will be reduced and won't go over this header's postfix
	 */
	scan->wire_len -= scan->hdr_postfix;
	if (buf_len > scan->wire_len) {
		buf_len = scan->buf_len = scan->wire_len; // Make sure that buf_len and wire_len sync up
#ifdef DEBUG
		debug_scan("adj buf_len", scan);
#endif
	}

	/*
	 * If payload length hasn't explicitly been set to some length, set it
	 * to the remainder of the packet.
	 */
	if (scan->hdr_payload == 0 && scan->id != PAYLOAD_ID) {
		scan->hdr_payload = scan->buf_len - (offset + scan->hdr_prefix
				+ scan->length + scan->hdr_gap);
		scan->hdr_payload = (scan->hdr_payload < 0) ? 0 : scan->hdr_payload;
#ifdef DEBUG
		debug_scan("adj payload", scan);
#endif
	}

	adjustForTruncatedPacket(scan);
	register int length = scan->length;

	/*
	 * Initialize the header entry in our packet header array
	 */
//	packet->pkt_header_map |= (uint64_t)(1ULL << scan->id);
	PACKET_STATE_ADD_HEADER(packet, scan->id);
	header->hdr_id = scan->id;
	header->hdr_offset = offset + scan->hdr_prefix;
	header->hdr_analysis = NULL;

	/*
	 * This is a combination of regular header flags with cumulative flags
	 * which are accumulated by subsequent pass to the next header and pass on
	 * to their encapsulated headers. This is a way to pass flags such as 
	 * the remaining header's are fragmented.
	 */
	header->hdr_flags = scan->hdr_flags | (scan->flags & CUMULATIVE_FLAG_MASK);

	header->hdr_prefix = scan->hdr_prefix;
	header->hdr_gap = scan->hdr_gap;
	header->hdr_payload = scan->hdr_payload;
	header->hdr_postfix = scan->hdr_postfix;
	header->hdr_length = length;

	scan->hdr_flags = 0;
	scan->hdr_prefix = 0;
	scan->hdr_gap = 0;
	scan->hdr_payload = 0;
	scan->hdr_postfix = 0;
	scan->is_recorded = 1;
	scan->hdr_count ++;

	packet->pkt_header_count++; /* number of entries */

	//	scan->id = -1; // Indicates, that header is already recorded

	/* Initialize key fields in a new header */
	header = ++scan->header; /* point to next header entry *** ptr arithmatic */
	memset(header, 0, sizeof(header_t));

#ifdef DEBUG
	debug_scan("bottom", scan);
	debug_exit("record_header");
#endif
}
/**
 * Scan packet buffer
 */
int scan(JNIEnv *env, jobject obj, jobject jpacket, scanner_t *scanner,
		packet_state_t *p_packet, int first_id, char *buf, int buf_len,
		uint32_t wirelen) {

	scan_t scan; // Our current in progress scan's state information
	scan_t *pscan = &scan;
	scan.env = env;
	scan.jscanner = obj;
	scan.jpacket = jpacket;
	scan.scanner = scanner;
	scan.packet = p_packet;
	scan.header = &p_packet->pkt_headers[0];
	scan.buf = buf;
	scan.buf_len = buf_len; // Changing buffer length, reduced by 'postfix'
	scan.mem_len = buf_len; // Constant in memory buffer length
	scan.wire_len = wirelen;
	scan.offset = 0;
	scan.length = 0;
	scan.id = first_id;
	scan.next_id = PAYLOAD_ID;
	scan.flags = 0;
	scan.stack_index = 0;

	scan.hdr_count = 0;
	scan.hdr_flags = 0;
	scan.hdr_prefix = 0;
	scan.hdr_gap = 0;
	scan.hdr_payload = 0;
	scan.hdr_postfix = 0;

	memset(scan.header, 0, sizeof(header_t));

	// Point jscan 
	setJMemoryPhysical(env, scanner->sc_jscan, toLong(&scan));

	// Local temp variables
	register uint64_t mask;

#ifdef DEBUG
	debug_enter("scan");
	debug_trace("processing packet", "#%d", p_packet->pkt_frame_num);
#endif

	/*
	 * Main scanner loop, 1st scans for builtin header types then
	 * reverts to calling on JBinding objects to provide the binding chain
	 */
	while (scan.id != END_OF_HEADERS) {
#ifdef DEBUG
		debug_trace("", "");
		debug_trace("processing header", id2str(scan.id));
		debug_scan("loop-top", &scan);
#endif

		/* A flag that keeps track of header recording. Set in record_header()*/
		scan.is_recorded = 0;

		/*
		 * If debugging is compiled in, we can also call on each protocols
		 * debug_* function to print out details about the protocol header
		 * structure. 
		 */
#ifdef DEBUG
		if (native_debug[scan.id]) {
			native_debug[scan.id](scan.buf + scan.offset);
		}
#endif

		/* 
		 * Scan of each protocol is done through a dispatch function table.
		 * Each protocol that has a protocol header scanner attached, a scanner
		 * designed specifically for that protocol. The protocol id is also the
		 * index into the table. There are 2 types of scanners both have exactly
		 * the same signature and thus both are set in this table. The first is
		 * the native scanner that only performs a direct scan of the header.
		 * The second scanner is a java header scanner. It is based on 
		 * JHeaderScanner class. A single dispatch method callJavaHeaderScanner
		 * uses the protocol ID to to dispatch to the appropriate java scanner.
		 * Uses a separate java specific table: sc_java_header_scanners[]. The
		 * java scanner is capable of calling the native scan method from java
		 * but also adds the ability to check all the attached JBinding[] for
		 * any additional registered bindings. Interesting fact is that if the
		 * java scanner doesn't have any bindings nor does it override the 
		 * default scan method to perform a scan in java and is also setup to 
		 * dispatch to native scanner, it is exactly same thing as if the 
		 * native scanner was dispatched directly from here, but round 
		 * about way through java land.
		 */
		if (scanner->sc_scan_table[scan.id] != NULL) {
			scanner->sc_scan_table[scan.id](&scan); // Dispatch to scanner
		}

#ifdef DEBUG
		debug_scan("loop-middle", &scan);
#endif

		if (scan.length == 0) {
#ifdef DEBUG
			debug_scan("loop-length==0", &scan);
#endif
			if (scan.id == PAYLOAD_ID) {
				if (scan.stack_index == 0) {
					scan.next_id = END_OF_HEADERS;
				} else {
					scan.stack_index --;
					scan.next_id = scan.stack[scan.stack_index].next_id;
					scan.offset = scan.stack[scan.stack_index].offset;
				}
			} else {
				scan.next_id = PAYLOAD_ID;
			}

		} else { // length != 0

#ifdef DEBUG
			debug_scan("loop-length > 0", &scan);
#endif

			/******************************************************
			 * ****************************************************
			 * * If override flag is set, then we reset the
			 * * discovered next protocol. If that is what the user 
			 * * wants then that is what he gets.
			 * ****************************************************
			 ******************************************************/
			if (scanner->sc_flags[scan.id] & FLAG_OVERRIDE_BINDING) {
#ifdef DEBUG
				debug_scan("TCP OVERRIDE", &scan);
#endif
				scan.next_id = PAYLOAD_ID;
			}

			/******************************************************
			 * ****************************************************
			 * * Now do HEURISTIC discovery scans if the appropriate
			 * * flags are set. Heuristics allow us to provide nxt
			 * * protocol binding, using discovery (an educated 
			 * * guess). 
			 * ****************************************************
			 ******************************************************/
			if (scanner->sc_flags[scan.id] & FLAG_HEURISTIC_BINDING) {

				/* 
				 * Save these critical properties, in case heuristic changes them
				 * for this current header, not the next one its supposed to
				 * check for.
				 */
				int saved_offset = scan.offset;
				int saved_length = scan.length;

				/* Advance offset to next header, so that heuristics can get a 
				 * peek. It will be restored at the end of heuristics block.
				 */
				scan.offset += scan.length + scan.hdr_gap;

				/*
				 * 2 types of heuristic bindings. Pre and post.
				 * Pre - heuristics are run before the direct discovery method
				 *       in scanner. Only after the pre-heuristic fail do we
				 *       utilize the directly discovered binding.
				 * 
				 * Post - heuristics are run after the direct discovery method
				 *        didn't produce a binding.
				 *
				 * ------------------------------------------------------------
				 * 
				 * In our case, since we have already ran the direct discovery
				 * in the header scanner, we save scan.next_id value, reset it,
				 * call the heuristic function, check its scan.next_id if it
				 * was set, if it was, then use that instead. Otherwise if it
				 * wasn't restore the original next_id and continue on normally.
				 */
				if (scanner->sc_flags[scan.id] & FLAG_HEURISTIC_PRE_BINDING) {
#ifdef DEBUG
					debug_scan("heurists_pre", &scan);
#endif

					int saved_next_id = scan.next_id;
					scan.next_id = PAYLOAD_ID;

					for (int i = 0; i < MAX_ID_COUNT; i++) {
						native_validate_func_t validate_func;
						validate_func
								= scanner->sc_heuristics_table[scan.id][i];

						if (validate_func == NULL) {
							break;
						}

						if ((scan.next_id = validate_func(&scan)) != INVALID) {
							break;
						}
					}

					if (scan.next_id == PAYLOAD_ID) {
						scan.next_id = saved_next_id;
					}

				} else if (scan.next_id == PAYLOAD_ID) {
#ifdef DEBUG
					debug_scan("heurists_post", &scan);
#endif
					for (int i = 0; i < MAX_ID_COUNT; i++) {
						native_validate_func_t validate_func;
						validate_func
								= scanner->sc_heuristics_table[scan.id][i];

						if (validate_func == NULL) {
							break;
						}

#ifdef DEBUG
						debug_trace("heurists_post", "[%d]", i);
#endif
						if ((scan.next_id = validate_func(&scan)) != INVALID) {

#ifdef DEBUG
							debug_scan("heurists_post::found", &scan);
#endif

							break;
						}
					}
				}

				/* Restore these 2 critical properties */
				scan.offset = saved_offset;
				scan.length = saved_length;
			}

			/******************************************************
			 * ****************************************************
			 * * Now record discovered information in structures
			 * ****************************************************
			 ******************************************************/
			record_header(&scan);

#ifdef DEBUG
			debug_header("header_t", scan.header - 1);
#endif
		} // End if len != 0

#ifdef DEBUG
		debug_scan("loop-bottom", &scan);
#endif

		scan.id = scan.next_id;
		scan.offset += scan.length + scan.hdr_gap;
		scan.length = 0;
		scan.next_id = PAYLOAD_ID;

		if (scan.offset >= scan.buf_len) {
			scan.id = END_OF_HEADERS;
		}

	} // End for loop

	/* record number of header entries found */
	//	scan.packet->pkt_header_count = count;

	process_flow_key(&scan);

#ifdef DEBUG
	debug_trace("loop-finished",
			"header_count=%d offset=%d header_map=0x%X",
			scan.packet->pkt_header_count, scan.offset,
			scan.packet->pkt_header_map);
	debug_exit("scan()");
#endif

	return scan.offset;
} // End scan()
Пример #9
0
/* Set the exteded attribute */ 
int plfs_setxattr(Plfs_fd *fd, const void *value, const char *key, size_t len) {
    debug_enter(__FUNCTION__,fd->getPath());
    int ret = fd->setxattr(value, key, len);
    debug_exit(__FUNCTION__,fd->getPath(),ret);
    return ret;
}
Пример #10
0
FeedListView *
feed_list_view_create (GtkTreeView *treeview)
{
	GtkCellRenderer		*titleRenderer, *countRenderer;
	GtkCellRenderer		*iconRenderer;
	GtkTreeViewColumn 	*column, *column2;
	GtkTreeSelection	*select;

	debug_enter ("feed_list_view_create");

	/* Set up store */
	g_assert (NULL == flv);
	flv = FEED_LIST_VIEW (g_object_new (FEED_LIST_VIEW_TYPE, NULL));

	flv->treeview = treeview;
	flv->feedstore = gtk_tree_store_new (FS_LEN,
	                                     G_TYPE_STRING,
   	                                     G_TYPE_ICON,
	                                     G_TYPE_POINTER,
	                                     G_TYPE_UINT,
	                                     G_TYPE_STRING);

	gtk_tree_view_set_model (GTK_TREE_VIEW (flv->treeview), GTK_TREE_MODEL (flv->feedstore));

	/* Prepare filter */
	flv->filter = gtk_tree_model_filter_new (GTK_TREE_MODEL (flv->feedstore), NULL);
	gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (flv->filter),
	                                        feed_list_view_filter_visible_function,
	                                        NULL,
	                                        NULL);

	g_signal_connect (G_OBJECT (flv->feedstore), "row-changed",
                      G_CALLBACK (feed_list_view_row_changed_cb), flv);

	/* we render the icon/state, the feed title and the unread count */
	iconRenderer  = gtk_cell_renderer_pixbuf_new ();
	titleRenderer = gtk_cell_renderer_text_new ();
	countRenderer = gtk_cell_renderer_text_new ();

	gtk_cell_renderer_set_alignment (countRenderer, 1.0, 0);

	column  = gtk_tree_view_column_new ();
	column2 = gtk_tree_view_column_new ();

	gtk_tree_view_column_pack_start (column, iconRenderer, FALSE);
	gtk_tree_view_column_pack_start (column, titleRenderer, TRUE);
	gtk_tree_view_column_pack_end   (column2, countRenderer, FALSE);

	gtk_tree_view_column_add_attribute (column, iconRenderer, "gicon", FS_ICON);
	gtk_tree_view_column_add_attribute (column, titleRenderer, "markup", FS_LABEL);
	gtk_tree_view_column_add_attribute (column2, countRenderer, "markup", FS_COUNT);

	gtk_tree_view_column_set_expand (column, TRUE);
	gtk_tree_view_column_set_sizing (column, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
	gtk_tree_view_column_set_sizing (column2, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
	gtk_tree_view_append_column (flv->treeview, column);
	gtk_tree_view_append_column (flv->treeview, column2);

	g_object_set (titleRenderer, "ellipsize", PANGO_ELLIPSIZE_END, NULL);

	g_signal_connect (G_OBJECT (flv->treeview), "row-activated",   G_CALLBACK (feed_list_view_row_activated_cb), flv);
	g_signal_connect (G_OBJECT (flv->treeview), "key-press-event", G_CALLBACK (feed_list_view_key_press_cb), flv);

	select = gtk_tree_view_get_selection (flv->treeview);
	gtk_tree_selection_set_mode (select, GTK_SELECTION_SINGLE);

	g_signal_connect (G_OBJECT (select), "changed",
	                  G_CALLBACK (feed_list_view_selection_changed_cb),
                	  flv);

	conf_get_bool_value (REDUCED_FEEDLIST, &flv->feedlist_reduced_unread);
	if (flv->feedlist_reduced_unread)
		feed_list_view_reduce_mode_changed ();	/* before menu setup for reduced mode check box to be correct */

	ui_dnd_setup_feedlist (flv->feedstore);
	liferea_shell_update_feed_menu (TRUE, FALSE, FALSE);
	liferea_shell_update_allitems_actions (FALSE, FALSE);

	debug_exit ("feed_list_view_create");

	return flv;
}
Пример #11
0
/**
 * General feed source parsing function. Parses the passed feed source
 * and tries to determine the source type. 
 *
 * @param ctxt		feed parsing context
 *
 * @returns FALSE if auto discovery is indicated, 
 *          TRUE if feed type was recognized and parsing was successful
 */
gboolean
feed_parse (feedParserCtxtPtr ctxt)
{
	xmlNodePtr	cur;
	gboolean	success = FALSE;

	debug_enter("feed_parse");

	g_assert(NULL == ctxt->items);
	
	ctxt->failed = TRUE;	/* reset on success ... */

	if(ctxt->feed->parseErrors)
		g_string_truncate(ctxt->feed->parseErrors, 0);
	else
		ctxt->feed->parseErrors = g_string_new(NULL);

	/* try to parse buffer with XML and to create a DOM tree */	
	do {
		if(NULL == xml_parse_feed (ctxt)) {
			g_string_append_printf (ctxt->feed->parseErrors, _("XML error while reading feed! Feed \"%s\" could not be loaded!"), subscription_get_source (ctxt->subscription));
			break;
		}
		
		if(NULL == (cur = xmlDocGetRootElement(ctxt->doc))) {
			g_string_append(ctxt->feed->parseErrors, _("Empty document!"));
			break;
		}
		
		while(cur && xmlIsBlankNode(cur)) {
			cur = cur->next;
		}
		
		if(!cur)
			break;
				
		if(!cur->name) {
			g_string_append(ctxt->feed->parseErrors, _("Invalid XML!"));
			break;
		}

		/* determine the syndication format and start parser */
		GSList *handlerIter = feed_parsers_get_list ();
		while(handlerIter) {
			feedHandlerPtr handler = (feedHandlerPtr)(handlerIter->data);
			if(handler && handler->checkFormat && (*(handler->checkFormat))(ctxt->doc, cur)) {
				/* free old temp. parsing data, don't free right after parsing because
				   it can be used until the last feed request is finished, move me 
				   to the place where the last request in list otherRequests is 
				   finished :-) */
				g_hash_table_destroy(ctxt->tmpdata);
				ctxt->tmpdata = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, g_free);
				
				/* we always drop old metadata */
				metadata_list_free(ctxt->subscription->metadata);
				ctxt->subscription->metadata = NULL;
				ctxt->failed = FALSE;

				ctxt->feed->fhp = handler;
				(*(handler->feedParser))(ctxt, cur);		/* parse it */

				break;
			}
			handlerIter = handlerIter->next;
		}
	} while(0);
	
	/* if the given URI isn't valid we need to start auto discovery */
	if(ctxt->failed)
		feed_parser_auto_discover (ctxt);

	if(ctxt->failed) {
		/* Autodiscovery failed */
		/* test if we have a HTML page */
		if((strstr(ctxt->data, "<html>") || strstr(ctxt->data, "<HTML>") ||
		    strstr(ctxt->data, "<html ") || strstr(ctxt->data, "<HTML "))) {
			debug0(DEBUG_UPDATE, "HTML document detected!");
			g_string_append(ctxt->feed->parseErrors, _("Source points to HTML document."));
		} else {
			debug0(DEBUG_UPDATE, "neither a known feed type nor a HTML document!");
			g_string_append(ctxt->feed->parseErrors, _("Could not determine the feed type."));
		}
	} else {
		debug1(DEBUG_UPDATE, "discovered feed format: %s", feed_type_fhp_to_str(ctxt->feed->fhp));
		success = TRUE;
	}
	
	if(ctxt->doc) {
		xmlFreeDoc(ctxt->doc);
		ctxt->doc = NULL;
	}
		
	debug_exit("feed_parse");
	
	return success;
}