/* This file is part of GNUnet. (C) 2005, 2006 Christian Grothoff (and other contributing authors) GNUnet 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. GNUnet 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 GNUnet; see the file COPYING. If not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /** * @file src/plugins/fs/namespace.c * @brief code for operations with namespaces * @author Christian Grothoff */ #include "platform.h" #include "gnunetgtk_common.h" #include "fs.h" #include "helper.h" #include "meta.h" #include "namespace.h" #include #include #include #include /** * @brief linked list of pages in the search notebook */ typedef struct NL { struct NL * next; GtkWidget * treeview; GtkWidget * namespacepage; GtkTreeModel * model; GtkWidget * anonymityButton; char * name; HashCode512 id; struct ECRS_MetaData * meta; } NamespaceList; static NamespaceList * head; static GladeXML * metaXML; static GtkWidget * makeNamespaceFrame(GtkWidget ** treeview, GtkWidget ** anonSpin) { GtkWidget * child; GtkWidget * resultList; GtkCellRenderer * renderer; GtkListStore * model; GladeXML * namespaceXML; GtkTreeViewColumn * column; int col; DEBUG_BEGIN(); namespaceXML = glade_xml_new(getGladeFileName(), "namespaceContentFrame", PACKAGE_NAME); connectGladeWithPlugins(namespaceXML); child = extractMainWidgetFromWindow(namespaceXML, "namespaceContentFrame"); resultList = glade_xml_get_widget(namespaceXML, "namespaceContentFrameTreeView"); *anonSpin = glade_xml_get_widget(namespaceXML, "namespaceAnonymitySpinButton"); if (treeview != NULL) (*treeview) = GTK_WIDGET(GTK_TREE_VIEW(resultList)); model = gtk_list_store_new(IN_NAMESPACE_NUM, G_TYPE_STRING, /* (file)name */ G_TYPE_UINT64, /* size */ G_TYPE_STRING, /* human-readable size */ G_TYPE_STRING, /* description */ G_TYPE_STRING, /* mime-type */ G_TYPE_STRING, /* last-ID */ G_TYPE_STRING, /* next-ID */ G_TYPE_STRING, /* pub-freq */ G_TYPE_STRING, /* next pub date */ G_TYPE_POINTER, /* URI */ G_TYPE_POINTER); /* META */ gtk_tree_view_set_model(GTK_TREE_VIEW(resultList), GTK_TREE_MODEL(model)); gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(resultList)), GTK_SELECTION_MULTIPLE); renderer = gtk_cell_renderer_text_new(); col = gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(resultList), -1, _("Filename"), renderer, "text", IN_NAMESPACE_FILENAME, NULL); column = gtk_tree_view_get_column(GTK_TREE_VIEW(resultList), col - 1); gtk_tree_view_column_set_resizable(column, TRUE); gtk_tree_view_column_set_clickable(column, TRUE); gtk_tree_view_column_set_reorderable(column, TRUE); gtk_tree_view_column_set_sort_column_id(column, IN_NAMESPACE_FILENAME); /*gtk_tree_view_column_set_sort_indicator(column, TRUE);*/ gtk_tree_view_column_set_resizable(gtk_tree_view_get_column(GTK_TREE_VIEW(resultList), col - 1), TRUE); renderer = gtk_cell_renderer_text_new(); g_object_set (renderer, "xalign", 1.00, NULL); col = gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(resultList), -1, _("Filesize"), renderer, "text", IN_NAMESPACE_HSIZE, NULL); column = gtk_tree_view_get_column(GTK_TREE_VIEW(resultList), col - 1); gtk_tree_view_column_set_resizable(column, TRUE); gtk_tree_view_column_set_clickable(column, TRUE); gtk_tree_view_column_set_reorderable(column, TRUE); gtk_tree_view_column_set_sort_column_id(column, IN_NAMESPACE_SIZE); /*gtk_tree_view_column_set_sort_indicator(column, TRUE);*/ gtk_tree_view_column_set_resizable(gtk_tree_view_get_column(GTK_TREE_VIEW(resultList), col - 1), TRUE); renderer = gtk_cell_renderer_text_new(); col = gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(resultList), -1, _("Description"), renderer, "text", IN_NAMESPACE_DESCRIPTION, NULL); column = gtk_tree_view_get_column(GTK_TREE_VIEW(resultList), col - 1); gtk_tree_view_column_set_resizable(column, TRUE); gtk_tree_view_column_set_clickable(column, TRUE); gtk_tree_view_column_set_reorderable(column, TRUE); gtk_tree_view_column_set_sort_column_id(column, IN_NAMESPACE_DESCRIPTION); /*gtk_tree_view_column_set_sort_indicator(column, TRUE);*/ gtk_tree_view_column_set_resizable(gtk_tree_view_get_column(GTK_TREE_VIEW(resultList), col - 1), TRUE); renderer = gtk_cell_renderer_text_new(); col = gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(resultList), -1, _("Mime-type"), renderer, "text", IN_NAMESPACE_MIMETYPE, NULL); column = gtk_tree_view_get_column(GTK_TREE_VIEW(resultList), col - 1); gtk_tree_view_column_set_resizable(column, TRUE); gtk_tree_view_column_set_clickable(column, TRUE); gtk_tree_view_column_set_reorderable(column, TRUE); gtk_tree_view_column_set_sort_column_id(column, IN_NAMESPACE_MIMETYPE); /*gtk_tree_view_column_set_sort_indicator(column, TRUE);*/ gtk_tree_view_column_set_resizable(gtk_tree_view_get_column(GTK_TREE_VIEW(resultList), col - 1), TRUE); renderer = gtk_cell_renderer_text_new(); col = gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(resultList), -1, _("Publication Frequency"), renderer, "text", IN_NAMESPACE_PUB_FREQ_STRING, NULL); column = gtk_tree_view_get_column(GTK_TREE_VIEW(resultList), col - 1); gtk_tree_view_column_set_resizable(column, TRUE); gtk_tree_view_column_set_clickable(column, TRUE); gtk_tree_view_column_set_reorderable(column, TRUE); gtk_tree_view_column_set_sort_column_id(column, IN_NAMESPACE_PUB_FREQ_STRING); /*gtk_tree_view_column_set_sort_indicator(column, TRUE);*/ gtk_tree_view_column_set_resizable(gtk_tree_view_get_column(GTK_TREE_VIEW(resultList), col - 1), TRUE); renderer = gtk_cell_renderer_text_new(); col = gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(resultList), -1, _("Next Publication Date"), renderer, "text", IN_NAMESPACE_PUB_DATE_STRING, NULL); column = gtk_tree_view_get_column(GTK_TREE_VIEW(resultList), col - 1); gtk_tree_view_column_set_reorderable(column, TRUE); gtk_tree_view_column_set_resizable(column, TRUE); gtk_tree_view_column_set_clickable(column, TRUE); gtk_tree_view_column_set_sort_column_id(column, IN_NAMESPACE_PUB_DATE_STRING); /*gtk_tree_view_column_set_sort_indicator(column, TRUE);*/ gtk_tree_view_column_set_resizable(gtk_tree_view_get_column(GTK_TREE_VIEW(resultList), col - 1), TRUE); renderer = gtk_cell_renderer_text_new(); col = gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(resultList), -1, _("Last ID"), renderer, "text", IN_NAMESPACE_LAST_STRING, NULL); column = gtk_tree_view_get_column(GTK_TREE_VIEW(resultList), col - 1); gtk_tree_view_column_set_reorderable(column, TRUE); gtk_tree_view_column_set_resizable(column, TRUE); gtk_tree_view_column_set_resizable(gtk_tree_view_get_column(GTK_TREE_VIEW(resultList), col - 1), TRUE); renderer = gtk_cell_renderer_text_new(); col = gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(resultList), -1, _("Next ID"), renderer, "text", IN_NAMESPACE_NEXT_STRING, NULL); column = gtk_tree_view_get_column(GTK_TREE_VIEW(resultList), col - 1); gtk_tree_view_column_set_reorderable(column, TRUE); gtk_tree_view_column_set_resizable(column, TRUE); gtk_tree_view_column_set_resizable(gtk_tree_view_get_column(GTK_TREE_VIEW(resultList), col - 1), TRUE); UNREF(namespaceXML); DEBUG_END(); return child; } /** * Add the given content to the globally available * content model. Check that it is not already * present! */ static void * updateView(void * cls) { const ECRS_FileInfo * fi = cls; GtkTreeIter iter; char * filename; char * uriString; unsigned long long size; char * size_h; GtkWidget * contentList; GtkTreeModel * model; contentList = glade_xml_get_widget(getMainXML(), "availableContentList"); model = gtk_tree_view_get_model(GTK_TREE_VIEW(contentList)); filename = ECRS_getFirstFromMetaData(fi->meta, EXTRACTOR_FILENAME, EXTRACTOR_TITLE, EXTRACTOR_DESCRIPTION, EXTRACTOR_SUBJECT, EXTRACTOR_ARTIST, EXTRACTOR_AUTHOR, EXTRACTOR_PUBLISHER, EXTRACTOR_CREATOR, EXTRACTOR_PRODUCER, EXTRACTOR_UNKNOWN, -1); if (filename == NULL) { filename = STRDUP(_("no name given")); } else { char * dotdot; while (NULL != (dotdot = strstr(filename, ".."))) dotdot[0] = dotdot[1] = '_'; filename = validate_utf8(filename); } if (ECRS_isFileUri(fi->uri)) size = ECRS_fileSize(fi->uri); else size = 0; uriString = ECRS_uriToString(fi->uri); gtk_list_store_append(GTK_LIST_STORE(model), &iter); size_h = string_get_fancy_byte_size(size); gtk_list_store_set(GTK_LIST_STORE(model), &iter, NAMESPACE_FILENAME, filename, NAMESPACE_SIZE, size, NAMESPACE_HSIZE, size_h, NAMESPACE_URISTRING, uriString, NAMESPACE_URI, ECRS_dupUri(fi->uri), NAMESPACE_META, ECRS_dupMetaData(fi->meta), -1); FREE(size_h); FREE(filename); FREE(uriString); return NULL; } /** * Add the given content to the globally available * content model. Check that it is not already * present! */ static int updateViewSave(const ECRS_FileInfo * fi, const HashCode512 * key, int isRoot, void * closure) { gtkSaveCall(&updateView, (void*) fi); return OK; } static void * clearContentList(void * mdl) { GtkTreeModel * model = GTK_TREE_MODEL(mdl); struct ECRS_URI * uri; struct ECRS_MetaData * meta; GtkTreeIter iter; DEBUG_BEGIN(); if (gtk_tree_model_get_iter_first(model, &iter)) { do { gtk_tree_model_get(model, &iter, NAMESPACE_URI, &uri, NAMESPACE_META, &meta, -1); ECRS_freeUri(uri); ECRS_freeMetaData(meta); gtk_list_store_set(GTK_LIST_STORE(model), &iter, NAMESPACE_URI, NULL, NAMESPACE_META, NULL, -1); } while (gtk_list_store_remove(GTK_LIST_STORE(model), &iter)); } DEBUG_END(); return NULL; } /** * Update the model that lists the content of a namespace: * add this content. * * @param uri URI of the last content published * @param lastId the ID of the last publication * @param nextId the ID of the next update * @param publicationFrequency how often are updates scheduled? * @param nextPublicationTime the scheduled time for the * next update (0 for sporadic updates) * @return OK to continue iteration, SYSERR to abort */ static int addNamespaceContentToModel(void * cls, const ECRS_FileInfo * fi, const HashCode512 * lastId, const HashCode512 * nextId, TIME_T publicationFrequency, TIME_T nextPublicationTime) { GtkListStore * model = GTK_LIST_STORE(cls); GtkTreeIter iter; char * filename; char * desc; char * mime; char * uriString; EncName last; EncName next; char * freq; char * date; unsigned long long size; char * size_h; DEBUG_BEGIN(); filename = ECRS_getFirstFromMetaData(fi->meta, EXTRACTOR_FILENAME, EXTRACTOR_TITLE, EXTRACTOR_ARTIST, EXTRACTOR_AUTHOR, EXTRACTOR_PUBLISHER, EXTRACTOR_CREATOR, EXTRACTOR_PRODUCER, EXTRACTOR_UNKNOWN, -1); if (filename == NULL) filename = STRDUP(_("no name given")); else { char *dotdot; while (NULL != (dotdot = strstr(filename, ".."))) dotdot[0] = dotdot[1] = '_'; } desc = ECRS_getFirstFromMetaData(fi->meta, EXTRACTOR_DESCRIPTION, EXTRACTOR_GENRE, EXTRACTOR_ALBUM, EXTRACTOR_COMMENT, EXTRACTOR_SUBJECT, EXTRACTOR_FORMAT, EXTRACTOR_SIZE, EXTRACTOR_KEYWORDS, -1); if (desc == NULL) desc = STRDUP(""); mime = ECRS_getFromMetaData(fi->meta, EXTRACTOR_MIMETYPE); if (mime == NULL) mime = STRDUP(_("unknown")); if (ECRS_isFileUri(fi->uri)) size = ECRS_fileSize(fi->uri); else size = 0; uriString = ECRS_uriToString(fi->uri); hash2enc(lastId, &last); if (nextId != NULL) hash2enc(nextId, &next); else memset(&next, 0, sizeof(EncName)); if (publicationFrequency == ECRS_SBLOCK_UPDATE_SPORADIC) date = STRDUP(_("unspecified")); else if (publicationFrequency == ECRS_SBLOCK_UPDATE_NONE) date = STRDUP(_("never")); else date = GN_CTIME(&nextPublicationTime); freq = updateIntervalToString(publicationFrequency); size_h = string_get_fancy_byte_size(size); gtk_list_store_append(model, &iter); gtk_list_store_set(model, &iter, IN_NAMESPACE_FILENAME, filename, IN_NAMESPACE_SIZE, size, IN_NAMESPACE_HSIZE, size_h, IN_NAMESPACE_DESCRIPTION, desc, IN_NAMESPACE_MIMETYPE, mime, IN_NAMESPACE_LAST_STRING, &last, IN_NAMESPACE_NEXT_STRING, &next, IN_NAMESPACE_PUB_FREQ_STRING, freq, IN_NAMESPACE_PUB_DATE_STRING, date, IN_NAMESPACE_URI, ECRS_dupUri(fi->uri), IN_NAMESPACE_META, ECRS_dupMetaData(fi->meta), -1); FREE(size_h); FREE(filename); FREE(uriString); FREE(freq); FREE(date); FREE(mime); DEBUG_END(); return OK; } /** * Add a tab for the given namespace. */ static int addTabForNamespace(void * unused, const char * namespaceName, const HashCode512 * namespaceId, const struct ECRS_MetaData * md, int rating) { NamespaceList * list; GtkWidget * label; GtkWidget * spin; GtkWidget * notebook; GtkListStore * model; DEBUG_BEGIN(); label = gtk_label_new(namespaceName); list = MALLOC(sizeof(NamespaceList)); list->name = STRDUP(namespaceName); list->id = *namespaceId; list->meta = ECRS_dupMetaData(md); list->namespacepage = makeNamespaceFrame(&list->treeview, &spin); list->anonymityButton = spin; model = GTK_LIST_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW(list->treeview))); list->model = GTK_TREE_MODEL(model); list->next = head; head = list; notebook = glade_xml_get_widget(getMainXML(), "localNamespacesNotebook"); gtk_notebook_append_page(GTK_NOTEBOOK(notebook), list->namespacepage, label); gtk_widget_show(notebook); NS_listNamespaceContent (ectx, cfg, namespaceName, &addNamespaceContentToModel, model); DEBUG_END(); return OK; } void on_namespacemetaDataDialogKeywordAddButton_clicked_fs(gpointer dummy, GtkWidget * uploadButton) { handleKeywordListUpdate(metaXML, "namespaceKeywordEntry", "namespaceMetaDataDialogKeywordList"); } void on_namespacemetaDataDialogMetaDataAddButton_clicked_fs(gpointer dummy, GtkWidget * uploadButton) { handleMetaDataListUpdate(metaXML, "namespaceMetaDataDialogMetaTypeComboBox", "namespaceMetaDataValueEntry", "namespaceMetaDataDialogMetaDataList"); } void create_namespace_clicked_fs(GtkWidget * dummy1, GtkWidget * dummy2) { const char * namespaceName; GtkWidget * nameLine; GtkWidget * dialog; GtkWidget * spin; struct ECRS_MetaData * meta; struct ECRS_URI * keywordURI; struct ECRS_URI * root; HashCode512 namespaceId; HashCode512 rootEntry; DEBUG_BEGIN(); metaXML = glade_xml_new(getGladeFileName(), "namespaceMetaDataDialog", PACKAGE_NAME); connectGladeWithPlugins(metaXML); dialog = glade_xml_get_widget(metaXML, "namespaceMetaDataDialog"); createMetaDataListTreeView(metaXML, "namespaceMetaDataDialogMetaDataList", NULL, NULL); createKeywordListTreeView(metaXML, "namespaceMetaDataDialogKeywordList", NULL); createMetaTypeComboBox(metaXML, "namespaceMetaDataDialogMetaTypeComboBox"); gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK); if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) { meta = getMetaDataFromList(metaXML, "namespaceMetaDataDialogMetaDataList", NULL); keywordURI = getKeywordURIFromList(metaXML, "namespaceMetaDataDialogKeywordList"); spin = glade_xml_get_widget(metaXML, "namespaceAnonymityspinbutton"); nameLine = glade_xml_get_widget(metaXML, "namespaceRootEntry"); namespaceName = gtk_entry_get_text(GTK_ENTRY(nameLine)); if (namespaceName == NULL) namespaceName = "root"; /* do NOT translate "root"! */ hash(namespaceName, strlen(namespaceName), &rootEntry); nameLine = glade_xml_get_widget(metaXML, "namespaceNameEntry"); namespaceName = gtk_entry_get_text(GTK_ENTRY(nameLine)); root = NS_createNamespace(ectx, cfg, gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(spin)), 1000, /* FIXME: priority */ 999999, /* FIXME: expiration */ namespaceName, meta, keywordURI, &rootEntry); if (root != NULL) { ECRS_getNamespaceId(root, &namespaceId); addTabForNamespace(NULL, namespaceName, &namespaceId, meta, 0); ECRS_freeUri(root); } else { GtkWidget * dialog; dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Failed to create namespace `%s'." "Consult logs, most likely error is" " that a namespace with that name " "already exists."), namespaceName); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); } ECRS_freeMetaData(meta); ECRS_freeUri(keywordURI); } gtk_widget_destroy(dialog); UNREF(metaXML); metaXML = NULL; DEBUG_END(); } void namespaceDelete_clicked_fs(GtkWidget * dummy1, GtkWidget * dummy2) { GtkWidget * notebook; NamespaceList * list; NamespaceList * prev; gint num; GtkWidget * page; GtkWidget * dialog; gint ret; DEBUG_BEGIN(); notebook = glade_xml_get_widget(getMainXML(), "localNamespacesNotebook"); num = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)); if (num == -1) { /* IMPROVE-ME: disable the menu item as long as this may happen! */ dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("No local namespaces available that could be deleted!")); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); return; } page = gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), num); list = head; prev = NULL; while ( (list != NULL) && (list->namespacepage != page) ) { prev = list; list = list->next; } if (list == NULL) { GE_BREAK(ectx, 0); return; } /* open window to ask for confirmation, only then delete */ dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_YES_NO, _("Should the namespace `%s' really be deleted?"), list->name); ret = gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); if (GTK_RESPONSE_YES != ret) return; gtk_notebook_remove_page(GTK_NOTEBOOK(notebook), num); if (prev == NULL) head = list->next; else prev->next = list->next; NS_deleteNamespace(ectx, cfg, list->name); FREE(list->name); ECRS_freeMetaData(list->meta); FREE(list); DEBUG_END(); } typedef struct { unsigned int anonymityLevel; char * namespaceName; TIME_T updateInterval; HashCode512 * lastId; HashCode512 thisId; HashCode512 * nextId; struct ECRS_MetaData * meta; } IUC; /** * Publish the selected file in the * selected namespace. */ static void initiateUpload(GtkTreeModel * model, GtkTreePath * path, GtkTreeIter * iter, gpointer data) { IUC * cls = data; struct ECRS_URI * resultURI; struct ECRS_URI * dst; struct ECRS_MetaData * ometa; struct ECRS_MetaData * meta; NamespaceList * list; ECRS_FileInfo fi; DEBUG_BEGIN(); dst = NULL; meta = cls->meta; gtk_tree_model_get(model, iter, NAMESPACE_URI, &dst, NAMESPACE_META, &ometa, -1); /* FIXME: we may want to optionally combine the metadata from the original file ID (ometa) with the new metadata (cls->meta) here; or if we limit us to one file at a time, show the original metadata immediately with the dialog. */ if (dst == NULL) { GE_BREAK(ectx, 0); return; } resultURI = NS_addToNamespace(ectx, cfg, cls->anonymityLevel, 1000, /* FIXME: priority */ 999999, /* FIXME: expiration */ cls->namespaceName, cls->updateInterval, cls->lastId, &cls->thisId, cls->nextId, dst, meta); if (resultURI != NULL) { list = head; while ( (list != NULL) && (0 != strcmp(cls->namespaceName, list->name)) ) list = list->next; if (list == NULL) { GE_BREAK(ectx, 0); } else { /* update namespace content list! */ fi.uri = dst; fi.meta = meta; addNamespaceContentToModel(list->model, &fi, &cls->thisId, cls->nextId, cls->updateInterval, cls->updateInterval + TIME(NULL)); } ECRS_freeUri(resultURI); } else { infoMessage(YES, _("Failed to insert content into namespace " "(consult logs).\n")); } DEBUG_END(); } void on_namespaceInsertMetaDataDialogMetaDataAddButton_clicked_fs(GtkWidget * dummy1, GtkWidget * dummy2) { handleMetaDataListUpdate(metaXML, "namespaceInsertMetaTypeComboBox", "metaDataValueEntry", "metaDataTreeView"); } void on_namespaceInsertButton_clicked_fs(GtkWidget * dummy1, GtkWidget * dummy2) { const char * identifierName; NamespaceList * list; GtkWidget * nameLine; GtkWidget * page; GtkWidget * notebook; GtkWidget * dialog; struct ECRS_MetaData * meta; HashCode512 nextId; GtkWidget * contentList; GtkTreeSelection * selection; IUC cls; gint num; GtkTreeIter iter; DEBUG_BEGIN(); contentList = glade_xml_get_widget(getMainXML(), "availableContentList"); selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(contentList)); if (0 == gtk_tree_selection_count_selected_rows(selection)) { /* IMPROVE-ME: disable the menu item as long as this may happen! */ dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("You must select some available content for publication first!")); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); return; } if (FALSE == gtk_tree_selection_get_selected(selection, NULL, &iter)) { GE_BREAK(ectx, 0); return; } gtk_tree_model_get(gtk_tree_view_get_model(GTK_TREE_VIEW(contentList)), &iter, NAMESPACE_META, &meta, -1); notebook = glade_xml_get_widget(getMainXML(), "localNamespacesNotebook"); num = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)); GE_ASSERT(ectx, num != -1); page =gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), num); list = head; while ( (list != NULL) && (list->namespacepage != page) ) list = list->next; if (list == NULL) { GE_BREAK(ectx, 0); return; } cls.namespaceName = list->name; metaXML = glade_xml_new(getGladeFileName(), "namespaceInsertDialog", PACKAGE_NAME); connectGladeWithPlugins(metaXML); createMetaDataListTreeView(metaXML, "metaDataTreeView", "namespaceInsertPreview", meta); createMetaTypeComboBox(metaXML, "namespaceInsertMetaTypeComboBox"); dialog = glade_xml_get_widget(metaXML, "namespaceInsertDialog"); gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK); if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) { if (OK != tryParseTimeInterval(metaXML, "updateIntervalComboBoxEntry", &cls.updateInterval)) { gtk_widget_destroy(dialog); UNREF(metaXML); metaXML = NULL; dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("Failed to parse given time interval!")); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); return; } meta = getMetaDataFromList(metaXML, "metaDataTreeView", "namespaceInsertPreview"); cls.anonymityLevel = getSpinButtonValue(metaXML, "anonymitySpinButton"); nameLine = glade_xml_get_widget(metaXML, "namespaceContentIdentifierEntry"); identifierName = gtk_entry_get_text(GTK_ENTRY(nameLine)); if (identifierName == NULL) identifierName = ""; hash(identifierName, strlen(identifierName), &cls.thisId); cls.lastId = NULL; nameLine = glade_xml_get_widget(metaXML, "nextIdentifierEntry"); identifierName = gtk_entry_get_text(GTK_ENTRY(nameLine)); if ( (identifierName == NULL) || (strlen(identifierName) == 0)) { cls.nextId = NULL; } else { hash(identifierName, strlen(identifierName), &nextId); cls.nextId = &nextId; } cls.meta = meta; ggc_tree_selection_selected_foreach (selection, &initiateUpload, &cls); ECRS_freeMetaData(meta); } gtk_widget_destroy(dialog); UNREF(metaXML); metaXML = NULL; DEBUG_END(); } void on_namespaceUpdateButton_clicked_fs(GtkWidget * dummy1, GtkWidget * dummy2) { const char * identifierName; NamespaceList * list; GtkWidget * nameLine; GtkWidget * page; GtkWidget * notebook; GtkWidget * dialog; GtkWidget * spin; GtkWidget * update; GtkTreeIter iter; struct ECRS_MetaData * meta; HashCode512 nextId; HashCode512 prevId; GtkWidget * contentList; GtkTreeSelection * selection; GtkTreeSelection * selectionNamespace; IUC cls; gint num; char * last; char * next; char * freq; DEBUG_BEGIN(); contentList = glade_xml_get_widget(getMainXML(), "availableContentList"); selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(contentList)); if (0 == gtk_tree_selection_count_selected_rows(selection)) { /* IMPROVE-ME: disable the menu item as long as this may happen! */ dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("You must select some available content for publication first!")); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); return; } if (FALSE == gtk_tree_selection_get_selected(selection, NULL, &iter)) { GE_BREAK(ectx, 0); return; } gtk_tree_model_get(gtk_tree_view_get_model(GTK_TREE_VIEW(contentList)), &iter, NAMESPACE_META, &meta, -1); notebook = glade_xml_get_widget(getMainXML(), "localNamespacesNotebook"); num = gtk_notebook_get_current_page(GTK_NOTEBOOK(notebook)); GE_ASSERT(ectx, num != -1); page =gtk_notebook_get_nth_page(GTK_NOTEBOOK(notebook), num); list = head; while ( (list != NULL) && (list->namespacepage != page) ) list = list->next; if (list == NULL) { GE_BREAK(ectx, 0); return; } cls.namespaceName = list->name; /* check that in namespace (updateable) content is selected! */ selectionNamespace = gtk_tree_view_get_selection(GTK_TREE_VIEW(list->treeview)); if (0 == gtk_tree_selection_count_selected_rows(selectionNamespace)) { /* IMPROVE-ME: disable the menu item as long as this may happen! */ dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, _("You must select some existing namespace content to be updated first!")); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); return; } if (FALSE == gtk_tree_selection_get_selected(selectionNamespace, NULL, &iter)) { GE_BREAK(ectx, 0); return; } gtk_tree_model_get(list->model, &iter, IN_NAMESPACE_LAST_STRING, &last, IN_NAMESPACE_NEXT_STRING, &next, IN_NAMESPACE_PUB_FREQ_STRING, &freq, -1); metaXML = glade_xml_new(getGladeFileName(), "namespaceUpdateDialog", PACKAGE_NAME); connectGladeWithPlugins(metaXML); nameLine = glade_xml_get_widget(metaXML, "identifierLabel"); gtk_label_set_text(GTK_LABEL(nameLine), next); if (OK != enc2hash(next, &cls.thisId)) { GE_BREAK(ectx, 0); UNREF(metaXML); metaXML = NULL; if (last != NULL) free(last); if (next != NULL) free(next); if (freq != NULL) free(freq); return; } if (OK == enc2hash(last, &prevId)) { cls.lastId = &prevId; } else { GE_BREAK(ectx, 0); /* should not happen, try to continue */ cls.lastId = NULL; } nameLine = glade_xml_get_widget(metaXML, "nextIdentifierEntry"); if (OK != parseTimeInterval(freq, &cls.updateInterval)) { GE_BREAK(ectx, 0); cls.updateInterval = ECRS_SBLOCK_UPDATE_SPORADIC; } if (cls.updateInterval == ECRS_SBLOCK_UPDATE_SPORADIC) { gtk_entry_set_text(GTK_ENTRY(nameLine), ""); } else { EncName updateName; if (OK != NS_computeNextId(ectx, cfg, list->name, &prevId, &cls.thisId, cls.updateInterval, &nextId)) { GE_BREAK(ectx, 0); UNREF(metaXML); metaXML = NULL; if (last != NULL) free(last); if (next != NULL) free(next); if (freq != NULL) free(freq); return; } hash2enc(&nextId, &updateName); gtk_entry_set_text(GTK_ENTRY(nameLine), (const char*) &updateName); gtk_entry_set_editable(GTK_ENTRY(nameLine), FALSE); } update = glade_xml_get_widget(metaXML, "namespaceUpdateIntervalComboBoxEntry"); gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(update))), freq); createMetaDataListTreeView(metaXML, "namespaceUpdateMetaDataTreeView", "namespaceUpdatePreviewImage", meta); createMetaTypeComboBox(metaXML, "namespaceUpdateMetaTypeComboBox"); dialog = glade_xml_get_widget(metaXML, "namespaceUpdateDialog"); gtk_dialog_set_default_response(GTK_DIALOG(dialog), GTK_RESPONSE_OK); if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_OK) { const char * error = NULL; nameLine = glade_xml_get_widget(metaXML, "nextIdentifierEntry"); if (OK != tryParseTimeInterval(metaXML, "namespaceUpdateIntervalComboBoxEntry", &cls.updateInterval)) { error = _("Failed to parse given time interval!"); identifierName = ""; /* to make gcc happy */ } else { identifierName = gtk_entry_get_text(GTK_ENTRY(nameLine)); if ( (cls.updateInterval != ECRS_SBLOCK_UPDATE_NONE) && ( (identifierName == NULL) || (strlen(identifierName) == 0)) ) { error = _("You must specify an identifier for the next publication."); } } if (error != NULL) { gtk_widget_destroy(dialog); UNREF(metaXML); metaXML = NULL; dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, error); gtk_dialog_run(GTK_DIALOG(dialog)); gtk_widget_destroy(dialog); FREENONNULL(last); FREENONNULL(next); FREENONNULL(freq); return; } hash(identifierName, strlen(identifierName), &nextId); cls.nextId = &nextId; cls.meta = getMetaDataFromList(metaXML, "namespaceUpdateMetaDataTreeView", "namespaceUpdatePreviewImage"); spin = glade_xml_get_widget(metaXML, "namespaceUpdateAnonymitySpinButton"); cls.anonymityLevel = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin)); ggc_tree_selection_selected_foreach (selection, &initiateUpload, &cls); ECRS_freeMetaData(cls.meta); } gtk_widget_destroy(dialog); UNREF(metaXML); metaXML = NULL; if (last != NULL) free(last); if (next != NULL) free(next); if (freq != NULL) free(freq); DEBUG_END(); } void on_clearAvailableContentButton_clicked_fs(GtkWidget * dummy1, GtkWidget * dummy2) { GtkWidget * contentList; GtkTreeModel * model; DEBUG_BEGIN(); contentList = glade_xml_get_widget(getMainXML(), "availableContentList"); model = gtk_tree_view_get_model(GTK_TREE_VIEW(contentList)); URITRACK_clearTrackedURIS(ectx, cfg); gtkSaveCall(&clearContentList, model); DEBUG_END(); } void on_trackingCheckButton_toggled_fs(GtkWidget * dummy1, GtkWidget * dummy2) { GtkWidget * trackCheckButton; trackCheckButton = glade_xml_get_widget(getMainXML(), "trackingCheckButton"); URITRACK_trackURIS(ectx, cfg, gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(trackCheckButton)) == TRUE ? YES : NO); } /** * The spin button giving the rating for a particular namespace * has been changed. Store the new rating for the namespace. */ void on_namespaceRatingSpinButton_changed_fs(GtkWidget * dummy, GtkWidget * dummy2) { GtkWidget * spin; GtkWidget * ncbe; GtkTreeModel * model; GtkTreeIter iter; char * encStr; char * description; int rating; int newrating; DEBUG_BEGIN(); spin = glade_xml_get_widget(getMainXML(), "namespaceRatingSpinButton"); ncbe = glade_xml_get_widget(getMainXML(), "searchNamespaceComboBoxEntry"); model = gtk_combo_box_get_model(GTK_COMBO_BOX(ncbe)); description = NULL; encStr = NULL; if (TRUE == gtk_combo_box_get_active_iter(GTK_COMBO_BOX(ncbe), &iter)) { gtk_tree_model_get(model, &iter, NS_SEARCH_DESCRIPTION, &description, NS_SEARCH_ENCNAME, &encStr, NS_SEARCH_RATING, &rating, -1); if ( (description != NULL) && (0 == strcmp(description, _("globally"))) ) { /* just to be sure */ gtk_widget_set_sensitive(spin, FALSE); } else { if (encStr != NULL) { newrating = gtk_spin_button_get_value(GTK_SPIN_BUTTON(spin)); rating = NS_rankNamespace(ectx, cfg, encStr, newrating - rating); if (rating != newrating) { /* concurrent modification? */ gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin), rating); GE_BREAK(ectx, 0); } gtk_list_store_set(GTK_LIST_STORE(model), &iter, NS_SEARCH_RATING, rating, -1); } } } else { /* FIXME: if enc2hash succeeds, we may want to keep this active */ gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin), 0); gtk_widget_set_sensitive(spin, FALSE); } if (description != NULL) free(description); if (encStr != NULL) free(encStr); DEBUG_END(); } /** * The namespace in the search window has changed. * Update the trust level (possibly changing sensitivity) * and set the search string to the root (if available). */ void on_searchNamespaceComboBoxEntry_changed_fs(GtkWidget * dummy, GtkWidget * dummy2) { GtkWidget * keyword; GtkWidget * spin; GtkWidget * ncbe; GtkTreeModel * model; GtkTreeIter iter; int rating; char * encStr; char * descStr; HashCode512 ns; HashCode512 root; EncName enc; DEBUG_BEGIN(); spin = glade_xml_get_widget(getMainXML(), "namespaceRatingSpinButton"); ncbe = glade_xml_get_widget(getMainXML(), "searchNamespaceComboBoxEntry"); model = gtk_combo_box_get_model(GTK_COMBO_BOX(ncbe)); descStr = NULL; encStr = NULL; if (TRUE == gtk_combo_box_get_active_iter(GTK_COMBO_BOX(ncbe), &iter)) { gtk_tree_model_get(model, &iter, NS_SEARCH_DESCRIPTION, &descStr, NS_SEARCH_ENCNAME, &encStr, NS_SEARCH_RATING, &rating, -1); if ( (descStr != NULL) && (0 == strcmp(descStr, _("globally"))) ) { gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin), 0); gtk_widget_set_sensitive(spin, FALSE); } else if (encStr != NULL) { enc2hash(encStr, &ns); gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin), rating); gtk_widget_set_sensitive(spin, TRUE); if (OK == NS_getNamespaceRoot(ectx, cfg, encStr, &root)) { hash2enc(&root, &enc); keyword = glade_xml_get_widget(getMainXML(), "fssearchKeywordComboBoxEntry"); gtk_entry_set_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(keyword))), (const gchar*) &enc); } } } else { gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin), 0); gtk_widget_set_sensitive(spin, FALSE); } if (descStr != NULL) free(descStr); if (encStr != NULL) free(encStr); DEBUG_END(); } void fs_namespace_start() { GtkWidget * contentList; GtkListStore * model; GtkCellRenderer * renderer; GtkWidget * trackCheckButton; GtkTreeViewColumn * column; int col; DEBUG_BEGIN(); trackCheckButton = glade_xml_get_widget(getMainXML(), "trackingCheckButton"); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(trackCheckButton), URITRACK_trackStatus(ectx, cfg) == YES ? TRUE : FALSE); contentList = glade_xml_get_widget(getMainXML(), "availableContentList"); model = gtk_list_store_new(NAMESPACE_NUM, G_TYPE_STRING, /* name */ G_TYPE_UINT64, /* size */ G_TYPE_STRING, /* human-readable size */ G_TYPE_STRING, /* uri-string */ G_TYPE_POINTER, G_TYPE_POINTER); /* uri */ gtk_tree_view_set_model(GTK_TREE_VIEW(contentList), GTK_TREE_MODEL(model)); gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(contentList)), GTK_SELECTION_MULTIPLE); renderer = gtk_cell_renderer_text_new(); col = gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(contentList), -1, _("Filename"), renderer, "text", NAMESPACE_FILENAME, NULL); column = gtk_tree_view_get_column(GTK_TREE_VIEW(contentList), col - 1); gtk_tree_view_column_set_resizable(column, TRUE); gtk_tree_view_column_set_clickable(column, TRUE); gtk_tree_view_column_set_reorderable(column, TRUE); gtk_tree_view_column_set_sort_column_id(column, NAMESPACE_FILENAME); /*gtk_tree_view_column_set_sort_indicator(column, TRUE);*/ gtk_tree_view_column_set_resizable(gtk_tree_view_get_column(GTK_TREE_VIEW(contentList), col - 1), TRUE); renderer = gtk_cell_renderer_text_new(); g_object_set (renderer, "xalign", 1.00, NULL); col = gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(contentList), -1, _("Filesize"), renderer, "text", NAMESPACE_HSIZE, NULL); column = gtk_tree_view_get_column(GTK_TREE_VIEW(contentList), col - 1); gtk_tree_view_column_set_resizable(column, TRUE); gtk_tree_view_column_set_clickable(column, TRUE); gtk_tree_view_column_set_reorderable(column, TRUE); gtk_tree_view_column_set_sort_column_id(column, NAMESPACE_SIZE); /*gtk_tree_view_column_set_sort_indicator(column, TRUE);*/ gtk_tree_view_column_set_resizable(gtk_tree_view_get_column(GTK_TREE_VIEW(contentList), col - 1), TRUE); renderer = gtk_cell_renderer_text_new(); col = gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(contentList), -1, _("URI"), renderer, "text", NAMESPACE_URISTRING, NULL); column = gtk_tree_view_get_column(GTK_TREE_VIEW(contentList), col - 1); gtk_tree_view_column_set_reorderable(column, TRUE); gtk_tree_view_column_set_resizable(column, TRUE); gtk_tree_view_column_set_resizable(gtk_tree_view_get_column(GTK_TREE_VIEW(contentList), col - 1), TRUE); URITRACK_registerTrackCallback(ectx, cfg, &updateViewSave, NULL); NS_listNamespaces(ectx, cfg, YES, &addTabForNamespace, NULL); DEBUG_END(); } #if 0 void on_availableContentList_destroy_fs(GtkWidget * dummy1, GtkWidget * dummy2) { GtkWidget * contentList; GtkTreeModel * model; contentList = glade_xml_get_widget(getMainXML(), "availableContentList"); model = gtk_tree_view_get_model(GTK_TREE_VIEW(contentList)); clearContentList(model); } void on_localNamespacesNotebook_destroy_fs(GtkWidget * dummy1, GtkWidget * dummy2) { NamespaceList * pos; GtkTreeIter iter; struct ECRS_URI * u; struct ECRS_MetaData * m; while (head != NULL) { pos = head->next; FREE(head->name); ECRS_freeMetaData(head->meta); if (gtk_tree_model_get_iter_first(head->model, &iter)) { do { gtk_tree_model_get(head->model, &iter, IN_NAMESPACE_URI, &u, IN_NAMESPACE_META, &m, -1); gtk_list_store_set(GTK_LIST_STORE(head->model), &iter, IN_NAMESPACE_URI, NULL, IN_NAMESPACE_META, NULL, -1); if (u != NULL) ECRS_freeUri(u); if (m != NULL) ECRS_freeMetaData(m); } while (gtk_tree_model_iter_next(head->model, &iter)); } FREE(head); head = pos; } } #endif void fs_namespace_stop() { URITRACK_unregisterTrackCallback(&updateViewSave, NULL); /* FIXME: free resources! */ } /* end of namespace.c */