Ryo SHIMIZU
furyo****@users*****
Thu Feb 23 22:29:03 JST 2006
Index: kazehakase/src/utils/rast-search.c diff -u /dev/null kazehakase/src/utils/rast-search.c:1.1 --- /dev/null Thu Feb 23 22:29:03 2006 +++ kazehakase/src/utils/rast-search.c Thu Feb 23 22:29:03 2006 @@ -0,0 +1,542 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* + * Copyright (C) 2006 Ryo SHIMIZU + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#include <string.h> +#include <ctype.h> +#include <glib/gi18n.h> + +#include "kazehakase.h" +#include "utils/utils.h" +#include "glib-utils.h" +#include "rast-search.h" +#include "egg-pixbuf-thumbnail.h" + + +#define RAST_URI "http://projects.netlab.jp/rast/" +#define DTD "<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">" +#define HEAD "<head>\n" \ + " <title>Full-text search in history</title>\n" \ + " <link rel=\"stylesheet\" type=\"text/css\" href=\"history-search:?css=search-result.css\">\n" \ + "</head>\n" +#define HEADER "" +#define CONTENT "<div class=\"content\">\n" \ + " <div class=\"header\"><span class=\"title\"><a href=\"%s\">%s</a></span></div>\n" \ + " <div class=\"summary\"><img src=\"%s\" class=\"thumbnail\">\n" \ + " <span class=\"sentence\">%s</span>\n" \ + " </div>\n" \ + " <div class=\"footer\">\n" \ + " <span class=\"uri\">%s</span>\n" \ + " <span class=\"cache\"><a href=\"%s\">cache</a></span>\n" \ + " <span class=\"date\">%s</span>\n" \ + " </div>\n" \ + "</div>\n" +#define FOOTER "<div class=\"footer\">\n" \ + "Powered by <a href=\"%s\">Rast</a> version %s\n" \ + "</div>\n" + +static gchar *rast_get_version (void); +gchar *get_value (const gchar *line); + +static gboolean +rast_execute_search_command(const gchar *search_text, gint *standard_output) +{ + gboolean ret; + const gchar *rast_cmd = "rast search "; + gchar *command; + gint argc; + gchar **argv = NULL; + GSpawnFlags flags; + GPid pid; + gint err; + gchar **split = NULL; + gchar *join = NULL; + gint max_results = 20, num_summary = 128; + gchar *except_word; + gchar **except_keywords = NULL; + + KZ_CONF_GET("History", "num_summary", num_summary, INT); + KZ_CONF_GET("History", "max_results", max_results, INT); + + split = g_strsplit(search_text, " ", -1); + if (split) + { + join = g_strjoinv(" & ", split); + g_strfreev(split); + } + + except_word = KZ_CONF_GET_STR("History", "except_keyword"); + if (except_word && *except_word) + { + except_keywords = g_strsplit(except_word, ",", -1); + g_free(except_word); + except_word = g_strjoinv(" - ", except_keywords); + g_strfreev(except_keywords); + + command = g_strdup_printf("%s --num-items %d --summary-nchars %d '%s - %s' %s%s ", + rast_cmd, + max_results, + num_summary, + join, + except_word, + g_get_home_dir(), + HISTORY_INDEX); + g_free(except_word); + } + else + { + command = g_strdup_printf("%s --num-items %d --summary-nchars %d '%s' %s%s", + rast_cmd, + max_results, + num_summary, + join, + g_get_home_dir(), + HISTORY_INDEX" "); + } + + if (join) + g_free(join); + + g_shell_parse_argv(command, + &argc, + &argv, + NULL); + + flags = G_SPAWN_SEARCH_PATH; + ret = g_spawn_async_with_pipes(NULL, + argv, + NULL, + flags, + NULL, + NULL, + &pid, + NULL, + standard_output, + &err, + NULL); + g_strfreev(argv); + g_free(command); + + return ret; +} + + +static gchar * +rast_create_search_result_html (gint out, const gchar *text) +{ + GIOChannel *io; + gchar *line; + gsize length; + gchar *title = NULL, *uri = NULL, *date = NULL, *desc = NULL; + gchar *cache_link = NULL; + gchar *rastversion = rast_get_version(); + GString *html; + + io = g_io_channel_unix_new(out); + g_io_channel_set_encoding(io, NULL, NULL); + + html = g_string_sized_new(0); + + g_string_append(html, DTD"\n"); + g_string_append(html, "<html>\n"); + g_string_append(html, HEAD); + g_string_append(html, "<body>\n"); + + g_string_append_printf(html, "<h1>Search results for %s</h1>", + text); + + while (g_io_channel_read_line(io, &line, &length, NULL, NULL) == G_IO_STATUS_NORMAL) + { + if (g_str_has_prefix(line, "uri :")) + { + size_t len; + gchar *dirname = g_strconcat(g_get_home_dir(), + HISTORY_DIR, + NULL); + len = strlen(dirname); + + cache_link = get_value(line); + g_print("%s\n", cache_link); + g_print("%s\n", dirname); + uri = create_uri_from_filename(cache_link + + strlen("file://") + + len); + g_free(dirname); + } + else if (g_str_has_prefix(line, "summary :")) + { + gchar *thumb_filename, *thumb_uri; + gchar *summary = get_value(line); + + desc = remove_tag(summary, g_strlen(summary)); + thumb_filename = egg_pixbuf_get_thumb_filename(uri, + EGG_PIXBUF_THUMB_LARGE); + thumb_uri = g_strdup_printf("history-search:?image=%s", + thumb_filename); + g_string_append_printf(html, + CONTENT, + uri, + title, + thumb_uri, /* thumbnail */ + desc, + uri, + cache_link, + date); + + g_free(desc); + g_free(title); + g_free(uri); + g_free(date); + g_free(cache_link); + g_free(summary); + g_free(thumb_filename); + g_free(thumb_uri); + } + else if (g_str_has_prefix(line, "title :")) + { + title = get_value(line); + } + else if (g_str_has_prefix(line, "last_modified :")) + { + date = get_value(line); + } + g_free(line); + } + g_io_channel_unref(io); + g_string_append_printf(html, FOOTER, RAST_URI, rastversion); + g_string_append(html, "</body></html>"); + + if (rastversion) + g_free(rastversion); + return g_string_free(html, FALSE); +} + + +gchar * +rast_get_search_result (const gchar *text) +{ + gint out; + + if (!text) return NULL; + if (!exists_search_cmd) return NULL; + + if (!rast_execute_search_command(text, &out)) + return NULL; + + return rast_create_search_result_html(out, text); +} + +gboolean +rast_update_index (gpointer data) +{ + const gchar *rast_register = "rast register "; + gchar *index_dir; + gchar *command; + gint argc; + gchar **argv = NULL; + GSpawnFlags flags; + GPid pid; + + index_dir = g_strconcat(g_get_home_dir(), HISTORY_INDEX, NULL); + + command = g_strconcat(rast_register, + index_dir, + " ", + (gchar*)data, + NULL); + g_free(index_dir); + + g_shell_parse_argv(command, + &argc, + &argv, + NULL); + + flags = G_SPAWN_SEARCH_PATH | + G_SPAWN_STDOUT_TO_DEV_NULL; + g_spawn_async(NULL, + argv, + NULL, + flags, + NULL, + NULL, + &pid, + NULL); + g_strfreev(argv); + g_free(command); + + g_free(data); + + return FALSE; +} + + +gboolean +rast_purge_index (void) +{ + const gchar *estpurge = "rast delete"; + gchar *command; + gint argc; + gchar **argv = NULL; + GSpawnFlags flags; + GPid pid; + + /* purge index */ + flags = G_SPAWN_SEARCH_PATH | + G_SPAWN_STDOUT_TO_DEV_NULL; + command = g_strconcat(estpurge, + g_get_home_dir(), + HISTORY_INDEX, + NULL); + + g_shell_parse_argv(command, + &argc, + &argv, + NULL); + flags = G_SPAWN_SEARCH_PATH | + G_SPAWN_STDOUT_TO_DEV_NULL; + + g_spawn_async(NULL, + argv, + NULL, + flags, + NULL, + NULL, + &pid, + NULL); + + g_strfreev(argv); + g_free(command); + + return FALSE; +} + +GPid +rast_optimize_index (void) +{ + const gchar *estoptimize = "rast optimize "; + gchar *command; + gint argc; + gchar **argv = NULL; + GSpawnFlags flags; + GPid pid; + + /* optimize index process */ + command = g_strconcat(estoptimize, + g_get_home_dir(), + HISTORY_INDEX, + NULL); + + g_shell_parse_argv(command, + &argc, + &argv, + NULL); + flags = G_SPAWN_SEARCH_PATH | + G_SPAWN_STDOUT_TO_DEV_NULL; + + g_spawn_async(NULL, + argv, + NULL, + flags, + NULL, + NULL, + &pid, + NULL); + g_strfreev(argv); + g_free(command); + + return pid; +} + +static gchar* +rast_get_version (void) +{ + gchar *version; + const gchar *rastversion = "rast-config --version"; + gint argc; + gchar **argv = NULL; + GSpawnFlags flags; + GPid pid; + gint out, err; + gboolean ret; + GIOChannel *io; + gsize length; + + if (!exists_search_cmd) return NULL; + + g_shell_parse_argv(rastversion, + &argc, + &argv, + NULL); + + flags = G_SPAWN_SEARCH_PATH; + ret = g_spawn_async_with_pipes(NULL, + argv, + NULL, + flags, + NULL, + NULL, + &pid, + NULL, + &out, + &err, + NULL); + g_strfreev(argv); + if (!ret) return NULL; + + io = g_io_channel_unix_new(out); + g_io_channel_set_encoding(io, NULL, NULL); + g_io_channel_read_line(io, &version, &length, NULL, NULL); + g_io_channel_shutdown(io, TRUE, NULL); + g_io_channel_unref(io); + + return version; +} + +static KzBookmark * +rast_create_search_result_bookmark (gint out, const gchar *text) +{ + GIOChannel *io; + gchar *line; + gsize length; + gchar *title = NULL, *uri = NULL, *desc = NULL; + KzBookmark *result; + + io = g_io_channel_unix_new(out); + g_io_channel_set_encoding(io, NULL, NULL); + + result = kz_bookmark_pure_folder_new(); + + while (g_io_channel_read_line(io, &line, &length, NULL, NULL) == G_IO_STATUS_NORMAL) + { + if (g_str_has_prefix(line, "</document>")) + { + KzBookmark *child; + child = kz_bookmark_new_with_attrs(title, uri, desc); + kz_bookmark_append(result, child); + g_object_unref(child); + g_free(desc); + g_free(title); + g_free(uri); + } + else if (g_str_has_prefix(line, "<uri>")) + { + gchar *dirname, *orig_uri; + gchar *link; + size_t len; + link = xml_get_attr(line, "uri"); + dirname = g_strconcat(g_get_home_dir(), + HISTORY_DIR, + NULL); + len = strlen(dirname); + orig_uri = create_uri_from_filename(link + strlen("file://") + len); + uri = url_decode(orig_uri); + g_free(orig_uri); + g_free(dirname); + g_free(link); + } + else if (g_str_has_prefix(line, "<title>")) + { + title = xml_get_content(line); + } + else if (g_str_has_prefix(line, "<summary")) + { + gchar *summary = xml_get_content(line); + desc = remove_tag(summary, g_strlen(summary)); + g_free(summary); + } + g_free(line); + } + g_io_channel_unref(io); + + return result; +} + +KzBookmark * +rast_get_search_result_bookmark (const gchar *text) +{ + gint out; + + if (!text) return NULL; + if (!exists_search_cmd) return NULL; + + if (!rast_execute_search_command(text, &out)) + return NULL; + + return rast_create_search_result_bookmark(out, text); +} + +void +rast_make_index(void) +{ + const gchar *rast_create = "rast create --preserve-text --property=title:string:search "; + gchar *command; + gint argc; + gchar **argv = NULL; + GSpawnFlags flags; + GPid pid; + + command = g_strconcat(rast_create, + g_get_home_dir(), + HISTORY_INDEX" ", + g_get_home_dir(), + HISTORY_DIR, + NULL); + + g_shell_parse_argv(command, + &argc, + &argv, + NULL); + flags = G_SPAWN_SEARCH_PATH | + G_SPAWN_STDOUT_TO_DEV_NULL; + + g_spawn_async(NULL, + argv, + NULL, + flags, + NULL, + NULL, + &pid, + NULL); + g_strfreev(argv); + g_free(command); +} + +gboolean +rast_exist_index_dir(void) +{ + gchar *index_dir; + gboolean exist = FALSE; + + index_dir = g_build_filename(g_get_home_dir(), + HISTORY_INDEX, NULL); + exist = g_file_test(index_dir, G_FILE_TEST_IS_DIR); + g_free(index_dir); + + return exist; +} + +gchar *get_value (const gchar *line) +{ + gchar *p; + + p = strchr(line, ':'); + p += 2; + + return g_strchomp(g_strdup(p)); +} Index: kazehakase/src/utils/rast-search.h diff -u /dev/null kazehakase/src/utils/rast-search.h:1.1 --- /dev/null Thu Feb 23 22:29:03 2006 +++ kazehakase/src/utils/rast-search.h Thu Feb 23 22:29:03 2006 @@ -0,0 +1,41 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ + +/* + * Copyright (C) 2006 Ryo SHIMIZU + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef __RASTSEARCH_H__ +#define __RASTSEARCH_H__ + +#include <glib.h> +#include <kz-bookmark.h> + +G_BEGIN_DECLS + +gchar *rast_get_search_result (const gchar* text); + +KzBookmark *rast_get_search_result_bookmark (const gchar* text); + +gboolean rast_update_index (gpointer data); +gboolean rast_purge_index (void); +GPid rast_optimize_index (void); +void rast_make_index (void); +gboolean rast_exist_index_dir (void); + +G_END_DECLS + +#endif /* __RASTSEARCH_H__ */