static const char* guess_type_file(const char* path) { GString* command = g_string_new("file -b --mime-type "); char* tmp = g_shell_quote(path); g_string_append(command, tmp); g_free(tmp); GError* error = NULL; char* out = NULL; int ret = 0; g_spawn_command_line_sync(command->str, &out, NULL, &ret, &error); g_string_free(command, TRUE); if (error != NULL) { girara_warning("failed to execute command: %s", error->message); g_error_free(error); g_free(out); return NULL; } if (WEXITSTATUS(ret) != 0) { girara_warning("file failed with error code: %d", WEXITSTATUS(ret)); g_free(out); return NULL; } g_strdelimit(out, "\n\r", '\0'); return out; }
zathura_bookmark_t* zathura_bookmark_add(zathura_t* zathura, const gchar* id, unsigned int page) { g_return_val_if_fail(zathura && zathura->document && zathura->bookmarks.bookmarks, NULL); g_return_val_if_fail(id, NULL); double position_x = zathura_document_get_position_x(zathura->document); double position_y = zathura_document_get_position_y(zathura->document); zathura_bookmark_t* old = zathura_bookmark_get(zathura, id); if (old != NULL) { old->page = page; old->x = position_x; old->y = position_y; if (zathura->database != NULL) { const char* path = zathura_document_get_path(zathura->document); if (zathura_db_remove_bookmark(zathura->database, path, old->id) == false) { girara_warning("Failed to remove old bookmark from database."); } if (zathura_db_add_bookmark(zathura->database, path, old) == false) { girara_warning("Failed to add new bookmark to database."); } } return old; } zathura_bookmark_t* bookmark = g_try_malloc0(sizeof(zathura_bookmark_t)); if (bookmark == NULL) { return NULL; } bookmark->id = g_strdup(id); bookmark->page = page; bookmark->x = position_x; bookmark->y = position_y; girara_list_append(zathura->bookmarks.bookmarks, bookmark); if (zathura->database != NULL) { const char* path = zathura_document_get_path(zathura->document); if (zathura_db_add_bookmark(zathura->database, path, bookmark) == false) { girara_warning("Failed to add bookmark to database."); } } return bookmark; }
zathura_error_t pdf_document_attachment_save(zathura_document_t* document, PopplerDocument* poppler_document, const char* attachmentname, const char* file) { if (document == NULL || poppler_document == NULL) { return ZATHURA_ERROR_INVALID_ARGUMENTS; } if (poppler_document_has_attachments(poppler_document) == FALSE) { girara_warning("PDF file has no attachments"); return ZATHURA_ERROR_INVALID_ARGUMENTS; } GList* attachment_list = poppler_document_get_attachments(poppler_document); GList* attachments; for (attachments = attachment_list; attachments; attachments = g_list_next(attachments)) { PopplerAttachment* attachment = (PopplerAttachment*) attachments->data; if (g_strcmp0(attachment->name, attachmentname) != 0) { continue; } return poppler_attachment_save(attachment, file, NULL); } return ZATHURA_ERROR_OK; }
girara_list_t* pdf_document_attachments_get(zathura_document_t* document, void* data, zathura_error_t* error) { if (document == NULL || data == NULL) { if (error != NULL) { *error = ZATHURA_ERROR_INVALID_ARGUMENTS; } return NULL; } PopplerDocument* poppler_document = data; if (poppler_document_has_attachments(poppler_document) == FALSE) { girara_warning("PDF file has no attachments"); if (error != NULL) { *error = ZATHURA_ERROR_UNKNOWN; } return NULL; } girara_list_t* res = girara_sorted_list_new2((girara_compare_function_t) g_strcmp0, g_free); if (res == NULL) { if (error != NULL) { *error = ZATHURA_ERROR_OUT_OF_MEMORY; } return NULL; } GList* attachment_list = poppler_document_get_attachments(poppler_document); for (GList* attachments = attachment_list; attachments != NULL; attachments = g_list_next(attachments)) { PopplerAttachment* attachment = (PopplerAttachment*) attachments->data; girara_list_append(res, g_strdup(attachment->name)); } return res; }
bool zathura_bookmark_remove(zathura_t* zathura, const gchar* id) { g_return_val_if_fail(zathura && zathura->document && zathura->bookmarks.bookmarks, false); g_return_val_if_fail(id, false); zathura_bookmark_t* bookmark = zathura_bookmark_get(zathura, id); if (bookmark == NULL) { return false; } if (zathura->database != NULL) { const char* path = zathura_document_get_path(zathura->document); if (zathura_db_remove_bookmark(zathura->database, path, bookmark->id) == false) { girara_warning("Failed to remove bookmark from database."); } } girara_list_remove(zathura->bookmarks.bookmarks, bookmark); return true; }
bool girara_xdg_open(const char* uri) { if (uri == NULL || strlen(uri) == 0) { return false; } /* g_spawn_async expects char** */ char* argv[] = { g_strdup("xdg-open"), g_strdup(uri), NULL }; GError* error = NULL; const bool res = g_spawn_async(NULL, argv, NULL, G_SPAWN_SEARCH_PATH, NULL, NULL, NULL, &error); if (error != NULL) { girara_warning("Failed to execute command: %s", error->message); g_error_free(error); } g_free(argv[0]); g_free(argv[1]); return res; }
static const gchar* guess_type(const char* path) { gboolean uncertain; const gchar* content_type = g_content_type_guess(path, NULL, 0, &uncertain); if (content_type == NULL) { return NULL; } if (uncertain == FALSE) { return content_type; } girara_debug("g_content_type is uncertain, guess: %s\n", content_type); FILE* f = fopen(path, "rb"); if (f == NULL) { return NULL; } const int fd = fileno(f); guchar* content = NULL; size_t length = 0u; ssize_t bytes_read = -1; while (uncertain == TRUE && length < GT_MAX_READ && bytes_read != 0) { g_free((void*)content_type); content_type = NULL; content = g_realloc(content, length + BUFSIZ); bytes_read = read(fd, content + length, BUFSIZ); if (bytes_read == -1) { break; } length += bytes_read; content_type = g_content_type_guess(NULL, content, length, &uncertain); girara_debug("new guess: %s uncertain: %d, read: %zu\n", content_type, uncertain, length); } fclose(f); g_free(content); if (uncertain == FALSE) { return content_type; } g_free((void*)content_type); content_type = NULL; girara_debug("falling back to file"); GString* command = g_string_new("file -b --mime-type "); char* tmp = g_shell_quote(path); g_string_append(command, tmp); g_free(tmp); GError* error = NULL; char* out = NULL; int ret = 0; g_spawn_command_line_sync(command->str, &out, NULL, &ret, &error); g_string_free(command, TRUE); if (error != NULL) { girara_warning("failed to execute command: %s", error->message); g_error_free(error); g_free(out); return NULL; } if (WEXITSTATUS(ret) != 0) { girara_warning("file failed with error code: %d", WEXITSTATUS(ret)); g_free(out); return NULL; } g_strdelimit(out, "\n\r", '\0'); return out; }
static const gchar* guess_type(const char* path) { const gchar* content_type = NULL; #ifdef WITH_MAGIC const char* mime_type = NULL; /* creat magic cookie */ const int flags = MAGIC_MIME_TYPE | MAGIC_SYMLINK | MAGIC_NO_CHECK_APPTYPE | MAGIC_NO_CHECK_CDF | MAGIC_NO_CHECK_ELF | MAGIC_NO_CHECK_ENCODING; magic_t magic = magic_open(flags); if (magic == NULL) { girara_debug("failed creating the magic cookie"); goto cleanup; } /* ... and load mime database */ if (magic_load(magic, NULL) < 0) { girara_debug("failed loading the magic database: %s", magic_error(magic)); goto cleanup; } /* get the mime type */ mime_type = magic_file(magic, path); if (mime_type == NULL) { girara_debug("failed guessing filetype: %s", magic_error(magic)); goto cleanup; } girara_debug("magic detected filetype: %s", mime_type); content_type = g_strdup(mime_type); cleanup: if (magic != NULL) { magic_close(magic); } if (content_type != NULL) { return content_type; } /* else fallback to g_content_type_guess method */ #endif /*WITH_MAGIC*/ gboolean uncertain = FALSE; content_type = g_content_type_guess(path, NULL, 0, &uncertain); if (content_type == NULL) { girara_debug("g_content_type failed\n"); } else { if (uncertain == FALSE) { girara_debug("g_content_type detected filetype: %s", content_type); return content_type; } girara_debug("g_content_type is uncertain, guess: %s", content_type); } FILE* f = fopen(path, "rb"); if (f == NULL) { return NULL; } const int fd = fileno(f); guchar* content = NULL; size_t length = 0u; ssize_t bytes_read = -1; while (uncertain == TRUE && length < GT_MAX_READ && bytes_read != 0) { g_free((void*)content_type); content_type = NULL; content = g_realloc(content, length + BUFSIZ); bytes_read = read(fd, content + length, BUFSIZ); if (bytes_read == -1) { break; } length += bytes_read; content_type = g_content_type_guess(NULL, content, length, &uncertain); girara_debug("new guess: %s uncertain: %d, read: %zu", content_type, uncertain, length); } fclose(f); g_free(content); if (uncertain == FALSE) { return content_type; } g_free((void*)content_type); content_type = NULL; girara_debug("falling back to file"); GString* command = g_string_new("file -b --mime-type "); char* tmp = g_shell_quote(path); g_string_append(command, tmp); g_free(tmp); GError* error = NULL; char* out = NULL; int ret = 0; g_spawn_command_line_sync(command->str, &out, NULL, &ret, &error); g_string_free(command, TRUE); if (error != NULL) { girara_warning("failed to execute command: %s", error->message); g_error_free(error); g_free(out); return NULL; } if (WEXITSTATUS(ret) != 0) { girara_warning("file failed with error code: %d", WEXITSTATUS(ret)); g_free(out); return NULL; } g_strdelimit(out, "\n\r", '\0'); return out; }
bool zathura_init(zathura_t* zathura) { if (zathura == NULL) { return false; } /* create zathura (config/data) directory */ if (g_mkdir_with_parents(zathura->config.config_dir, 0771) == -1) { girara_error("Could not create '%s': %s", zathura->config.config_dir, strerror(errno)); } if (g_mkdir_with_parents(zathura->config.data_dir, 0771) == -1) { girara_error("Could not create '%s': %s", zathura->config.data_dir, strerror(errno)); } /* load plugins */ zathura_plugin_manager_load(zathura->plugins.manager); /* configuration */ config_load_default(zathura); /* load global configuration files */ char* config_path = girara_get_xdg_path(XDG_CONFIG_DIRS); girara_list_t* config_dirs = girara_split_path_array(config_path); ssize_t size = girara_list_size(config_dirs) - 1; for (; size >= 0; --size) { const char* dir = girara_list_nth(config_dirs, size); char* file = g_build_filename(dir, ZATHURA_RC, NULL); config_load_file(zathura, file); g_free(file); } girara_list_free(config_dirs); g_free(config_path); config_load_file(zathura, GLOBAL_RC); /* load local configuration files */ char* configuration_file = g_build_filename(zathura->config.config_dir, ZATHURA_RC, NULL); config_load_file(zathura, configuration_file); g_free(configuration_file); /* UI */ if (girara_session_init(zathura->ui.session, "zathura") == false) { goto error_free; } /* girara events */ zathura->ui.session->events.buffer_changed = cb_buffer_changed; zathura->ui.session->events.unknown_command = cb_unknown_command; /* page view */ #if (GTK_MAJOR_VERSION == 3) zathura->ui.page_widget = gtk_grid_new(); gtk_grid_set_row_homogeneous(GTK_GRID(zathura->ui.page_widget), TRUE); gtk_grid_set_column_homogeneous(GTK_GRID(zathura->ui.page_widget), TRUE); #else zathura->ui.page_widget = gtk_table_new(0, 0, TRUE); #endif if (zathura->ui.page_widget == NULL) { goto error_free; } g_signal_connect(G_OBJECT(zathura->ui.session->gtk.window), "size-allocate", G_CALLBACK(cb_view_resized), zathura); /* Setup hadjustment tracker */ GtkAdjustment* hadjustment = gtk_scrolled_window_get_hadjustment( GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view)); zathura->ui.hadjustment = zathura_adjustment_clone(hadjustment); g_object_ref_sink(zathura->ui.hadjustment); /* Connect hadjustment signals */ g_signal_connect(G_OBJECT(hadjustment), "value-changed", G_CALLBACK(cb_view_vadjustment_value_changed), zathura); g_signal_connect(G_OBJECT(hadjustment), "value-changed", G_CALLBACK(cb_adjustment_track_value), zathura->ui.hadjustment); g_signal_connect(G_OBJECT(hadjustment), "changed", G_CALLBACK(cb_view_hadjustment_changed), zathura); g_signal_connect(G_OBJECT(hadjustment), "changed", G_CALLBACK(cb_adjustment_track_bounds), zathura->ui.hadjustment); /* Setup vadjustment tracker */ GtkAdjustment* vadjustment = gtk_scrolled_window_get_vadjustment( GTK_SCROLLED_WINDOW(zathura->ui.session->gtk.view)); zathura->ui.vadjustment = zathura_adjustment_clone(vadjustment); g_object_ref_sink(zathura->ui.vadjustment); /* Connect vadjustment signals */ g_signal_connect(G_OBJECT(vadjustment), "value-changed", G_CALLBACK(cb_view_vadjustment_value_changed), zathura); g_signal_connect(G_OBJECT(vadjustment), "value-changed", G_CALLBACK(cb_adjustment_track_value), zathura->ui.vadjustment); g_signal_connect(G_OBJECT(vadjustment), "changed", G_CALLBACK(cb_view_vadjustment_changed), zathura); g_signal_connect(G_OBJECT(vadjustment), "changed", G_CALLBACK(cb_adjustment_track_bounds), zathura->ui.vadjustment); /* page view alignment */ zathura->ui.page_widget_alignment = gtk_alignment_new(0.5, 0.5, 0, 0); if (zathura->ui.page_widget_alignment == NULL) { goto error_free; } gtk_container_add(GTK_CONTAINER(zathura->ui.page_widget_alignment), zathura->ui.page_widget); #if (GTK_MAJOR_VERSION == 3) gtk_widget_set_hexpand_set(zathura->ui.page_widget_alignment, TRUE); gtk_widget_set_hexpand(zathura->ui.page_widget_alignment, FALSE); gtk_widget_set_vexpand_set(zathura->ui.page_widget_alignment, TRUE); gtk_widget_set_vexpand(zathura->ui.page_widget_alignment, FALSE); #endif gtk_widget_show(zathura->ui.page_widget); /* statusbar */ zathura->ui.statusbar.file = girara_statusbar_item_add(zathura->ui.session, TRUE, TRUE, TRUE, NULL); if (zathura->ui.statusbar.file == NULL) { goto error_free; } zathura->ui.statusbar.buffer = girara_statusbar_item_add(zathura->ui.session, FALSE, FALSE, FALSE, NULL); if (zathura->ui.statusbar.buffer == NULL) { goto error_free; } zathura->ui.statusbar.page_number = girara_statusbar_item_add(zathura->ui.session, FALSE, FALSE, FALSE, NULL); if (zathura->ui.statusbar.page_number == NULL) { goto error_free; } girara_statusbar_item_set_text(zathura->ui.session, zathura->ui.statusbar.file, _("[No name]")); /* signals */ g_signal_connect(G_OBJECT(zathura->ui.session->gtk.window), "destroy", G_CALLBACK(cb_destroy), zathura); /* set page padding */ int page_padding = 1; girara_setting_get(zathura->ui.session, "page-padding", &page_padding); #if (GTK_MAJOR_VERSION == 3) gtk_grid_set_row_spacing(GTK_GRID(zathura->ui.page_widget), page_padding); gtk_grid_set_column_spacing(GTK_GRID(zathura->ui.page_widget), page_padding); #else gtk_table_set_row_spacings(GTK_TABLE(zathura->ui.page_widget), page_padding); gtk_table_set_col_spacings(GTK_TABLE(zathura->ui.page_widget), page_padding); #endif /* database */ char* database = NULL; girara_setting_get(zathura->ui.session, "database", &database); if (g_strcmp0(database, "plain") == 0) { girara_debug("Using plain database backend."); zathura->database = zathura_plaindatabase_new(zathura->config.data_dir); #ifdef WITH_SQLITE } else if (g_strcmp0(database, "sqlite") == 0) { girara_debug("Using sqlite database backend."); char* tmp = g_build_filename(zathura->config.data_dir, "bookmarks.sqlite", NULL); zathura->database = zathura_sqldatabase_new(tmp); g_free(tmp); #endif } else { girara_error("Database backend '%s' is not supported.", database); } g_free(database); if (zathura->database == NULL) { girara_error("Unable to initialize database. Bookmarks won't be available."); } else { g_object_set(zathura->ui.session->command_history, "io", zathura->database, NULL); } /* bookmarks */ zathura->bookmarks.bookmarks = girara_sorted_list_new2((girara_compare_function_t) zathura_bookmarks_compare, (girara_free_function_t) zathura_bookmark_free); /* jumplist */ zathura->jumplist.max_size = 20; girara_setting_get(zathura->ui.session, "jumplist-size", &(zathura->jumplist.max_size)); zathura->jumplist.list = girara_list_new2(g_free); zathura->jumplist.size = 0; zathura->jumplist.cur = NULL; zathura_jumplist_append_jump(zathura); zathura->jumplist.cur = girara_list_iterator(zathura->jumplist.list); /* page cache */ int cache_size = 0; girara_setting_get(zathura->ui.session, "page-cache-size", &cache_size); if (cache_size <= 0) { girara_warning("page-cache-size is not positive, using %d instead", ZATHURA_PAGE_CACHE_DEFAULT_SIZE); zathura->page_cache.size = ZATHURA_PAGE_CACHE_DEFAULT_SIZE; } else { zathura->page_cache.size = cache_size; } zathura->page_cache.cache = g_malloc(zathura->page_cache.size * sizeof(int)); zathura_page_cache_invalidate_all(zathura); return true; error_free: if (zathura->ui.page_widget != NULL) { g_object_unref(zathura->ui.page_widget); } if (zathura->ui.page_widget_alignment != NULL) { g_object_unref(zathura->ui.page_widget_alignment); } return false; }