pax_global_header00006660000000000000000000000064144625365570014533gustar00rootroot0000000000000052 comment=4cdfa43453f81932dba3a8ce1a8280a58ed0e122 cpdb-libs-2.0b5/000077500000000000000000000000001446253655700134625ustar00rootroot00000000000000cpdb-libs-2.0b5/.gitignore000066400000000000000000000011171446253655700154520ustar00rootroot00000000000000*~ *.o *.pc *.pdf *.tar.* .project .vscode/ .gdb_history .cproject gmon.out autoscan.log aclocal.m4 autom4te.cache build-aux/ m4/* !m4/cpdb* ABOUT-NLS po/* !po/POTFILE.in !po/Makevars config.* configure libtool Makefile Makefile.in ar-lib compile depcomp install-sh ltmain.sh missing tmp tmp. cpdb/backend-interface.c cpdb/backend-interface.h cpdb/frontend-interface.c cpdb/frontend-interface.h cpdb/*.so cpdb/*.o cpdb/*.la cpdb/*.lo cpdb/.deps cpdb/.libs tools/cpdb-text-frontend tools/cpdb-pickle-print tools/gmon.out tools/*.o tools/.deps tools/.libs tools/*.log tools/*.trs cpd-library* cpdb-libs-2.0b5/CHANGES.md000066400000000000000000000167271446253655700150710ustar00rootroot00000000000000# CHANGES - Common Print Dialog Backends - Libraries - v2.0b5 - 2023-08-02 ## CHANGES IN V2.0b5 (2nd August 2023) - Removed browsing for backends via file system The frontend should only shout into the D-Bus to find out which backends are available and to communicate with them. Depending on the way (for example sandboxed packaging, like Snap) how the frontend and backand are installed the frontend cannot access the host's or the backend's file systems (PR #27). - Limit scanned string length in `scanf()`/`fscanf()` functions cpdb-libs uses the `fscanf()` and `scanf()` functions to parse command lines and configuration files, dropping the read string components into fixed-length buffers, but does not limit the length of the strings to be read by `fscanf()` and `scanf()` causing buffer overflows when a string is longer than 1023 characters (CVE-2023-34095). - Fixed memory bugs leading to leaks and crashes (PR #26) - Build system: Removed unnecessary lines in `tools/Makefile.am` Removed the `TESTdir` and `TEST_SCRIPTS` entries in `tools/Makefile.am`. They are not needed and let `make install` try to install `run-tests.sh` in the source directory, where it already is, causing an error. ## CHANGES IN V2.0b4 (20th March 2023) - Added test script for `make test`/`make check` The script tools/run-tests.sh runs the `cpdb-text-frontend` text mode example frontend and stops it by supplying "stop" to its standard input. - Allow changing the backend info directory via env variable To make it possible to test backends which are not installed into the system, one can now set the environment variable CPDB_BACKEND_INFO_DIR to the directory where the backend info file for the backend is, for example in its source tree. - Install sample frontend with `make install` We use the sample frontend `cpdb-text-frontend` for several tests now, especially "make check" and also the autopkgtests in the Debian/Ubuntu packages. They are also useful for backend developers for manual testing. - Renamed develping/debug tools As we install the development and debugging tools now, they should be more easily identifiable as part of CPDB. Therefore they get `cpdb-`-prefixed names. - `cpdb-text-frontend`: Use larger and more easily adjustable string buffers - Fixed segfault in the frontend library `cpdbResurrectPrinterFromFile()`, when called with an invalid file name, caused a crash. ## CHANGES IN V2.0b3 (20th February 2023) - Added functions to fetch all printer strings translations (PR #23) * Added `cpdbGetAllTranslations()` to synchronously fetch all printer string translations * Added `cpdbAcquireTranslations()` to asychronously fetch them. * Removed `get-human-readable-option`/`choice-name` methods * Removed `cpdb_async_obj_t` from `cpdb-frontend.h` as that is meant for internal use. ## CHANGES IN V2.0b2 (13th February 2023) - Options groups: To allow better structuring of options in print dialogs, common options are categorized in groups, like media, print quality, color, finishing, ... This can be primarily done by the backends but the frontend library can do fallback/default assignments for options not assigned by the backend. - Many print dialogs have a "Color" option group (usually shown on one tab), so also have one in cpdb-libs to match with the dialogs and more easily map the options into the dialogs. - Add macros for new options and choices, also add "Color" group - Synchronous printer fetching upon backend activation (PR #21) Made `cpdbConnectToDbus()` wait until all backends activate - Backends will automatically signal any printer updates instead of the frontend having to manually ask them (PR #21) - Add `printer-state-changed` signal (PR #21) * Changed function callback type definition for printer updates * Added callback to frontends for changes in printer state - Translation support: Translations of option, choice, and group names are now supported, not only English human-readable strings. And Translations can be provided by the backends (also polling them from the print service) and by the frontend library. - Use autopoint instead of gettextize - Enable reconnecting to dbus (PR #14) - Debug logging: Now backends forward their log messages to the frontend library for easier debugging. - Use instead of redefining macros (Issue #20) - Add functions to free objects (PR #15) - Remove hardcoded paths and follow XDG base dir specs (PR #14) - Added javadoc comments to function declarations (PR #21) - Build system: Let "make dist" also create .tar.bz2 and .tar.xz - Add the dependency on libdbus to README.md libdbus-1-dev is needed to configure pkg-config variables for backends - COPYING: Added Priydarshi Singh ## CHANGES IN V2.0b1 (11th December 2022) - Added interfaces to get human readable option and settings names Print attributes/options and their choices are usually defined in a machine-readable form which is more made for easy typing in a command line, not too long, no special characters, always in English and human-readable form for GUI (print dialogs), more verbose for easier understanding, with spaces and other special characters, translated, ... Older backends without human-readable strings can still be used. In such a case it is recommended that the dialog does either its own conversion or simply shows the machine-readable string as a last mean. - Added get_media_size() function to retrieve media dimensions for a given "media" option value - Support for media sizes to have multiple margin variants (like standard and borderless) - Support for configurable user and system-wide default printers - Acquire printer details asynchronously (non blocking) - Made cpdb-libs completely CUPS-neutral Removed CUPS-specific functions from the frontend library functions and the dependency on libcups, renamed CUPS-base function and signal names - Use "const" qualifiers on suitable function parameters - DBG_LOG now includes error-message - Renamed all API functions, data types and constants To make sure that the resources of libcpdb and libcpdb-frontend do not conflict with the ones of any other library used by a frontend or backend created with CPDB, all functions, data types, and constants of CPDB got renamed to be unique to CPDB. Here we follow the rules of CUPS and cups-filters (to get unique rules for all libraries by OpenPrinting): API functions are in camelCase and with "cpdb" prefix, data types all-lowercase, with '_' as word separator, and constants are all-uppercase, also with '_' as word separator, and with "CPDB_" prefix. - Renamed and re-organized source files to make all more standards-conforming and naming more consistent. - All headers go to /usr/include/cpdb now: Base API headers cpdb.h and cpdb-frontend.h, interface headers (and also part of the API) backend-interface.h and frontend-interface.h, and the convenience header files backend.h and frontend.h (include exactly the headers needed). - Bumped soname of the libraries to 2. - Check settings pointer for NULL before freeing it - NULL check on input parameters for many functions - Fixed incompatibility with newer versions of glib() glib.h cannot get included inside 'extern "C" { ... }' - Corrected AC_INIT() in configure.ac: Bug report destination, directory for "make dist". - README.md: Fixed typos and updated usage instructions - Updated .gitignore cpdb-libs-2.0b5/COPYING000066400000000000000000000026541446253655700145240ustar00rootroot00000000000000Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: cpdb-libs Upstream-Contact: OpenPrinting Source: https://github.com/OpenPrinting/cpdb-libs/releases Files: * Copyright: 2017, Nilanjana Lodh 2017-2022, Till Kamppeter 2020, Priydarshi Singh 2022, Gaurav Guleria License: MIT License: MIT The MIT License . Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: . The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. . THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. cpdb-libs-2.0b5/LICENSE.md000066400000000000000000000020571446253655700150720ustar00rootroot00000000000000MIT License Copyright (c) 2017 Nilanjana Lodh Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. cpdb-libs-2.0b5/Makefile.am000066400000000000000000000003511446253655700155150ustar00rootroot00000000000000EXTRA_DIST = README.md LICENSE.md COPYING CHANGES.md autogen.sh AUTOMAKE_OPTIONS = foreign ACLOCAL_AMFLAGS = -I m4 SUBDIRS = cpdb po tools pkgconfigdir = $(libdir)/pkgconfig pkgconfig_DATA = cpdb-backend.pc cpdb-frontend.pc cpdb.pc cpdb-libs-2.0b5/README.md000066400000000000000000000057741446253655700147560ustar00rootroot00000000000000# Frontend/Backend Communication Libraries for the Common Print Dialog Backends This repository hosts the code for frontend and backend libraries for the Common Printing Dialog Backends (CPDB) project. These libraries allow the CPDB frontends (the print dialogs) and backends (the modules communicating with the different printing systems) to communicate with each other via D-Bus. The frontend library also provides some extra functionality to deal with Printers, Settings, etc. in a high level manner. ## Background The Common Print Dialog Backends (CPDB) project of OpenPrinting is about separating the print dialogs of different GUI toolkits and applications (GTK, Qt, LibreOffice, Firefox, Chromium, ...) from the different print technologies (CUPS/IPP, cloud printing services, ...) so that they can get developed independently and so always from all applications one can print with all print technologies and changes in the print technologies get supported quickly. If one opens the print dialog, the dialog will not talk directly to CUPS, a cloud printing service, or any other printing system. For this communication there are the backends. The dialog will find all available backends and sends commands to them, for listing all available printers, giving property/option lists for the selected printer, and printing on the selected printer. This communication is done via D-Bus. So the backends are easily exchangeable and for getting support for a new print technology only its backend needs to get added. ## Dependencies - autoconf - autopoint - glib 2.0 - libdbus - libtool On Debian based distros, these can be installed by running: \ `sudo apt install autoconf autopoint libglib2.0-dev libdbus-1-dev libtool` ## Build and installation $ ./autogen.sh $ ./configure $ make $ sudo make install $ sudo ldconfig Also install at least one of the backends (cpdb-backend-...). ## Testing the library The project also includes a sample command line frontend (using the `cpdb-libs-frontend` API) that you can use to test whether the installed libraries and print backends work as expected. $ cpdb-text-frontend The list of printers from various print technologies should start appearing automatically. Type `help` to get the list of available commands. Make sure to stop the frontend using the `stop` command only. The library also provides support for serializing a printer. Use the `pickle-printer` command to serialize it, and run the `cpdb-pickle-print` executable after that to deserialize and test it. ## Using the libraries for developing print backends and dialogs. To develop a frontend client (eg. a print dialog), use the `libcpdb` and `libcpdb-frontend` libraries. pkg-config support: `pkg-config --cflags --libs cpdb` and `pkg-config --cflags --libs cpdb-frontend`. Header file: `cpdb/frontend.h` Similarly, to develop a print backend, you need to use the only the `libcpdb` library. pkg-config support: `pkg-config --cflags --libs cpdb`. Header file: `cpdb/backend.h` or simply only `cpdb/cpdb.h`. cpdb-libs-2.0b5/autogen.sh000077500000000000000000000000471446253655700154640ustar00rootroot00000000000000mkdir -p build-aux \ && autoreconf -fi cpdb-libs-2.0b5/configure.ac000066400000000000000000000017451446253655700157570ustar00rootroot00000000000000# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ([2.69]) dnl Package name and version... AC_INIT([cpdb-libs], [2.0b5], [https://github.com/OpenPrinting/cpdb-libs/issues], [cpdb-libs], [https://github.com/OpenPrinting/cpdb-libs]) AC_CONFIG_SRCDIR([cpdb/cpdb-frontend.h]) AC_CONFIG_MACRO_DIRS([m4]) AC_CONFIG_AUX_DIR([build-aux]) AM_INIT_AUTOMAKE([-Wall dist-xz dist-bzip2 foreign]) # Check for archiver AM_PROG_AR # Check for GNU gettext AM_GNU_GETTEXT([external]) AM_GNU_GETTEXT_VERSION([0.21]) LT_INIT dnl Include configure tests for different areas... sinclude(m4/cpdb-directories.m4) sinclude(m4/cpdb-common.m4) AC_CONFIG_FILES([Makefile po/Makefile.in cpdb/Makefile tools/Makefile cpdb-backend.pc cpdb-frontend.pc cpdb.pc]) AC_OUTPUT dnl Make sure m4 scripts are executable chmod +x m4 cpdb-libs-2.0b5/cpdb-backend.pc.in000066400000000000000000000004211446253655700167050ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ includedir=@includedir@ libdir=@libdir@ Cflags: -I${includedir} Requires: gio-2.0 gio-unix-2.0 glib-2.0 cpdb Libs: -L${libdir} Name: cpdb-backend Description: Common Print Dialog Backends: Library for backends Version: @VERSION@ cpdb-libs-2.0b5/cpdb-frontend.pc.in000066400000000000000000000004431446253655700171410ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ includedir=@includedir@ libdir=@libdir@ Cflags: -I${includedir} Requires: gio-2.0 gio-unix-2.0 glib-2.0 cpdb Libs: -L${libdir} -lcpdb-frontend Name: cpdb-frontend Description: Common Print Dialog Backends: Library for frontends Version: @VERSION@ cpdb-libs-2.0b5/cpdb.pc.in000066400000000000000000000005341446253655700153250ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ includedir=@includedir@ libdir=@libdir@ datarootdir=@datarootdir@ cpdb_backend_exec_dir=@CPDB_BACKEND_EXEC_DIR@ Cflags: -I${includedir} Requires: gio-2.0 gio-unix-2.0 glib-2.0 Libs: -L${libdir} -lcpdb Name: cpdb Description: Common Print Dialog Backends: Common parts of the libraries Version: @VERSION@ cpdb-libs-2.0b5/cpdb/000077500000000000000000000000001446253655700143725ustar00rootroot00000000000000cpdb-libs-2.0b5/cpdb/Makefile.am000066400000000000000000000034051446253655700164300ustar00rootroot00000000000000EXTRA_DIST = interface BUILT_SOURCES = backend-interface.h \ frontend-interface.h lib_LTLIBRARIES = libcpdb.la libcpdb-frontend.la libcpdb_la_SOURCES = cpdb.c \ cpdb.h nodist_libcpdb_la_SOURCES = backend-interface.c \ frontend-interface.c libcpdb_la_CPPFLAGS = $(GLIB_CFLAGS) libcpdb_la_CPPFLAGS += $(GIO_CFLAGS) libcpdb_la_CPPFLAGS += $(GIOUNIX_CFLAGS) libcpdb_la_CPPFLAGS += -I.. libcpdb_la_LIBADD = $(GLIB_LIBS) libcpdb_la_LIBADD += $(GIO_LIBS) libcpdb_la_LIBADD += $(GIOUNIX_LIBS) libcpdb_la_LDFLAGS = -no-undefined -version-info 2 libcpdb_frontend_la_SOURCES = cpdb-frontend.c \ cpdb-frontend.h libcpdb_frontend_la_CPPFLAGS = $(GLIB_CFLAGS) libcpdb_frontend_la_CPPFLAGS += $(GIO_CFLAGS) libcpdb_frontend_la_CPPFLAGS += $(GIOUNIX_CFLAGS) libcpdb_frontend_la_CPPFLAGS += -I.. libcpdb_frontend_la_LIBADD = -lpthread -lm -lcrypt libcpdb_frontend_la_LIBADD += $(GLIB_LIBS) libcpdb_frontend_la_LIBADD += $(GIO_LIBS) libcpdb_frontend_la_LIBADD += $(GIOUNIX_LIBS) libcpdb_frontend_la_LDFLAGS = -no-undefined -version-info 2 cpdb_headersdir = $(includedir)/cpdb cpdb_headers_HEADERS = cpdb.h \ cpdb-frontend.h \ backend.h \ frontend.h nodist_cpdb_headers_HEADERS = backend-interface.h \ frontend-interface.h backend-interface.c backend-interface.h: interface/org.openprinting.Backend.xml $(AM_V_GEN)gdbus-codegen --generate-c-code backend-interface \ --interface-prefix org.openprinting \ interface/org.openprinting.Backend.xml frontend-interface.c frontend-interface.h: interface/org.openprinting.Frontend.xml $(AM_V_GEN)gdbus-codegen --generate-c-code frontend-interface \ --interface-prefix org.openprinting \ interface/org.openprinting.Frontend.xml genfiles = *-interface.* clean-local: rm -f $(genfiles) cpdb-libs-2.0b5/cpdb/backend.h000066400000000000000000000001521446253655700161300ustar00rootroot00000000000000#ifndef _CPDB_BACKEND_H_ #define _CPDB_BACKEND_H_ #include #endif /* !_CPDB_BACKEND_H_ */ cpdb-libs-2.0b5/cpdb/cpdb-frontend.c000066400000000000000000002105361446253655700172720ustar00rootroot00000000000000#include "cpdb-frontend.h" static void on_printer_added (GDBusConnection * connection, const gchar * sender_name, const gchar * object_path, const gchar * interface_name, const gchar * signal_name, GVariant * parameters, gpointer user_data); static void on_printer_removed (GDBusConnection * connection, const gchar * sender_name, const gchar * object_path, const gchar * interface_name, const gchar * signal_name, GVariant * parameters, gpointer user_data); static void on_printer_state_changed (GDBusConnection * connection, const gchar * sender_name, const gchar * object_path, const gchar * interface_name, const gchar * signal_name, GVariant * parameters, gpointer user_data); static void on_name_acquired (GDBusConnection * connection, const gchar * name, gpointer user_data); static void on_name_lost (GDBusConnection * connection, const gchar * name, gpointer user_data); static void fetchPrinterListFromBackend (cpdb_frontend_obj_t * frontend_obj, const char * backend); static void cpdbActivateBackends (cpdb_frontend_obj_t * frontend_obj); static GList * cpdbLoadDefaultPrinters (const char * path); static int cpdbSetDefaultPrinter (const char * path, cpdb_printer_obj_t * printer_obj); static void cpdbFillBasicOptions (cpdb_printer_obj_t * printer_obj, GVariant * variant); static void cpdbDeleteTranslations (cpdb_printer_obj_t * printer_obj); static void cpdbUnpackOptions (int num_options, GVariant * var, int num_media, GVariant * media_var, cpdb_options_t * options); static void cpdbUnpackJobArray (GVariant * var, int num_jobs, cpdb_job_t * jobs, char * backend_name); static GHashTable * cpdbUnpackTranslations (GVariant * translations); /** ________________________________________________ cpdb_frontend_obj_t __________________________________________ **/ cpdb_frontend_obj_t *cpdbGetNewFrontendObj(const char *instance_name, cpdb_printer_callback printer_cb) { cpdb_frontend_obj_t *f = g_new0(cpdb_frontend_obj_t, 1); f->skeleton = print_frontend_skeleton_new(); f->connection = NULL; f->own_id = 0; f->name_done = FALSE; if (instance_name == NULL) f->bus_name = cpdbGetStringCopy(CPDB_DIALOG_BUS_NAME); else f->bus_name = cpdbConcat(CPDB_DIALOG_BUS_NAME, instance_name); f->printer_cb = printer_cb; f->num_backends = 0; f->backend = g_hash_table_new_full(g_str_hash, g_str_equal, free, g_object_unref); f->num_printers = 0; f->printer = g_hash_table_new_full(g_str_hash, g_str_equal, free, NULL); f->last_saved_settings = cpdbReadSettingsFromDisk(); return f; } void cpdbDeleteFrontendObj(cpdb_frontend_obj_t *f) { if (f == NULL) return; logdebug("Deleting frontend obj %s\n", f->bus_name); cpdbDisconnectFromDBus(f); if (f->skeleton) g_object_unref(f->skeleton); if (f->bus_name) free(f->bus_name); if (f->backend) g_hash_table_destroy(f->backend); if (f->printer) g_hash_table_destroy(f->printer); if (f->last_saved_settings) cpdbDeleteSettings(f->last_saved_settings); free(f); } static void on_printer_added(GDBusConnection *connection, const gchar *sender_name, const gchar *object_path, const gchar *interface_name, const gchar *signal_name, GVariant *parameters, gpointer user_data) { cpdb_frontend_obj_t *f = (cpdb_frontend_obj_t *)user_data; cpdb_printer_obj_t *p = cpdbGetNewPrinterObj(); /* If some previously saved settings were retrieved, * use them in this new cpdb_printer_obj_t */ if (f->last_saved_settings != NULL) { cpdbCopySettings(f->last_saved_settings, p->settings); } cpdbFillBasicOptions(p, parameters); cpdbAddPrinter(f, p); f->printer_cb(f, p, CPDB_CHANGE_PRINTER_ADDED); } static void on_printer_removed(GDBusConnection *connection, const gchar *sender_name, const gchar *object_path, const gchar *interface_name, const gchar *signal_name, GVariant *parameters, gpointer user_data) { cpdb_frontend_obj_t *f = (cpdb_frontend_obj_t *)user_data; char *printer_id; char *backend_name; g_variant_get(parameters, "(ss)", &printer_id, &backend_name); cpdb_printer_obj_t *p = cpdbRemovePrinter(f, printer_id, backend_name); f->printer_cb(f, p, CPDB_CHANGE_PRINTER_REMOVED); } static void on_printer_state_changed(GDBusConnection *connection, const gchar *sender_name, const gchar *object_path, const gchar *interface_name, const gchar *signal_name, GVariant *parameters, gpointer user_data) { cpdb_frontend_obj_t *f = (cpdb_frontend_obj_t *) user_data; gboolean printer_is_accepting_jobs; char *printer_id, *printer_state, *backend_name; g_variant_get(parameters, "(ssbs)", &printer_id, &printer_state, &printer_is_accepting_jobs, &backend_name); cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name); if (p->state) free(p->state); p->state = cpdbGetStringCopy(printer_state); p->accepting_jobs = printer_is_accepting_jobs; f->printer_cb(f, p, CPDB_CHANGE_PRINTER_STATE_CHANGED); } static void on_name_acquired(GDBusConnection *connection, const gchar *name, gpointer user_data) { GError *error = NULL; cpdb_frontend_obj_t *f = user_data; logdebug("Acquired bus name %s\n", name); g_dbus_connection_signal_subscribe(connection, NULL, //Sender name "org.openprinting.PrintBackend", //Sender interface CPDB_SIGNAL_PRINTER_ADDED, //Signal name NULL, /**match on all object paths**/ NULL, /**match on all arguments**/ 0, //Flags on_printer_added, //callback user_data, //user_data NULL); g_dbus_connection_signal_subscribe(connection, NULL, //Sender name "org.openprinting.PrintBackend", //Sender interface CPDB_SIGNAL_PRINTER_REMOVED, //Signal name NULL, /**match on all object paths**/ NULL, /**match on all arguments**/ 0, //Flags on_printer_removed, //callback user_data, //user_data NULL); g_dbus_connection_signal_subscribe(connection, NULL, //Sender name "org.openprinting.PrintBackend", //Sender interface CPDB_SIGNAL_PRINTER_STATE_CHANGED, //Signal name NULL, /**match on all object paths**/ NULL, /**match on all arguments**/ 0, //Flags on_printer_state_changed, //callback user_data, //user_data NULL); g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(f->skeleton), connection, CPDB_DIALOG_OBJ_PATH, &error); if (error) { logerror("Error exporting frontend interface : %s\n", error->message); return; } cpdbActivateBackends(f); f->name_done = TRUE; } static void on_name_lost(GDBusConnection *connection, const gchar *name, gpointer user_data) { logdebug("Lost bus name %s\n", name); cpdb_frontend_obj_t *f = user_data; f->name_done = TRUE; } static GDBusConnection *get_dbus_connection() { gchar *bus_addr; GError *error = NULL; GDBusConnection *connection; bus_addr = g_dbus_address_get_for_bus_sync(G_BUS_TYPE_SESSION, NULL, &error); connection = g_dbus_connection_new_for_address_sync(bus_addr, G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT | G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION, NULL, NULL, &error); if (error) { logerror("Error acquiring bus connection : %s\n", error->message); return NULL; } logdebug("Acquired bus connection\n"); return connection; } void cpdbConnectToDBus(cpdb_frontend_obj_t *f) { GMainContext *context; if ((f->connection = get_dbus_connection()) == NULL) { loginfo("Couldn't connect to DBus\n"); return; } f->own_id = g_bus_own_name_on_connection(f->connection, f->bus_name, 0, on_name_acquired, on_name_lost, f, NULL); // Wait till either of name acquired/lost callbacks finish context = g_main_context_get_thread_default(); while (!f->name_done) { g_main_context_iteration(context, TRUE); } } void cpdbDisconnectFromDBus(cpdb_frontend_obj_t *f) { if (f->connection == NULL || g_dbus_connection_is_closed(f->connection)) { logwarn("Already disconnected from DBus\n"); return; } print_frontend_emit_stop_listing(f->skeleton); g_dbus_connection_flush_sync(f->connection, NULL, NULL); g_bus_unown_name(f->own_id); g_dbus_connection_close_sync(f->connection, NULL, NULL); } static void fetchPrinterListFromBackend(cpdb_frontend_obj_t *f, const char *backend) { int num_printers; GVariantIter iter; GVariant *printers, *printer; PrintBackend *proxy; GError *error = NULL; cpdb_printer_obj_t *p; if ((proxy = g_hash_table_lookup(f->backend, backend)) == NULL) { logerror("Couldn't get %s proxy object\n", backend); return; } print_backend_call_get_printer_list_sync (proxy, &num_printers, &printers, NULL, &error); if (error) { logerror("Error getting %s printer list : %s\n", backend, error->message); return; } logdebug("Fetched %d printers from backend %s\n", num_printers, backend); g_variant_iter_init(&iter, printers); while (g_variant_iter_loop(&iter, "(v)", &printer)) { p = cpdbGetNewPrinterObj(); cpdbFillBasicOptions(p, printer); if (f->last_saved_settings != NULL) cpdbCopySettings(f->last_saved_settings, p->settings); cpdbAddPrinter(f, p); } } static void cpdbActivateBackends(cpdb_frontend_obj_t *f) { int len; char *service_name, *backend_suffix; GDBusProxy *dbus_proxy; PrintBackend *backend_proxy; GVariantIter iter; GError *error = NULL; GVariant *service_names, *service_names_tuple; logdebug("Activating backends\n"); dbus_proxy = g_dbus_proxy_new_sync(f->connection, G_DBUS_PROXY_FLAGS_NONE, NULL, "org.freedesktop.DBus", "/org/freedesktop/DBus", "org.freedesktop.DBus", NULL, &error); if (error) { logerror("Error getting dbus proxy : %s", error->message); g_error_free(error); return; } service_names_tuple = g_dbus_proxy_call_sync(dbus_proxy, "ListActivatableNames", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &error); if (error) { logerror("Couldn't get activatable service names %s", error->message); g_error_free(error); return; } service_names = g_variant_get_child_value(service_names_tuple, 0); len = strlen(CPDB_BACKEND_PREFIX); g_variant_iter_init(&iter, service_names); while (g_variant_iter_next(&iter, "s", &service_name)) { if (g_str_has_prefix(service_name, CPDB_BACKEND_PREFIX)) { backend_suffix = cpdbGetStringCopy(service_name + len); loginfo("Found backend %s\n", backend_suffix); backend_proxy = cpdbCreateBackend(f->connection, service_name); g_hash_table_insert(f->backend, backend_suffix, backend_proxy); f->num_backends++; fetchPrinterListFromBackend(f, backend_suffix); } } g_variant_unref(service_names); g_variant_unref(service_names_tuple); g_object_unref(backend_proxy); } PrintBackend *cpdbCreateBackend(GDBusConnection *connection, const char *service_name) { FILE *file = NULL; PrintBackend *proxy; GError *error = NULL; char *path, *backend_name; const char *info_dir_name; char obj_path[CPDB_BSIZE]; backend_name = cpdbGetStringCopy(service_name); proxy = print_backend_proxy_new_sync(connection, 0, backend_name, CPDB_BACKEND_OBJ_PATH, NULL, &error); if (error) { logerror("Error creating backend proxy for %s : %s\n", backend_name, error->message); return NULL; } return proxy; } void cpdbIgnoreLastSavedSettings(cpdb_frontend_obj_t *f) { loginfo("Ignoring previous settings\n"); cpdbDeleteSettings(f->last_saved_settings); f->last_saved_settings = NULL; } gboolean cpdbAddPrinter(cpdb_frontend_obj_t *f, cpdb_printer_obj_t *p) { p->backend_proxy = g_hash_table_lookup(f->backend, p->backend_name); if (p->backend_proxy == NULL) { logerror("Couldn't add printer %s : Backend doesn't exist %s\n", p->id, p->backend_name); return FALSE; } g_object_ref(p->backend_proxy); loginfo("Adding printer %s %s\n", p->id, p->backend_name); cpdbDebugPrinter(p); g_hash_table_insert(f->printer, cpdbConcatSep(p->id, p->backend_name), p); f->num_printers++; return TRUE; } cpdb_printer_obj_t *cpdbRemovePrinter(cpdb_frontend_obj_t *f, const char *printer_id, const char *backend_name) { char *key; cpdb_printer_obj_t *p = NULL; loginfo("Removing printer %s %s\n", printer_id, backend_name); key = cpdbConcatSep(printer_id, backend_name); if (g_hash_table_contains(f->printer, key)) { p = cpdbFindPrinterObj(f, printer_id, backend_name); g_hash_table_remove(f->printer, key); f->num_printers--; } else { logwarn("Printer %s %s not found\n", printer_id, backend_name); } free(key); return p; } void cpdbHideRemotePrinters(cpdb_frontend_obj_t *f) { loginfo("Hiding remote printers\n"); print_frontend_emit_hide_remote_printers(f->skeleton); } void cpdbUnhideRemotePrinters(cpdb_frontend_obj_t *f) { loginfo("Unhiding remote printers\n"); print_frontend_emit_unhide_remote_printers(f->skeleton); } void cpdbHideTemporaryPrinters(cpdb_frontend_obj_t *f) { loginfo("Hiding temporary printers\n"); print_frontend_emit_hide_temporary_printers(f->skeleton); } void cpdbUnhideTemporaryPrinters(cpdb_frontend_obj_t *f) { loginfo("Unhiding temporary printers\n"); print_frontend_emit_unhide_temporary_printers(f->skeleton); } cpdb_printer_obj_t *cpdbFindPrinterObj(cpdb_frontend_obj_t *f, const char *printer_id, const char *backend_name) { char *hashtable_key; cpdb_printer_obj_t *p; if (printer_id == NULL || backend_name == NULL) { logwarn("Invalid parameters: cpdbFindPrinterObj()\n"); return NULL; } hashtable_key = cpdbConcatSep(printer_id, backend_name); p = g_hash_table_lookup(f->printer, hashtable_key); if (p == NULL) { logwarn("Couldn't find printer %s %s : Doesn't exist\n", printer_id, backend_name); } free(hashtable_key); return p; } cpdb_printer_obj_t *cpdbGetDefaultPrinterForBackend(cpdb_frontend_obj_t *f, const char *backend_name) { char *def, *service_name; GError *error = NULL; PrintBackend *proxy; cpdb_printer_obj_t *p = NULL; proxy = g_hash_table_lookup(f->backend, backend_name); if (proxy == NULL) { logwarn("Couldn't find backend proxy for %s\n", backend_name); service_name = cpdbConcat(CPDB_BACKEND_PREFIX, backend_name); proxy = cpdbCreateBackend(f->connection, service_name); free(service_name); if (proxy == NULL) { logerror("Error getting default printer for backend : Couldn't get backend proxy\n"); return NULL; } } print_backend_call_get_default_printer_sync(proxy, &def, NULL, &error); if (error) { logerror("Error getting default printer for backend : %s\n", error->message); return NULL; } p = cpdbFindPrinterObj(f, def, backend_name); if (p) logdebug("Obtained default printer %s for backend %s\n", p->id, backend_name); return p; } GList *cpdbLoadDefaultPrinters(const char *path) { FILE *fp; char buf[CPDB_BSIZE]; GList *printers = NULL; if ((fp = fopen(path, "r")) == NULL) { logwarn("Error loading default printers : Couldn't open %s for reading\n", path); return NULL; } while (fgets(buf, sizeof(buf), fp) != NULL) { buf[strcspn(buf, "\r\n")] = 0; printers = g_list_prepend(printers, cpdbGetStringCopy(buf)); } printers = g_list_reverse(printers); logdebug("Loaded default printers from %s\n", path); fclose(fp); return printers; } cpdb_printer_obj_t *cpdbGetDefaultPrinter(cpdb_frontend_obj_t *f) { gpointer key, value; GHashTableIter iter; char *conf_dir, *path, *printer_id, *backend_name; cpdb_printer_obj_t *default_printer = NULL; GList *printer, *user_printers, *system_printers, *printers = NULL; if (f->num_printers == 0 || f->num_backends == 0) { logwarn("Couldn't get default printer : No printers found\n"); return NULL; } /** Find a default printer from user config first, * before trying system wide config **/ conf_dir = cpdbGetUserConfDir(); if (conf_dir) { path = cpdbConcatPath(conf_dir, CPDB_DEFAULT_PRINTERS_FILE); printers = g_list_concat(printers, cpdbLoadDefaultPrinters(path)); free(path); free(conf_dir); } conf_dir = cpdbGetSysConfDir(); if (conf_dir) { path = cpdbConcatPath(conf_dir, CPDB_DEFAULT_PRINTERS_FILE); printers = g_list_concat(printers, cpdbLoadDefaultPrinters(path)); free(path); free(conf_dir); } for (printer = printers; printer != NULL; printer = printer->next) { printer_id = strtok(printer->data, "#"); backend_name = strtok(NULL, "\n"); default_printer = cpdbFindPrinterObj(f, printer_id, backend_name); if (default_printer) { g_list_free_full(printers, free); goto found; } } if (printers) g_list_free_full(printers, free); logdebug("Couldn't find a valid default printer from config files\n"); /** Fallback to default CUPS printer if CUPS backend exists **/ default_printer = cpdbGetDefaultPrinterForBackend(f, "CUPS"); if (default_printer) goto found; logdebug("Couldn't find a valid default CUPS printer\n"); /** Fallback to default FILE printer if FILE backend exists **/ default_printer = cpdbGetDefaultPrinterForBackend(f, "FILE"); if (default_printer) goto found; logdebug("Couldn't find a valid default FILE printer\n"); /** Fallback to the default printer of first backend found **/ g_hash_table_iter_init(&iter, f->backend); g_hash_table_iter_next(&iter, &key, &value); backend_name = (char *) key; default_printer = cpdbGetDefaultPrinterForBackend(f, backend_name); if (default_printer) goto found; logdebug("Couldn't find a valid default %s printer\n", backend_name); /** Fallback to first printer found **/ g_hash_table_iter_init(&iter, f->printer); g_hash_table_iter_next(&iter, &key, &value); default_printer = (cpdb_printer_obj_t *) value; if (!default_printer) { logerror("Couldn't find a valid printer\n"); return NULL; } found: logdebug("Found default printer %s %s\n", default_printer->id, default_printer->backend_name); return default_printer; } int cpdbSetDefaultPrinter(const char *path, cpdb_printer_obj_t *p) { FILE *fp; char *printer_data; GList *printer, *next, *printers; printers = cpdbLoadDefaultPrinters(path); printer_data = cpdbConcatSep(p->id, p->backend_name); if ((fp = fopen(path, "w")) == NULL) { logerror("Error setting default printer : Couldn't open %s for writing\n", path); return 0; } /* Delete duplicate entries */ printer = printers; while (printer != NULL) { next = printer->next; if (strcmp(printer->data, printer_data) == 0) { free(printer->data); printers = g_list_delete_link(printers, printer); } printer = next; } printers = g_list_prepend(printers, printer_data); for (printer = printers; printer != NULL; printer = printer->next) { fprintf(fp, "%s\n", (char *)printer->data); } g_list_free_full(printers, free); loginfo("Saved default printers to %s", path); fclose(fp); return 1; } int cpdbSetUserDefaultPrinter(cpdb_printer_obj_t *p) { int ret; char *conf_dir, *path; if ((conf_dir = cpdbGetUserConfDir()) == NULL) { logerror("Error setting default printer : Couldn't get system config dir\n"); return 0; } path = cpdbConcatPath(conf_dir, CPDB_DEFAULT_PRINTERS_FILE); ret = cpdbSetDefaultPrinter(path, p); free(path); free(conf_dir); return ret; } int cpdbSetSystemDefaultPrinter(cpdb_printer_obj_t *p) { int ret; char *conf_dir, *path; if ((conf_dir = cpdbGetSysConfDir()) == NULL) { logerror("Error setting default printer : Couldn't get system config dir\n"); return 0; } path = cpdbConcatPath(conf_dir, CPDB_DEFAULT_PRINTERS_FILE); ret = cpdbSetDefaultPrinter(path, p); free(path); free(conf_dir); return ret; } int cpdbGetAllJobs(cpdb_frontend_obj_t *f, cpdb_job_t **j, gboolean active_only) { /**inititalizing the arrays required for each of the backends **/ /** num_jobs[] stores the number of jobs for each of the backends**/ int *num_jobs = g_new(int, f->num_backends); /**backend_names[] stores the name for each of the backends**/ char **backend_names = g_new0(char *, f->num_backends); /**retval[] stores the gvariant returned by the respective backend **/ GVariant **retval = g_new(GVariant *, f->num_backends); GError *error = NULL; gpointer key, value; GHashTableIter iter; int i = 0, total_jobs = 0; /** Iterating over all the backends and getting each's active jobs**/ g_hash_table_iter_init(&iter, f->backend); while (g_hash_table_iter_next(&iter, &key, &value)) { PrintBackend *proxy = (PrintBackend *)value; backend_names[i] = (char *)key; print_backend_call_get_all_jobs_sync(proxy, active_only, &(num_jobs[i]), &(retval[i]), NULL, &error); if(error) { logerror("Error gettings jobs for backend %s : %s\n", backend_names[i], error->message); num_jobs[i] = 0; } else { logdebug("Obtained %d jobs for backend %s\n", num_jobs[i], backend_names[i]); } total_jobs += num_jobs[i]; i++; /** off to the next backend **/ } int n = 0; cpdb_job_t *jobs = g_new(cpdb_job_t, total_jobs); for (i = 0; i < f->num_backends; i++) { if(num_jobs[i]) { cpdbUnpackJobArray(retval[i], num_jobs[i], jobs + n, backend_names[i]); } n += num_jobs[i]; } *j = jobs; free(num_jobs); return total_jobs; } /** ________________________________________________ cpdb_printer_obj_t __________________________________________ **/ cpdb_printer_obj_t *cpdbGetNewPrinterObj() { cpdb_printer_obj_t *p = g_new0 (cpdb_printer_obj_t, 1); p->options = NULL; p->settings = cpdbGetNewSettings(); return p; } static void cpdbDeleteTranslations(cpdb_printer_obj_t *p) { g_free(p->locale); if (p->translations) g_hash_table_destroy(p->translations); p->locale = NULL; p->translations = NULL; } void cpdbDeletePrinterObj(cpdb_printer_obj_t *p) { if (p == NULL) return; logdebug("Deleting printer object %s\n", p->id); if (p->backend_name) free(p->backend_name); if (p->backend_proxy) g_object_unref(p->backend_proxy); if (p->options) cpdbDeleteOptions(p->options); if (p->settings) cpdbDeleteSettings(p->settings); cpdbDeleteTranslations(p); free(p); } void cpdbFillBasicOptions(cpdb_printer_obj_t *p, GVariant *gv) { g_variant_get(gv, CPDB_PRINTER_ADDED_ARGS, &(p->id), &(p->name), &(p->info), &(p->location), &(p->make_and_model), &(p->accepting_jobs), &(p->state), &(p->backend_name)); } void cpdbDebugPrinter(const cpdb_printer_obj_t *p) { logdebug("-------------------------\n"); logdebug("Printer %s\n", p->id); logdebug("name: %s\n", p->name); logdebug("location: %s\n", p->location); logdebug("info: %s\n", p->info); logdebug("make and model: %s\n", p->make_and_model); logdebug("accepting jobs? %s\n", (p->accepting_jobs ? "yes" : "no")); logdebug("state: %s\n", p->state); logdebug("backend: %s\n", p->backend_name); logdebug("-------------------------\n\n"); } gboolean cpdbIsAcceptingJobs(cpdb_printer_obj_t *p) { GError *error = NULL; print_backend_call_is_accepting_jobs_sync(p->backend_proxy, p->id, &p->accepting_jobs, NULL, &error); if (error) { logerror("Error getting accepting_jobs status for %s %s : %s\n", p->id, p->backend_name, error->message); return FALSE; } logdebug("Obtained accepting_jobs=%d; for %s %s\n", p->accepting_jobs, p->id, p->backend_name); return p->accepting_jobs; } char *cpdbGetState(cpdb_printer_obj_t *p) { GError *error = NULL; print_backend_call_get_printer_state_sync(p->backend_proxy, p->id, &p->state, NULL, &error); if (error) { logerror("Error getting printer state for %s %s : %s\n", p->id, p->backend_name, error->message); return NULL; } logdebug("Obtained state=%s; for %s %s\n", p->state, p->id, p->backend_name); return p->state; } cpdb_options_t *cpdbGetAllOptions(cpdb_printer_obj_t *p) { if (p == NULL) { logwarn("Invalid params: cpdbGetAllOptions()\n"); return NULL; } /** * If the options were previously queried, * return them, instead of querying again. */ if (p->options) return p->options; GError *error = NULL; int num_options, num_media; GVariant *var, *media_var; print_backend_call_get_all_options_sync(p->backend_proxy, p->id, &num_options, &var, &num_media, &media_var, NULL, &error); if (error) { logerror("Error getting printer options for %s %s : %s\n", p->id, p->backend_name, error->message); return NULL; } loginfo("Obtained %d options and %d media for %s %s\n", num_options, num_media, p->id, p->backend_name); p->options = cpdbGetNewOptions(); cpdbUnpackOptions(num_options, var, num_media, media_var, p->options); return p->options; } cpdb_option_t *cpdbGetOption(cpdb_printer_obj_t *p, const char *name) { if (p == NULL || name == NULL) { logwarn("Invalid params: cpdbGetOption()\n"); return NULL; } cpdbGetAllOptions(p); return (cpdb_option_t *)(g_hash_table_lookup(p->options->table, name)); } char *cpdbGetDefault(cpdb_printer_obj_t *p, const char *name) { if (p == NULL || name == NULL) { logwarn("Invalid params: cpdbGetDefault()\n"); return NULL; } cpdb_option_t *o = cpdbGetOption(p, name); if (!o) return NULL; return o->default_value; } char *cpdbGetSetting(cpdb_printer_obj_t *p, const char *name) { if (p == NULL || name == NULL) { logwarn("Invalid params: cpdbGetSetting()\n"); return NULL; } if (!g_hash_table_contains(p->settings->table, name)) return NULL; return g_hash_table_lookup(p->settings->table, name); } char *cpdbGetCurrent(cpdb_printer_obj_t *p, const char *name) { char *set = cpdbGetSetting(p, name); if (set) return set; return cpdbGetDefault(p, name); } int cpdbGetActiveJobsCount(cpdb_printer_obj_t *p) { int count; GError *error = NULL; print_backend_call_get_active_jobs_count_sync(p->backend_proxy, p->id, &count, NULL, &error); if (error) { logerror("Error getting active jobs count for % %s : %s\n", p->id, p->backend_name, error->message); return -1; } logdebug("Obtained %d active jobs for %s %s\n", count, p->id, p->backend_name); return count; } static void cpdbDebugPrintSettings(cpdb_settings_t *s) { gpointer key, value; GHashTableIter iter; g_hash_table_iter_init(&iter, s->table); while (g_hash_table_iter_next(&iter, &key, &value)) { logdebug("%s -> %s\n", (char *) key, (char *) value); } } char *cpdbPrintFile(cpdb_printer_obj_t *p, const char *file_path) { char *jobid, *absolute_file_path; GError *error = NULL; absolute_file_path = cpdbGetAbsolutePath(file_path); logdebug("Printing file %s on %s %s\n", absolute_file_path, p->id, p->backend_name); cpdbDebugPrintSettings(p->settings); print_backend_call_print_file_sync(p->backend_proxy, p->id, absolute_file_path, p->settings->count, cpdbSerializeToGVariant(p->settings), "final-file-path-not-required", &jobid, NULL, &error); if (error) { logerror("Error printing file %s on %s %s : %s\n", absolute_file_path, p->id, p->backend_name, error->message); return NULL; } if (jobid == NULL || jobid == "") { logerror("Error printing file %s on %s %s : Couldn't create a job\n", absolute_file_path, p->id, p->backend_name); return NULL; } loginfo("File %s sent for printing on %s %s successfully\n", absolute_file_path, p->id, p->backend_name); cpdbSaveSettingsToDisk(p->settings); free(absolute_file_path); return jobid; } char *cpdbPrintFilePath(cpdb_printer_obj_t *p, const char *file_path, const char *final_file_path) { char *result, *absolute_file_path, *absolute_final_file_path; GError *error = NULL; absolute_file_path = cpdbGetAbsolutePath(file_path); absolute_final_file_path = cpdbGetAbsolutePath(final_file_path); logdebug("Printing file %s on %s %s to %s\n", absolute_file_path, p->id, p->backend_name, absolute_final_file_path); cpdbDebugPrintSettings(p->settings); print_backend_call_print_file_sync(p->backend_proxy, p->id, absolute_file_path, p->settings->count, cpdbSerializeToGVariant(p->settings), absolute_final_file_path, &result, NULL, &error); if (error) { logerror("Error printing file %s to %s : %s\n", absolute_file_path, absolute_final_file_path, error->message); return NULL; } if (result == NULL) { logerror("Error printing file %s to %s\n", absolute_file_path, absolute_final_file_path); return NULL; } loginfo("File %s printed to %s successfully\n", absolute_file_path, absolute_final_file_path); free(absolute_file_path); free(absolute_final_file_path); return result; } void cpdbAddSettingToPrinter(cpdb_printer_obj_t *p, const char *name, const char *val) { if (p == NULL || name == NULL) { logwarn("Invalid params: cpdbAddSettingToPrinter()\n"); return; } cpdbAddSetting(p->settings, name, val); } gboolean cpdbClearSettingFromPrinter(cpdb_printer_obj_t *p, const char *name) { if (p == NULL || name == NULL) { logwarn("Invalid params: cpdbClearSettingFromPrinter()\n"); return FALSE; } return cpdbClearSetting(p->settings, name); } gboolean cpdbCancelJob(cpdb_printer_obj_t *p, const char *job_id) { gboolean status; GError *error = NULL; print_backend_call_cancel_job_sync(p->backend_proxy, job_id, p->id, &status, NULL, &error); if (error) { logerror("Error cancelling job %s on %s %s\n", job_id, p->id, p->backend_name, error->message); return FALSE; } logdebug("Obtained status=%d for cancelling job %s on %s %s\n", status, job_id, p->id, p->backend_name); return status; } void cpdbPicklePrinterToFile(cpdb_printer_obj_t *p, const char *filename, const cpdb_frontend_obj_t *parent_dialog) { FILE *fp; char *path; const char *unique_bus_name; GHashTableIter iter; gpointer key, value; GError *error = NULL; print_backend_call_keep_alive_sync(p->backend_proxy, NULL, &error); if (error) { logerror("Error keeping backend %s alive : %s\n", p->backend_name, error->message); return; } loginfo("Keeping backend %s alive\n", p->backend_name); path = cpdbGetAbsolutePath(filename); if ((fp = fopen(path, "w")) == NULL) { logerror("Error pickling printer %s %s : Couldn't open %s for writing\n", p->id, p->backend_name, path); return; } unique_bus_name = g_dbus_connection_get_unique_name(parent_dialog->connection); if (unique_bus_name == NULL) { logerror("Error pickling printer %s %s: Couldn't get unique bus name\n", p->id, p->backend_name); return; } fprintf(fp, "%s#\n", unique_bus_name); fprintf(fp, "%s#\n", p->backend_name); fprintf(fp, "%s#\n", p->id); fprintf(fp, "%s#\n", p->name); fprintf(fp, "%s#\n", p->location); fprintf(fp, "%s#\n", p->info); fprintf(fp, "%s#\n", p->make_and_model); fprintf(fp, "%s#\n", p->state); fprintf(fp, "%d\n", p->accepting_jobs); /* Not pickling the cpdb_options_t, * because it can be reconstructed by querying the backend */ fprintf(fp, "%d\n", p->settings->count); g_hash_table_iter_init(&iter, p->settings->table); while (g_hash_table_iter_next(&iter, &key, &value)) { fprintf(fp, "%s#%s#\n", (char *)key, (char *)value); } loginfo("Pickled printer %s %s to %s\n", p->id, p->backend_name, path); fclose(fp); free(path); } cpdb_printer_obj_t *cpdbResurrectPrinterFromFile(const char *filename) { FILE *fp; int count; char buf[CPDB_BSIZE]; GDBusConnection *connection; char *name, *value, *path = NULL; char *service_name = NULL, *previous_parent_dialog = NULL; GError *error = NULL; cpdb_printer_obj_t *p; path = cpdbGetAbsolutePath(filename); if ((fp = fopen(path, "r")) == NULL) { logerror("Error resurrecting printer : Couldn't open %s for reading\n", path); goto failed; } p = cpdbGetNewPrinterObj(); if (fgets(buf, sizeof(buf), fp) == NULL) goto parse_error; previous_parent_dialog = cpdbGetStringCopy(strtok(buf, "#")); if (fgets(buf, sizeof(buf), fp) == NULL) goto parse_error; p->backend_name = cpdbGetStringCopy(strtok(buf, "#")); service_name = cpdbConcat(CPDB_BACKEND_PREFIX, p->backend_name); if ((connection = get_dbus_connection()) == NULL) { logerror("Error resurrecting printer : Couldn't get dbus connection\n"); goto failed; } p->backend_proxy = cpdbCreateBackend(connection, service_name); free(service_name); print_backend_call_replace_sync(p->backend_proxy, previous_parent_dialog, NULL, &error); if (error) { logerror("Error replacing resurrected printer : %s\n", error->message); goto failed; } if (fgets(buf, sizeof(buf), fp) == NULL) goto parse_error; p->id = cpdbGetStringCopy(strtok(buf, "#")); if (fgets(buf, sizeof(buf), fp) == NULL) goto parse_error; p->name = cpdbGetStringCopy(strtok(buf, "#")); if (fgets(buf, sizeof(buf), fp) == NULL) goto parse_error; p->location = cpdbGetStringCopy(strtok(buf, "#")); if (fgets(buf, sizeof(buf), fp) == NULL) goto parse_error; p->info = cpdbGetStringCopy(strtok(buf, "#")); if (fgets(buf, sizeof(buf), fp) == NULL) goto parse_error; p->make_and_model = cpdbGetStringCopy(strtok(buf, "#")); if (fgets(buf, sizeof(buf), fp) == NULL) goto parse_error; p->state = cpdbGetStringCopy(strtok(buf, "#")); if (fscanf(fp, "%d\n", &p->accepting_jobs) == 0) goto parse_error; cpdbDebugPrinter(p); if (fscanf(fp, "%d\n", &count) == 0) goto parse_error; while (count--) { if (fgets(buf, sizeof(buf), fp) == NULL) goto parse_error; name = strtok(buf, "#"); value = strtok(NULL, "#"); cpdbAddSetting(p->settings, name, value); } loginfo("Resurrected printer %s %s from %s\n", p->id, p->backend_name, filename); fclose(fp); free(path); free(service_name); free(previous_parent_dialog); return p; parse_error: logerror("Error resurrecting printer : Coudln't parse %s\n", path); failed: if (fp) fclose(fp); free(path); if (service_name) free(service_name); if (previous_parent_dialog) free(previous_parent_dialog); return NULL; } char *cpdbGetOptionTranslation(cpdb_printer_obj_t *p, const char *option_name, const char *locale) { char *name_key, *translation; GError *error = NULL; if (p == NULL || option_name == NULL || locale == NULL) { logwarn("Invalid paramaters: cpdbGetOptionTranslation()\n"); return NULL; } if (p->locale != NULL && strcmp(p->locale, locale) == 0) { name_key = cpdbConcatSep(CPDB_OPT_PREFIX, option_name); translation = g_hash_table_lookup(p->translations, name_key); free(name_key); if (translation) { logdebug("Found translation=%s; for option=%s;locale=%s;printer=%s#%s;\n", translation, option_name, locale, p->id, p->backend_name); return cpdbGetStringCopy(translation); } } print_backend_call_get_option_translation_sync(p->backend_proxy, p->id, option_name, locale, &translation, NULL, &error); if (error) { logerror("Error getting translation for option=%s;locale=%s;printer=%s#%s; : %s\n", option_name, locale, p->id, p->backend_name, error->message); return NULL; } logdebug("Obtained translation=%s; for option=%s;locale=%s;printer=%s#%s;\n", translation, option_name, locale, p->id, p->backend_name); return cpdbGetStringCopy(translation); } char *cpdbGetChoiceTranslation(cpdb_printer_obj_t *p, const char *option_name, const char *choice_name, const char *locale) { char *name_key, *choice_key, *translation; GError *error = NULL; if (p == NULL || option_name == NULL || choice_name == NULL || locale == NULL) { logwarn("Invalid paramaters: cpdbGetChoiceTranslation()\n"); return NULL; } if (p->locale != NULL && strcmp(p->locale, locale) == 0) { name_key = cpdbConcatSep(CPDB_OPT_PREFIX, option_name); choice_key = cpdbConcatSep(name_key, choice_name); translation = g_hash_table_lookup(p->translations, choice_key); free(name_key); free(choice_key); if (translation) { logdebug("Found translation=%s; for option=%s;choice=%s;locale=%s;printer=%s#%s;\n", translation, option_name, choice_name, locale, p->id, p->backend_name); return cpdbGetStringCopy(translation); } } print_backend_call_get_choice_translation_sync(p->backend_proxy, p->id, option_name, choice_name, locale, &translation, NULL, &error); if (error) { logerror("Error getting translation for option=%s;choice=%s;locale=%s;printer=%s#%s; : %s\n", option_name, choice_name, locale, p->id, p->backend_name, error->message); return NULL; } logdebug("Obtained translation=%s; for option=%s;choice=%s;locale=%s;printer=%s#%s;\n", translation, option_name, choice_name, locale, p->id, p->backend_name); return cpdbGetStringCopy(translation); } char *cpdbGetGroupTranslation(cpdb_printer_obj_t *p, const char *group_name, const char *locale) { char *group_key, *translation; GError *error = NULL; if (p == NULL || group_name == NULL || locale == NULL) { logwarn("Invalid paramaters: cpdbGetGroupTranslation()\n"); return NULL; } if (p->locale != NULL && strcmp(p->locale, locale) == 0) { group_key = cpdbConcatSep(CPDB_GRP_PREFIX, group_name); translation = g_hash_table_lookup(p->translations, group_key); free(group_key); if (translation) { logdebug("Found translation=%s; for group=%s;locale=%s;printer=%s#%s;\n", translation, group_name, locale, p->id, p->backend_name); return cpdbGetStringCopy(translation); } } print_backend_call_get_group_translation_sync(p->backend_proxy, p->id, group_name, locale, &translation, NULL, &error); if (error) { logerror("Error getting translation for group=%s;locale=%s;printer=%s#%s; : %s\n", group_name, locale, p->id, p->backend_name, error->message); return NULL; } logdebug("Obtained translation=%s; for group=%s;locale=%s;printer=%s#%s;\n", translation, group_name, locale, p->id, p->backend_name); return cpdbGetStringCopy(translation); } void cpdbGetAllTranslations(cpdb_printer_obj_t *p, const char *locale) { GVariant *translations; GError *error = NULL; if (p == NULL || locale == NULL) { logwarn("Invalid parameters: cpdbGetAllTranslations()\n"); return; } if (p->locale != NULL && strcmp(p->locale, locale) == 0) return; print_backend_call_get_all_translations_sync(p->backend_proxy, p->id, locale, &translations, NULL, &error); if (error) { logerror("Error getting printer translations in %s for %s %s : %s\n", locale, p->id, p->backend_name, error->message); return; } logdebug("Fetched translations for printer %s %s\n", p->id, p->backend_name); cpdbDeleteTranslations(p); p->locale = cpdbGetStringCopy(locale); p->translations = cpdbUnpackTranslations(translations); } cpdb_media_t *cpdbGetMedia(cpdb_printer_obj_t *p, const char *media) { cpdbGetAllOptions(p); return (cpdb_media_t *) g_hash_table_lookup(p->options->media, media); } int cpdbGetMediaSize(cpdb_printer_obj_t *p, const char *media, int *width, int *length) { cpdb_media_t *m = cpdbGetMedia(p, media); if (m) { *width = m->width; *length = m->length; return 1; } return 0; } int cpdbGetMediaMargins(cpdb_printer_obj_t *p, const char *media, cpdb_margin_t **margins) { int num_margins = 0; cpdb_media_t *m = cpdbGetMedia(p, media); if (m) { num_margins = m->num_margins; *margins = m->margins; } return num_margins; } typedef struct { cpdb_printer_obj_t *p; cpdb_async_callback caller_cb; void *user_data; } cpdb_async_details_obj_t; void acquire_details_cb(PrintBackend *proxy, GAsyncResult *res, gpointer user_data) { cpdb_async_details_obj_t *a = user_data; cpdb_printer_obj_t *p = a->p; cpdb_async_callback caller_cb = a->caller_cb; p->options = cpdbGetNewOptions(); GError *error = NULL; int num_options, num_media; GVariant *var, *media_var; print_backend_call_get_all_options_finish (proxy, &num_options, &var, &num_media, &media_var, res, &error); if (error) { logerror("Error acquiring printer details for %s %s : %s\n", p->id, p->backend_name, error->message); if (caller_cb) caller_cb(p, FALSE, a->user_data); } else { loginfo("Acquired %d options and %d media for %s %s\n", num_options, num_media, p->id, p->backend_name); cpdbUnpackOptions(num_options, var, num_media, media_var, p->options); if (caller_cb) caller_cb(p, TRUE, a->user_data); } free(a); } void cpdbAcquireDetails(cpdb_printer_obj_t *p, cpdb_async_callback caller_cb, void *user_data) { if (p == NULL) { logwarn("Invalid parameters: cpdbAcquireDetails()\n"); return; } if (p->options) { if (caller_cb) caller_cb(p, TRUE, user_data); return; } cpdb_async_details_obj_t *a = g_new0(cpdb_async_details_obj_t, 1); a->p = p; a->caller_cb = caller_cb; a->user_data = user_data; logdebug("Acquiring printer details for %s %s\n", p->id, p->backend_name); print_backend_call_get_all_options(p->backend_proxy, p->id, NULL, (GAsyncReadyCallback) acquire_details_cb, a); } typedef struct { cpdb_printer_obj_t *p; char *locale; cpdb_async_callback caller_cb; void *user_data; } cpdb_async_translations_obj_t; static void acquire_translations_cb(PrintBackend *proxy, GAsyncResult *res, gpointer user_data) { GError *error = NULL; GVariant *translations; cpdb_async_translations_obj_t *a = user_data; cpdb_printer_obj_t *p = a->p; print_backend_call_get_all_translations_finish(proxy, &translations, res, &error); if (error) { logerror("Error getting printer translations for %s %s : %s\n", p->id, p->backend_name, error->message); a->caller_cb(p, FALSE, a->user_data); } else { cpdbDeleteTranslations(p); p->locale = cpdbGetStringCopy(a->locale); p->translations = cpdbUnpackTranslations(translations); a->caller_cb(p, TRUE, a->user_data); } free(a->locale); free(a); } void cpdbAcquireTranslations(cpdb_printer_obj_t *p, const char *locale, cpdb_async_callback caller_cb, void *user_data) { if (p == NULL || locale == NULL) { logwarn("Invalid parameters: cpdbAcquireTranslations()\n"); return; } if (p->locale != NULL && strcmp(locale, p->locale) == 0) { caller_cb(p, TRUE, user_data); return; } cpdb_async_translations_obj_t *a = g_new0(cpdb_async_translations_obj_t, 1); a->p = p; a->locale = cpdbGetStringCopy(locale); a->caller_cb = caller_cb; a->user_data = user_data; logdebug("Acquiring printer translations for %s %s\n", p->id, p->backend_name); print_backend_call_get_all_translations(p->backend_proxy, p->id, locale, NULL, (GAsyncReadyCallback) acquire_translations_cb, a); } /** ________________________________________________ cpdb_settings_t __________________________________________ **/ cpdb_settings_t *cpdbGetNewSettings() { cpdb_settings_t *s = g_new0(cpdb_settings_t, 1); s->count = 0; s->table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); return s; } void cpdbCopySettings(const cpdb_settings_t *source, cpdb_settings_t *dest) { if (source == NULL || dest == NULL) { logwarn("Invalid params: cpdbCopySettings()\n"); return; } GHashTableIter iter; g_hash_table_iter_init(&iter, source->table); gpointer key, value; while (g_hash_table_iter_next(&iter, &key, &value)) { cpdbAddSetting(dest, (char *)key, (char *)value); } } void cpdbAddSetting(cpdb_settings_t *s, const char *name, const char *val) { if (s == NULL || name == NULL) { logwarn("Invalid params: cpdbAddSettings()\n"); return; } gboolean new_entry = g_hash_table_insert(s->table, cpdbGetStringCopy(name), cpdbGetStringCopy(val)); if (new_entry) s->count++; } gboolean cpdbClearSetting(cpdb_settings_t *s, const char *name) { if (s == NULL || name == NULL) { logwarn("Invalid params: cpdbClearSetting()\n"); return FALSE; } if (g_hash_table_contains(s->table, name)) { g_hash_table_remove(s->table, name); s->count--; return TRUE; } else { return FALSE; } } GVariant *cpdbSerializeToGVariant(cpdb_settings_t *s) { GVariantBuilder *builder; GVariant *variant; builder = g_variant_builder_new(G_VARIANT_TYPE("a(ss)")); GHashTableIter iter; g_hash_table_iter_init(&iter, s->table); gpointer key, value; for (int i = 0; i < s->count; i++) { g_hash_table_iter_next(&iter, &key, &value); g_variant_builder_add(builder, "(ss)", key, value); } if (s->count == 0) g_variant_builder_add(builder, "(ss)", "NA", "NA"); variant = g_variant_new("a(ss)", builder); return variant; } void cpdbSaveSettingsToDisk(cpdb_settings_t *s) { FILE *fp; char *conf_dir, *path; GHashTableIter iter; gpointer key, value; if ((conf_dir = cpdbGetUserConfDir()) == NULL) { logerror("Error saving settings to disk : Couldn't obtain user config dir\n"); return; } path = cpdbConcatPath(conf_dir, CPDB_PRINT_SETTINGS_FILE); if ((fp = fopen(path, "w")) == NULL) { logerror("Error saving settings to disk : Couldn't open %s for writing\n", path); return; } fprintf(fp, "%d\n", s->count); g_hash_table_iter_init(&iter, s->table); while (g_hash_table_iter_next(&iter, &key, &value)) { fprintf(fp, "%s#%s#\n", (char *)key, (char *)value); } loginfo("Saved %d settings on disk to %s\n", s->count, path); fclose(fp); free(path); free(conf_dir); } cpdb_settings_t *cpdbReadSettingsFromDisk() { FILE *fp; int count; char *name, *value, *conf_dir, *path; char buf[CPDB_BSIZE]; cpdb_settings_t *s; if ((conf_dir = cpdbGetUserConfDir()) == NULL) { logerror("No previous settings found : Couldn't obtain user config dir\n"); return NULL; } path = cpdbConcatPath(conf_dir, CPDB_PRINT_SETTINGS_FILE); if ((fp = fopen(path, "r")) == NULL) { loginfo("No previous settings found : Couldn't open %s for reading\n", path); free(path); free(conf_dir); return NULL; } s = cpdbGetNewSettings(); if (fscanf(fp, "%d\n", &count) == 0) { logerror("Error getting settings from disk : Couldn't parse %s\n", path); fclose(fp); free(path); free(conf_dir); cpdbDeleteSettings(s); return NULL; } while (count--) { if (fgets(buf, sizeof(buf), fp) == NULL) break; name = strtok(buf, "#"); value = strtok(NULL, "#"); cpdbAddSetting(s, name, value); } loginfo("Retrievied %d settings from disk at %s\n", s->count, path); fclose(fp); free(path); free(conf_dir); return s; } void cpdbDeleteSettings(cpdb_settings_t *s) { if (s == NULL) return; if (s->table) g_hash_table_destroy(s->table); free(s); } /** ________________________________________________ cpdb_options_t __________________________________________ **/ cpdb_options_t *cpdbGetNewOptions() { cpdb_options_t *o = g_new0(cpdb_options_t, 1); o->count = 0; o->table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify) cpdbDeleteOption); o->media_count = 0; o->media = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify) cpdbDeleteMedia); return o; } void cpdbDeleteOptions(cpdb_options_t *opts) { if (opts == NULL) return; if (opts->table) g_hash_table_destroy(opts->table); if (opts->media) g_hash_table_destroy(opts->media); free(opts); } /**************cpdb_option_t************************************/ void cpdbDeleteOption(cpdb_option_t *opt) { if (opt == NULL) return; if (opt->option_name) free(opt->option_name); if (opt->group_name) free(opt->group_name); if (opt->supported_values) free(opt->supported_values); if (opt->default_value) free(opt->default_value); free(opt); } /**************cpdb_option_t************************************/ void cpdbDeleteMedia(cpdb_media_t *media) { if (media == NULL) return; if (media->name) free(media->name); if (media->margins) free(media->margins); free(media); } /** * ________________________________ cpdb_job_t __________________________ */ void cpdbUnpackJobArray(GVariant *var, int num_jobs, cpdb_job_t *jobs, char *backend_name) { int i; char *str; GVariantIter *iter; g_variant_get(var, CPDB_JOB_ARRAY_ARGS, &iter); int size; char *jobid, *title, *printer, *user, *state, *submit_time; for (i = 0; i < num_jobs; i++) { g_variant_iter_loop(iter, CPDB_JOB_ARGS, &jobid, &title, &printer, &user, &state, &submit_time, &size); logdebug("jobid=%s;\n", jobid); jobs[i].job_id = cpdbGetStringCopy(jobid); logdebug("title=%s;\n", title); jobs[i].title = cpdbGetStringCopy(title); logdebug("printer=%s;\n", printer); jobs[i].printer_id = cpdbGetStringCopy(printer); logdebug("backend_name=%s;\n", backend_name); jobs[i].backend_name = backend_name; logdebug("user=%s;\n", user); jobs[i].user = cpdbGetStringCopy(user); logdebug("state=%s;\n", state); jobs[i].state = cpdbGetStringCopy(state); logdebug("submit_time=%s;\n", submit_time); jobs[i].submitted_at = cpdbGetStringCopy(submit_time); logdebug("size=%d;\n", size); jobs[i].size = size; } } /** * ________________________________utility functions__________________________ */ void cpdbUnpackOptions(int num_options, GVariant *opts_var, int num_media, GVariant *media_var, cpdb_options_t *options) { cpdb_option_t *opt; cpdb_media_t *media; char buf[CPDB_BSIZE]; int i, j, num, width, length, l, r, t, b; GVariantIter *iter, *sub_iter; char *str, *name, *def, *group; options->count = num_options; g_variant_get(opts_var, "a(sssia(s))", &iter); for (i = 0; i < num_options; i++) { opt = g_new0(cpdb_option_t, 1); g_variant_iter_loop(iter, "(sssia(s))", &name, &group, &def, &num, &sub_iter); logdebug("name=%s;\n", name); opt->option_name = cpdbGetStringCopy(name); logdebug("group=%s;\n", group); opt->group_name = cpdbGetStringCopy(group); logdebug("default=%s;\n", def); opt->default_value = cpdbGetStringCopy(def); logdebug("num_choices=%d;\n", num); opt->num_supported = num; logdebug("choices:\n"); opt->supported_values = cpdbNewCStringArray(num); for (j = 0; j < num; j++) { g_variant_iter_loop(sub_iter, "(s)", &str); logdebug(" %s;\n", str); opt->supported_values[j] = cpdbGetStringCopy(str); } g_hash_table_insert(options->table, cpdbGetStringCopy(opt->option_name), opt); } options->media_count = num_media; g_variant_get(media_var, "a(siiia(iiii))", &iter); for (i = 0; i < num_media; i++) { media = g_new0(cpdb_media_t, 1); g_variant_iter_loop(iter, "(siiia(iiii))", &name, &width, &length, &num, &sub_iter); logdebug("name=%s;\n", name); media->name = cpdbGetStringCopy(name); logdebug("width=%d;\n", width); media->width = width; logdebug("length=%d;\n", length); media->length = length; logdebug("num_margins=%d;\n", num); media->num_margins = num; media->margins = g_new0(cpdb_margin_t, num); for (j = 0; j < num; j++) { g_variant_iter_loop(sub_iter, "(iiii)", &l, &r, &t, &b); logdebug(" %d,%d,%d,%d;\n", l, r, t, b); media->margins[j].left = l; media->margins[j].right = r; media->margins[j].top = t; media->margins[j].bottom = b; } g_hash_table_insert(options->media, cpdbGetStringCopy(media->name), media); } } static GHashTable *cpdbUnpackTranslations (GVariant *variant) { GVariantIter iter; gchar *key, *value; GHashTable *translations; translations = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free); g_variant_iter_init(&iter, variant); while (g_variant_iter_loop(&iter, CPDB_TL_ARGS, &key, &value)) { logdebug("Fetched translation '%s' : '%s'\n", key, value); g_hash_table_insert(translations, cpdbGetStringCopy(key), cpdbGetStringCopy(value)); } return translations; } /************************************************************************************************/ cpdb-libs-2.0b5/cpdb/cpdb-frontend.h000066400000000000000000000535201446253655700172750ustar00rootroot00000000000000#ifndef _CPDB_CPDB_FRONTEND_H_ #define _CPDB_CPDB_FRONTEND_H_ #include #ifdef __cplusplus extern "C" { #endif #include #include #include #include #include #define CPDB_DIALOG_BUS_NAME "org.openprinting.PrintFrontend" #define CPDB_DIALOG_OBJ_PATH "/" #define CPDB_BACKEND_PREFIX "org.openprinting.Backend." /* Names of default config files */ #define CPDB_PRINT_SETTINGS_FILE "print-settings" #define CPDB_DEFAULT_PRINTERS_FILE "default-printers" /* Debug macros */ #define logdebug(...) cpdbFDebugPrintf(CPDB_DEBUG_LEVEL_DEBUG, __VA_ARGS__) #define loginfo(...) cpdbFDebugPrintf(CPDB_DEBUG_LEVEL_INFO, __VA_ARGS__) #define logwarn(...) cpdbFDebugPrintf(CPDB_DEBUG_LEVEL_WARN, __VA_ARGS__) #define logerror(...) cpdbFDebugPrintf(CPDB_DEBUG_LEVEL_ERROR, __VA_ARGS__) typedef struct cpdb_frontend_obj_s cpdb_frontend_obj_t; typedef struct cpdb_printer_obj_s cpdb_printer_obj_t; typedef struct cpdb_settings_s cpdb_settings_t; typedef struct cpdb_options_s cpdb_options_t; typedef struct cpdb_option_s cpdb_option_t; typedef struct cpdb_margin_s cpdb_margin_t; typedef struct cpdb_media_s cpdb_media_t; typedef struct cpdb_job_s cpdb_job_t; typedef enum cpdb_printer_update_e { CPDB_CHANGE_PRINTER_ADDED, CPDB_CHANGE_PRINTER_REMOVED, CPDB_CHANGE_PRINTER_STATE_CHANGED, } cpdb_printer_update_t; /** * Callback for printer updates * * @param frontend_obj Frontend instance * @param printer_obj Printer object updated * @param update Type of update */ typedef void (*cpdb_printer_callback)(cpdb_frontend_obj_t *frontend_obj, cpdb_printer_obj_t *printer_obj, cpdb_printer_update_t update); /** * Callback for async functions * * @param printer_obj Printer object * @param status Success status * @param user_data User data */ typedef void (*cpdb_async_callback)(cpdb_printer_obj_t *printer_obj, int status, void *user_data); /*********************definitions ***************************/ /** ______________________________________ cpdb_frontend_obj_t __________________________________________ **/ struct cpdb_frontend_obj_s { PrintFrontend *skeleton; GDBusConnection *connection; int own_id; gboolean name_done; char *bus_name; cpdb_printer_callback printer_cb; int num_backends; GHashTable *backend; /**[backend name(like "CUPS" or "GCP")] ---> [BackendObj]**/ int num_printers; GHashTable *printer; /**[printer name] --> [cpdb_printer_obj_t] **/ cpdb_settings_t *last_saved_settings; /** The last saved settings to disk */ }; /** * Get a new cpdb_frontend_obj_t instance. * * @param instance_name Unique name for the frontend object, can be NULL * @param printer_cb Callback function for any printer updates * @param change Type of update * * @return Frontend instance */ cpdb_frontend_obj_t *cpdbGetNewFrontendObj(const char *instance_name, cpdb_printer_callback printer_cb); /** * Free up a frontend instance. * * @param frontend_obj Frontend instance to be deleted */ void cpdbDeleteFrontendObj(cpdb_frontend_obj_t *frontend_obj); /** * Connect to DBus, activate the CPDB backends and fetch printers. * * @param frontend_obj Frontend instance to connect to DBus */ void cpdbConnectToDBus(cpdb_frontend_obj_t *frontend_obj); /** * Disconnect from the DBus. * * Use cpdbDeleteFrontendObj() directly instead * which internally calls this function before deallocating the instance * * @param frontend_obj Frontend instance connected to DBus */ void cpdbDisconnectFromDBus(cpdb_frontend_obj_t *frontend_obj); /** * The default behaviour of cpdb_frontend_obj_t is to use the * settings previously saved to disk the last time any print dialog ran. * * To ignore the last saved settings, you need to explicitly call this function * after cpdbGetNewFrontendObj() * * @param frontend_obj Frontend instance */ void cpdbIgnoreLastSavedSettings(cpdb_frontend_obj_t *frontend_obj); /** * Add the printer to the frontend instance * * @param frontend_obj Frontend instance * @param printer_obj Printer object * * @return Success status */ gboolean cpdbAddPrinter(cpdb_frontend_obj_t *frontend_obj, cpdb_printer_obj_t *printer_obj); /** * Remove the printer from the frontend instance. * * @param frontend_obj Frontend instance * @param printer_id Printer ID * @param backend_name Backend name * * @return * The printer object corresponding to the printer just removed, * or NULL if the removal was unsuccesful. * * The caller is responsible for deallocating the printer object. */ cpdb_printer_obj_t *cpdbRemovePrinter(cpdb_frontend_obj_t *f, const char *printer_id, const char *backend_name); /** * Hide the remote printers of the backend. * * @param frontend_obj Frontend instance */ void cpdbHideRemotePrinters(cpdb_frontend_obj_t *frontend_obj); /** * Unhide the remote printers of the backend. * * @param frontend_obj Frontend instance */ void cpdbUnhideRemotePrinters(cpdb_frontend_obj_t *frontend_obj); /** * Hide those (temporary) printers which have been discovered by the backend, * but haven't been yet set up locally. * * @param frontend_obj Frontend instance */ void cpdbHideTemporaryPrinters(cpdb_frontend_obj_t *frontend_obj); /** * Unhide those (temporary) printers which have been discovered by the backend, * but haven't been yet set up locally. * * @param frontend_obj Frontend instance */ void cpdbUnhideTemporaryPrinters(cpdb_frontend_obj_t *frontend_obj); /** * Read the file installed by the backend and create a proxy object * on the connection using the backend service name and object path */ PrintBackend *cpdbCreateBackend(GDBusConnection *, const char *); /** * Find the cpdb_printer_obj_t instance with a particular id and backend name. * * @param frontend_obj Frontend instance * @param printer_id Printer ID * @param backend_name Backend name * * @return Printer object if found, NULL otherwise. */ cpdb_printer_obj_t *cpdbFindPrinterObj(cpdb_frontend_obj_t *frontend_obj, const char *printer_id, const char *backend_name); /** * Get the default printer for a particular CPDB backend. * * @param frontend_obj Frontend instance * @param backend_name Backend name * * @return Default printer for backend if found, NULL otherwise */ cpdb_printer_obj_t *cpdbGetDefaultPrinterForBackend(cpdb_frontend_obj_t *frontend_obj, const char *backend_name); /** * Get the most preferred default printer. * Always returns a printer, unless there are no printers connected to the frontend. * * @param frontend_obj Frontend instance * * @return Default printer if any exists, NULL otherwise */ cpdb_printer_obj_t *cpdbGetDefaultPrinter(cpdb_frontend_obj_t *frontend_obj); /** * Set a printer as user default. * * @param printer_obj Printer object * * @return TRUE on success, FALSE on failure */ gboolean cpdbSetUserDefaultPrinter(cpdb_printer_obj_t *p); /** * Set a printer as system wide default. * * @param printer_obj Printer object * * @return TRUE on success, FALSE on failure */ gboolean cpdbSetSystemDefaultPrinter(cpdb_printer_obj_t *p); /** * Get the list of (all/active) jobs from all the backends for all users. * * @param jobs Pointer to a cpdb_job_t array. The retrieved job list array is stored at this location * @param active_only If TRUE, retrieves only the active jobs, otherwise retrieves all(active + completed + stopped) jobs * * @return Number of jobs (i.e. length of the cpdb_job_t array) * */ int cpdbGetAllJobs(cpdb_frontend_obj_t *frontend_obj, cpdb_job_t **jobs, gboolean active_only); /*******************************************************************************************/ /** ______________________________________ cpdb_printer_obj_t __________________________________________ **/ struct cpdb_printer_obj_s { PrintBackend *backend_proxy; /** The proxy object of the backend the printer is associated with **/ char *backend_name; /** Backend name ,("CUPS"/ "GCP") also used as suffix */ /**The basic attributes first**/ char *id; char *name; char *location; char *info; char *make_and_model; char *state; gboolean accepting_jobs; /** The more advanced options we get from the backend **/ cpdb_options_t *options; /**The settings the user selects, and which will be used for printing the job**/ cpdb_settings_t *settings; /** Translations **/ char *locale; GHashTable *translations; }; /** * Get a new empty printer object. * * @return Printer object */ cpdb_printer_obj_t *cpdbGetNewPrinterObj(); /** * Free up a printer object. * * @param printer_obj Printer object */ void cpdbDeletePrinterObj(cpdb_printer_obj_t *printer_obj); /** * Print basic printer info to debug logs. * * @param printer_obj Printer object */ void cpdbDebugPrinter(const cpdb_printer_obj_t *printer_obj); /** * Update and return whether printer is accepting jobs. * * @param printer_obj Printer object * * @return TRUE if printer is accepting jobs, otherwise FALSE */ gboolean cpdbIsAcceptingJobs(cpdb_printer_obj_t *printer_obj); /** * Update and return printer status. * * @param printer_obj Printer object * * @return Printer status */ char *cpdbGetState(cpdb_printer_obj_t *printer_obj); /** * Get all the different options and values supported by a printer. * * @param printer_obj Printer object * * @return Options struct */ cpdb_options_t *cpdbGetAllOptions(cpdb_printer_obj_t *printer_obj); /** * Get a single cpdb_option_t struct corresponding to an option name for a printer. * * @param printer_obj Printer object * @param option_name Option name * * @return Option struct if it exists, otherwise NULL */ cpdb_option_t *cpdbGetOption(cpdb_printer_obj_t *printer_obj, const char *option_name); /** * Get the default option value for a printer. * * @param printer_obj Printer object * @param option_name Option name * * @return Default value if exists. * "NA" if option is present, but default value isn't set. * NULL if option doesn't exist. */ char *cpdbGetDefault(cpdb_printer_obj_t *p, const char *option_name); /** * Get the option value set for a printer. * * @param printer_obj Printer object * @param option_name Option name * * @return Value if set, NULL otherwise */ char *cpdbGetSetting(cpdb_printer_obj_t *p, const char *option_name); /** * Get the option value set for a printer. If not set, get the default option value. * * @param printer_obj Printer object * @param option_name Option name * * @return Current value for an option */ char *cpdbGetCurrent(cpdb_printer_obj_t *printer_obj, const char *option_name); /** * Get the number of active jobs(pending + paused + printing) on a printer. * * @param printer_obj Printer object * * @return Number of active jobs */ int cpdbGetActiveJobsCount(cpdb_printer_obj_t *printer_obj); /** * Submit a file for printing, using the settings set previously. * * @param printer_obj Printer object * @param file_path Path of file to print * * @return Job ID if created, NULL otherwise */ char *cpdbPrintFile(cpdb_printer_obj_t *printer_obj, const char *file_path); /** * Submit file for printing to another file, using the settings set previously. * * @param printer_obj Printer object * @param file_path Path of file to print * @param final_file_path Final path to print to * * @return Job ID if created, NULL otherwise */ char *cpdbPrintFilePath(cpdb_printer_obj_t *printer_obj, const char *file_path, const char *final_file_path); /** * Set an option value for a printer. * Updates the value if one is already set. * * @param printer_obj Printer object * @param option_name Option name * @param value Value to set */ void cpdbAddSettingToPrinter(cpdb_printer_obj_t *printer_obj, const char *option_name, const char *value); /** * Clear the option value set for a printer. * * @param printer_obj Printer object * @param option_name Option name * * @return TRUE if set value successfully cleared, FALSE otherwise */ gboolean cpdbClearSettingFromPrinter(cpdb_printer_obj_t *printer_obj, const char *option_name); /** * Cancel a job on a printer. * * @param printer_obj Printer object * @param job_id Job ID for job to cancel * * @return TRUE if job cancelled, FALSE otherwise */ gboolean cpdbCancelJob(cpdb_printer_obj_t *printer_obj, const char *job_id); /** * Serialize the cpdb_printer_obj_t and save it to a file * This also keeps the respective backend of the printer alive. * * This cpdb_printer_obj_t* can then be resurrecuted from the file using the * cpdbResurrectPrinterFromFile() function. * * @param printer_obj Printer object * @param file File path to save to * @param frontend_obj Frontend instance */ void cpdbPicklePrinterToFile(cpdb_printer_obj_t *p, const char *file, const cpdb_frontend_obj_t *frontend_obj); /** * Recreates a cpdb_printer_obj_t from its serialized form stored in the given format * and returns it. * * @param file File path to read from * * @return Printer object if deserialization was succesfull, NULL otherwise */ cpdb_printer_obj_t *cpdbResurrectPrinterFromFile(const char *file); /** * Get the translation for an option name provided by a printer. * * @param printer_obj Printer object * @param option_name Option name * @param lang BCP47 language tag to be used for translation * * @return Translated name */ char *cpdbGetOptionTranslation(cpdb_printer_obj_t *printer_obj, const char *option_name, const char *lang); /** * Get the translation for an option value provided by a printer. * * @param printer_obj Printer object * @param option_name Option name * @param choice_name Option value * @param lang BCP47 language tag to be used for translation * * @return Translated value */ char *cpdbGetChoiceTranslation(cpdb_printer_obj_t *printer_obj, const char *option_name, const char *choice_name, const char *lang); /** * Get the translation for an option group provided by a printer. * * @param printer_obj Printer object * @param group_name Group name * @param lang BCP47 language tag to be used for translation * * @return Translated name */ char *cpdbGetGroupTranslation(cpdb_printer_obj_t *printer_obj, const char *group_name, const char *lang); /** * Get translations for all strings provided by a printer. * * @param printer_obj Printer object * @param lang BCP47 language tag to be used for translation */ void cpdbGetAllTranslations(cpdb_printer_obj_t *printer_obj, const char *lang); /** * Get the cpdb_media_t struct corresponding to a media-size supported by a printer. * * @param printer_obj Printer object * @param media_name Media-size name * * @return Media struct if media-size exists, NULL otherwise */ cpdb_media_t *cpdbGetMedia(cpdb_printer_obj_t *printer_obj, const char *media_name); /** * Get the dimensions of a media-size supported by a printer. * * @param printer_obj Printer object * @param media_name Media-size name * @param width Address for storing media width * @param length Address for storing media length * * @return 1 if media-size exists, 0 otherwise */ int cpdbGetMediaSize(cpdb_printer_obj_t *printer_obj, const char *media_name, int *width, int *length); /** * Get the media margins for a media-size supported by a printer. * * @param printer_obj Printer object * @param media_name Media-size name * @param margins Address for storing margins array * * @returns Number of margins supported */ int cpdbGetMediaMargins(cpdb_printer_obj_t *printer_obj, const char *media_name, cpdb_margin_t **margins); /** * Asynchronously fetch printer details and options. * * @param printer_obj Printer object * @param caller_cb Callback function * @param user_data User data to pass to callback function * */ void cpdbAcquireDetails(cpdb_printer_obj_t *printer_obj, cpdb_async_callback caller_cb, void *user_data); /** * Asynchronously fetch all printer strings translations, * which can then be obtained using cpdbGet[...]Translation() functions. * For synchronous version, look at cpdbGetAllTranslations(). * * @param printer_obj Printer object * @param lang BCP47 language tag to be used for translation * @param caller_cb Callback function * @param user_data User data to pass to callback functions */ void cpdbAcquireTranslations(cpdb_printer_obj_t *printer_obj, const char *lang, cpdb_async_callback caller_cb, void *user_data); /************************************************************************************************/ /** ______________________________________ cpdb_settings_t __________________________________________ **/ /** * Takes care of the settings the user sets with the help of the dialog. * These settings will be used when sending a print job */ struct cpdb_settings_s { int count; GHashTable *table; /** [name] --> [value] **/ // planned functions: // serialize settings into a GVariant of type a(ss) }; /** * Get a new empty settings object. * * @return Settings object */ cpdb_settings_t *cpdbGetNewSettings(); /** * Copy settings from source to destination. * The previous values in dest will be overwritten. * * @param source Source settings * @param dest Destination settings */ void cpdbCopySettings(const cpdb_settings_t *source, cpdb_settings_t *dest); /** * Add the particular 'setting' to the settings object. * If the setting already exists, its value is updated instead. * * @param setting_obj Settings object * @param option_name Option name * @param value Option value */ void cpdbAddSetting(cpdb_settings_t *setting_obj, const char *option_name, const char *value); /** * Clear the setting specified by @name * * @return TRUE , if the setting was cleared * FALSE , if the setting wasn't there and thus couldn't be cleared */ gboolean cpdbClearSetting(cpdb_settings_t *, const char *name); /** * Serialize the cpdb_settings_t struct into a GVariant of type a(ss) * so that it can be sent as an argument over D-Bus */ GVariant *cpdbSerializeToGVariant(cpdb_settings_t *s); /** * Save the settings to disk, * i.e write them to CPDB_PRINT_SETTINGS_FILE * * @param settings_obj Settings object */ void cpdbSaveSettingsToDisk(cpdb_settings_t *settings_obj); /** * Reads the serialized settings stored in * CPDB_PRINT_SETTINGS_FILE and creates a cpdb_settings_t* struct from it. * The caller is responsible for freeing the returned settings object. * * @return Settings object */ cpdb_settings_t *cpdbReadSettingsFromDisk(); /** * Free up a settings object. * * @param settings_obj Settings object */ void cpdbDeleteSettings(cpdb_settings_t *settings_obj); /************************************************************************************************/ /** ______________________________________ cpdb_options_t __________________________________________ **/ struct cpdb_options_s { int count; int media_count; GHashTable *table; /**[name] --> cpdb_option_t struct**/ GHashTable *media; /**[name] --> cpdb_media_t struct**/ }; /** * Get an empty cpdb_options_t struct with no 'options' in it * * @return Options object */ cpdb_options_t *cpdbGetNewOptions(); /** * Free up an options object. * * @param options Options object */ void cpdbDeleteOptions(cpdb_options_t *); /************************************************************************************************/ /** ______________________________________ cpdb_option_t __________________________________________ **/ struct cpdb_option_s { char *option_name; char *group_name; int num_supported; char **supported_values; char *default_value; }; /** * @param opt Option object */ void cpdbDeleteOption(cpdb_option_t *); /************************************************************************************************/ /** ______________________________________ cpdb_margin_t __________________________________________ **/ struct cpdb_margin_s { int left; int right; int top; int bottom; }; /************************************************************************************************/ /** ______________________________________ cpdb_media_t __________________________________________ **/ struct cpdb_media_s { char *name; int width; int length; int num_margins; cpdb_margin_t *margins; }; /** * Free up a media-size object. * * @param media Media-size object */ void cpdbDeleteMedia(cpdb_media_t *media); /************************************************************************************************/ /** ______________________________________ cpdb_job_t __________________________________________ **/ struct cpdb_job_s { char *job_id; char *title; char *printer_id; char *backend_name; char *user; char *state; char *submitted_at; int size; }; #ifdef __cplusplus } #endif #endif /* !_CPDB_CPDB_FRONTEND_H_ */ cpdb-libs-2.0b5/cpdb/cpdb.c000066400000000000000000000232611446253655700154520ustar00rootroot00000000000000#include "cpdb.h" /** * If CPDB has been initialized */ volatile gboolean initialized = FALSE; /** * Table matching common IPP options prefix to groups */ const char *cpdbGroupTable[][2] = { {CPDB_OPTION_COPIES, CPDB_GROUP_COPIES}, {CPDB_OPTION_COLLATE, CPDB_GROUP_COPIES}, {CPDB_OPTION_COPIES_SUPPORTED, CPDB_GROUP_COPIES}, {CPDB_OPTION_MEDIA, CPDB_GROUP_MEDIA}, {CPDB_OPTION_MEDIA_TYPE, CPDB_GROUP_MEDIA}, {CPDB_OPTION_SIDES, CPDB_GROUP_PAGE_MGMT}, {CPDB_OPTION_MIRROR, CPDB_GROUP_PAGE_MGMT}, {CPDB_OPTION_BOOKLET, CPDB_GROUP_PAGE_MGMT}, {CPDB_OPTION_PAGE_SET, CPDB_GROUP_PAGE_MGMT}, {CPDB_OPTION_NUMBER_UP, CPDB_GROUP_PAGE_MGMT}, {CPDB_OPTION_PAGE_BORDER, CPDB_GROUP_PAGE_MGMT}, {CPDB_OPTION_PAGE_RANGES, CPDB_GROUP_PAGE_MGMT}, {CPDB_OPTION_ORIENTATION, CPDB_GROUP_PAGE_MGMT}, {CPDB_OPTION_POSITION, CPDB_GROUP_SCALING}, {CPDB_OPTION_PRINT_SCALING, CPDB_GROUP_SCALING}, {CPDB_OPTION_FIDELITY, CPDB_GROUP_SCALING}, {CPDB_OPTION_COLOR_MODE, CPDB_GROUP_COLOR}, {CPDB_OPTION_PRINT_QUALITY, CPDB_GROUP_QUALITY}, {CPDB_OPTION_RESOLUTION, CPDB_GROUP_QUALITY}, {CPDB_OPTION_FINISHINGS, CPDB_GROUP_FINISHINGS}, {CPDB_OPTION_OUTPUT_BIN, CPDB_GROUP_FINISHINGS}, {CPDB_OPTION_PAGE_DELIVERY, CPDB_GROUP_FINISHINGS}, {CPDB_OPTION_JOB_NAME, CPDB_GROUP_JOB_MGMT}, {CPDB_OPTION_JOB_SHEETS, CPDB_GROUP_JOB_MGMT}, {CPDB_OPTION_JOB_PRIORITY, CPDB_GROUP_JOB_MGMT}, {CPDB_OPTION_BILLING_INFO, CPDB_GROUP_JOB_MGMT}, {CPDB_OPTION_JOB_HOLD_UNTIL, CPDB_GROUP_JOB_MGMT} }; static void cpdbDebugLog(CpdbDebugLevel msg_lvl, const char *msg); void cpdbInit() { if (!initialized) { bindtextdomain(CPDB_GETTEXT_PACKAGE, CPDB_LOCALEDIR); initialized = TRUE; } } char **cpdbNewCStringArray(int num_elems) { return malloc(sizeof(char *) * num_elems); } gboolean cpdbGetBoolean(const char *g) { if (!g) return FALSE; if (g_str_equal(g, "true")) return TRUE; return FALSE; } char *cpdbConcat(const char *s1, const char *s2) { if (s1 == NULL) return cpdbGetStringCopy(s2); if (s2 == NULL) return cpdbGetStringCopy(s1); char *s = malloc(strlen(s1) + strlen(s2) + 1); sprintf(s, "%s%s", s1, s2); return s; } char *cpdbConcatSep(const char *s1, const char *s2) { char *s = malloc(strlen(s1) + strlen(s2) + 2); sprintf(s, "%s#%s", s1, s2); return s; } char *cpdbConcatPath(const char *s1, const char *s2) { char *s = malloc(strlen(s1) + strlen(s2) + 2); if (s1[strlen(s1) - 1] == '/') sprintf(s, "%s%s", s1, s2); else sprintf(s, "%s/%s", s1, s2); return s; } char *cpdbGetStringCopy(const char *str) { if (str == NULL) return NULL; char *s = malloc(sizeof(char) * (strlen(str) + 1)); strcpy(s, str); return s; } void cpdbUnpackStringArray(GVariant *variant, int num_val, char ***val) { GVariantIter *iter; if (!num_val) { printf("No supported values found.\n"); *val = NULL; return; } char **array = (char **)malloc(sizeof(char *) * num_val); g_variant_get(variant, "a(s)", &iter); int i = 0; char *str; for (i = 0; i < num_val; i++) { g_variant_iter_loop(iter, "(s)", &str); array[i] = cpdbGetStringCopy(str); printf(" %s\n", str); } *val = array; } GVariant *cpdbPackStringArray(int num_val, char **val) { GVariantBuilder *builder; GVariant *values; builder = g_variant_builder_new(G_VARIANT_TYPE("a(s)")); for (int i = 0; i < num_val; i++) { g_variant_builder_add(builder, "(s)", val[i]); } if (num_val == 0) g_variant_builder_add(builder, "(s)", "NA"); values = g_variant_builder_end(builder); return values; } GVariant *cpdbPackMediaArray(int num_val, int (*margins)[4]) { GVariantBuilder *builder; GVariant *values; builder = g_variant_builder_new(G_VARIANT_TYPE("a(iiii)")); for (int i = 0; i < num_val; i++) { g_variant_builder_add(builder, "(iiii)", margins[i][0], margins[i][1], margins[i][2], margins[i][3]); } values = g_variant_new("a(iiii)", builder); return values; } char *cpdbGetAbsolutePath(const char *file_path) { if (!file_path) return NULL; if (file_path[0] == '/') return cpdbGetStringCopy(file_path); if (file_path[0] == '~') { struct passwd *passwdEnt = getpwuid(getuid()); char *home = passwdEnt->pw_dir; if (home == NULL) return NULL; if (file_path[1] != '/' && file_path[1] != '\0') return NULL; char *fp = malloc(sizeof(char) * (strlen(home) + strlen(file_path))); if (fp == NULL) return NULL; sprintf(fp, "%s%s", home, file_path + 1); return fp; } char *cwd = getcwd(NULL, 0); if (cwd == NULL) return NULL; char *fp = malloc(sizeof(char) * (strlen(cwd) + strlen(file_path) + 2)); if (fp == NULL) return NULL; sprintf(fp, "%s/%s", cwd, file_path); free(cwd); printf("%s\n", fp); return fp; } char *cpdbExtractFileName(const char *file_path) { if (!file_path) return NULL; char *file_name_ptr = (char *)file_path; char *x = (char *)file_path; char c = *x; while (c) { if (c == '/') file_name_ptr = x; x++; c = *x; } return file_name_ptr; } char *cpdbGetUserConfDir() { char *config_dir = NULL, *env_xch, *env_home; if (env_xch = getenv("XDG_CONFIG_HOME")) config_dir = cpdbConcatPath(env_xch, "cpdb"); else if (env_home = getenv("HOME")) config_dir = cpdbConcatPath(env_home, ".config/cpdb"); if (config_dir && (access(config_dir, R_OK) == 0 || mkdir(config_dir, CPDB_USRCONFDIR_PERM) == 0)) return config_dir; return NULL; } char *cpdbGetSysConfDir() { char *config_dir = NULL, *env_xcd, *path; #ifdef CPDB_SYSCONFDIR config_dir = cpdbConcatPath(CPDB_SYSCONFDIR, "cpdb"); if (access(config_dir, R_OK) == 0 || mkdir(config_dir, CPDB_SYSCONFDIR_PERM) == 0) return config_dir; #endif if (env_xcd = getenv("XDG_CONFIG_DIRS")) { env_xcd = cpdbGetStringCopy(env_xcd); path = strtok(env_xcd, ":"); while (path != NULL) { config_dir = cpdbConcatPath(CPDB_SYSCONFDIR, "cpdb"); if (access(config_dir, R_OK) == 0 || mkdir(config_dir, CPDB_SYSCONFDIR_PERM) == 0) { free(env_xcd); return config_dir; } free(config_dir); path = strtok(NULL, ":"); } free(env_xcd); } config_dir = "/etc/cpdb"; if (access(config_dir, R_OK) == 0 || mkdir(config_dir, CPDB_SYSCONFDIR_PERM) == 0) return config_dir; return NULL; } char *cpdbGetGroup(const char *option_name) { if (option_name == NULL) { cpdbDebugLog(CPDB_DEBUG_LEVEL_WARN, "Invalid params: cpdbGetCommonGroup()\n"); return NULL; } int num_group = sizeof(cpdbGroupTable) / sizeof(cpdbGroupTable[0]); for (int i = 0; i < num_group; i++) { if (strncmp(option_name, cpdbGroupTable[i][0], strlen(cpdbGroupTable[i][0])) == 0) return cpdbGetStringCopy(cpdbGroupTable[i][1]); } return cpdbGetStringCopy(CPDB_GROUP_ADVANCED); } char *cpdbGetGroupTranslation2(const char *group_name, const char *lang) { setenv("LANGUAGE", lang, 1); { extern int _nl_msg_cat_cntr; ++_nl_msg_cat_cntr; } return cpdbGetStringCopy(_(group_name)); } static void cpdbDebugLog(CpdbDebugLevel msg_lvl, const char *msg) { FILE *log_file = NULL, *out; char *env_cdl, *env_cdlf; CpdbDebugLevel dbg_lvl; if (msg == NULL) return; dbg_lvl = CPDB_DEBUG_LEVEL_ERROR; if (env_cdl = getenv(CPDB_DEBUG_LEVEL)) { if (strncasecmp(env_cdl, "debug", 5) == 0) dbg_lvl = CPDB_DEBUG_LEVEL_DEBUG; else if (strncasecmp(env_cdl, "info", 4) == 0) dbg_lvl = CPDB_DEBUG_LEVEL_INFO; else if (strncasecmp(env_cdl, "warn", 4) == 0) dbg_lvl = CPDB_DEBUG_LEVEL_WARN; } if (msg_lvl < dbg_lvl) return; out = stderr; if (env_cdlf = getenv(CPDB_DEBUG_LOGFILE)) { if ((log_file = fopen(env_cdlf, "a")) != NULL) out = log_file; } switch(msg_lvl) { case CPDB_DEBUG_LEVEL_DEBUG: fprintf(out, "[Debug] %s", msg); break; case CPDB_DEBUG_LEVEL_INFO: fprintf(out, "[Info] %s", msg); break; case CPDB_DEBUG_LEVEL_WARN: fprintf(out, "[Warn] %s", msg); break; case CPDB_DEBUG_LEVEL_ERROR: fprintf(out, "[Error] %s", msg); break; } } void cpdbFDebugPrintf(CpdbDebugLevel msg_lvl, const char *fmt, ...) { va_list argptr; char buf[CPDB_BSIZE], msg[CPDB_BSIZE + 12]; va_start(argptr, fmt); vsnprintf(buf, sizeof(buf), fmt, argptr); snprintf(msg, sizeof(msg), "[Frontend] %s", buf); va_end(argptr); cpdbDebugLog(msg_lvl, msg); } void cpdbBDebugPrintf(CpdbDebugLevel msg_lvl, const char *backend_name, const char *fmt, ...) { va_list argptr; char buf[CPDB_BSIZE], msg[CPDB_BSIZE + 12]; va_start(argptr, fmt); vsnprintf(buf, sizeof(buf), fmt, argptr); snprintf(msg, sizeof(msg), "[Backend %s] %s", backend_name, buf); va_end(argptr); cpdbDebugLog(msg_lvl, msg); } cpdb-libs-2.0b5/cpdb/cpdb.h000066400000000000000000000204001446253655700154470ustar00rootroot00000000000000#ifndef _CPDB_CPDB_H_ #define _CPDB_CPDB_H_ #define GETTEXT_PACKAGE "cpdb" #include #ifdef __cplusplus extern "C" { #endif #include #include #include #include #include #include #include #include #include /* buffer sizes */ #define CPDB_BSIZE 512 /* Config files directory permissions, * if needed to be created */ #define CPDB_USRCONFDIR_PERM 0755 #define CPDB_SYSCONFDIR_PERM 0755 /* Environment variables for printing debug info */ #define CPDB_DEBUG_LEVEL "CPDB_DEBUG_LEVEL" #define CPDB_DEBUG_LOGFILE "CPDB_DEBUG_LOGFILE" #define CPDB_BACKEND_OBJ_PATH "/" #define CPDB_PRINTER_ARRAY_ARGS "a(sssssbss)" #define CPDB_PRINTER_ARGS "(sssssbss)" /* For translations */ #define CPDB_GRP_PREFIX "GRP" #define CPDB_OPT_PREFIX "OPT" #define CPDB_TL_DICT_ARGS "a{ss}" #define CPDB_TL_ARGS "{ss}" #define CPDB_PRINTER_ADDED_ARGS "(sssssbss)" #define CPDB_JOB_ARGS "(ssssssi)" #define CPDB_JOB_ARRAY_ARGS "a(ssssssi)" typedef enum { CPDB_DEBUG_LEVEL_DEBUG, CPDB_DEBUG_LEVEL_INFO, CPDB_DEBUG_LEVEL_WARN, CPDB_DEBUG_LEVEL_ERROR, } CpdbDebugLevel; /** * Initializes CPDB. * It’s the responsibility of the main program to set the locale. */ void cpdbInit(); /** * Get an array of C styled strings (char *) */ char **cpdbNewCStringArray(int num_elems); /** * Convert string to gboolean. */ gboolean cpdbGetBoolean(const char *); /** * Concatenate two strings. */ char *cpdbConcat(const char *s1, const char *s2); /** * Concatenate two strings with separator "#". */ char *cpdbConcatSep(const char *s1, const char *s2); /** * Concatenate two paths. */ char *cpdbConcatPath(const char *s1, const char *s2); /** * Get string copy. */ char *cpdbGetStringCopy(const char *s); /** * Get directory for user configuration files. */ char *cpdbGetUserConfDir(); /** * Get directory for system wide configuration files. */ char *cpdbGetSysConfDir(); /** * Get absolute path from relative path. */ char *cpdbGetAbsolutePath(const char *file_path); /** * Extract file name for path. */ char *cpdbExtractFileName(const char* file_path); /** * Get a group for given option name. */ char *cpdbGetGroup(const char *option_name); /** * Get translation for given group name. */ char *cpdbGetGroupTranslation2(const char *group_name, const char *locale); /** * Format and print debug message for frontend. */ void cpdbFDebugPrintf(CpdbDebugLevel msg_lvl, const char *fmt, ...); /** * Format and print debug message for backends. */ void cpdbBDebugPrintf(CpdbDebugLevel msg_lvl, const char *backend_name, const char *fmt, ...); /* Packing/Unpacking utility functions */ void cpdbUnpackStringArray(GVariant *variant, int num_val, char ***val); GVariant *cpdbPackStringArray(int num_val, char **val); GVariant *cpdbPackMediaArray(int num_val, int (*margins)[4]); /*********LISTING OF ALL POSSIBLE GROUPS*****/ /** * Some standard group names. */ #define CPDB_GROUP_MEDIA N_("Media") #define CPDB_GROUP_COPIES N_("Copies") #define CPDB_GROUP_COLOR N_("Color") #define CPDB_GROUP_SCALING N_("Scaling") #define CPDB_GROUP_QUALITY N_("Ouput Quality") #define CPDB_GROUP_ADVANCED N_("Advanced") #define CPDB_GROUP_JOB_MGMT N_("Job Management") #define CPDB_GROUP_PAGE_MGMT N_("Page Management") #define CPDB_GROUP_FINISHINGS N_("Finishings") /*********LISTING OF ALL POSSIBLE OPTIONS*****/ /** * Some standard IPP option names. * While adding settings, use these as option names */ #define CPDB_OPTION_COPIES N_("copies") #define CPDB_OPTION_COLLATE N_("multiple-document-handling") #define CPDB_OPTION_COPIES_SUPPORTED N_("multiple-document-jobs-supported") #define CPDB_OPTION_MEDIA N_("media") #define CPDB_OPTION_MEDIA_COL N_("media-col") #define CPDB_OPTION_MEDIA_TYPE N_("media-type") #define CPDB_OPTION_MEDIA_SOURCE N_("media-source") #define CPDB_OPTION_MARGIN_TOP N_("media-top-margin") #define CPDB_OPTION_MARGIN_BOTTOM N_("media-bottom-margin") #define CPDB_OPTION_MARGIN_LEFT N_("media-left-margin") #define CPDB_OPTION_MARGIN_RIGHT N_("media-right-margin") #define CPDB_OPTION_SIDES N_("sides") #define CPDB_OPTION_MIRROR N_("mirror") #define CPDB_OPTION_BOOKLET N_("booklet") #define CPDB_OPTION_PAGE_SET N_("page-set") #define CPDB_OPTION_NUMBER_UP N_("number-up") #define CPDB_OPTION_NUMBER_UP_LAYOUT N_("number-up-layout") #define CPDB_OPTION_PAGE_BORDER N_("page-border") #define CPDB_OPTION_PAGE_RANGES N_("page-ranges") #define CPDB_OPTION_ORIENTATION N_("orientation-requested") #define CPDB_OPTION_POSITION N_("position") #define CPDB_OPTION_FIDELITY N_("ipp-attribute-fidelity") #define CPDB_OPTION_PRINT_SCALING N_("print-scaling") #define CPDB_OPTION_COLOR_MODE N_("print-color-mode") #define CPDB_OPTION_RESOLUTION N_("printer-resolution") #define CPDB_OPTION_PRINT_QUALITY N_("print-quality") #define CPDB_OPTION_FINISHINGS N_("finishings") #define CPDB_OPTION_OUTPUT_BIN N_("output-bin") #define CPDB_OPTION_PAGE_DELIVERY N_("page-delivery") #define CPDB_OPTION_JOB_NAME N_("job-name") #define CPDB_OPTION_JOB_SHEETS N_("job-sheets") #define CPDB_OPTION_BILLING_INFO N_("billing-info") #define CPDB_OPTION_JOB_PRIORITY N_("job-priority") #define CPDB_OPTION_JOB_HOLD_UNTIL N_("job-hold-until") /*********LISTING OF ALL POSSIBLE OPTION CHOICES*****/ /** * Some standard IPP option names. * While adding settings, use these as option names */ #define CPDB_PAGE_SET_ALL N_("all") #define CPDB_PAGE_SET_ODD N_("odd") #define CPDB_PAGE_SET_EVEN N_("even") #define CPDB_COLOR_MODE_COLOR N_("color") #define CPDB_COLOR_MODE_BW N_("monochrome") #define CPDB_COLOR_MODE_AUTO N_("auto") #define CPDB_PAGE_DELIVERY_SAME N_("same-order") #define CPDB_PAGE_DELIVERY_REVERSE N_("reverse-order") #define CPDB_COLLATE_ENABLED N_("separate-documents-collated-copies") #define CPDB_COLLATE_DISABLED N_("separate-documents-uncollated-copies") #define CPDB_QUALITY_DRAFT N_("draft") #define CPDB_QUALITY_NORMAL N_("normal") #define CPDB_QUALITY_HIGH N_("high") #define CPDB_SIDES_ONE_SIDED N_("one-sided") #define CPDB_SIDES_TWO_SIDED_SHORT N_("two-sided-short-edge") #define CPDB_SIDES_TWO_SIDED_LONG N_("two-sided-long-edge") #define CPDB_ORIENTATION_PORTRAIT N_("3") #define CPDB_ORIENTATION_LANDSCAPE N_("4") #define CPDB_ORIENTATION_RLANDSCAPE N_("5") #define CPDB_ORIENTATION_RPORTRAIT N_("6") #define CPDB_JOB_HOLD_NONE N_("no-hold") #define CPDB_JOB_HOLD_INDEFINITE N_("indefinite") #define CPDB_PRIORITY_URGENT N_("urgent") #define CPDB_PRIORITY_HIGH N_("high") #define CPDB_PRIORITY_MEDIUM N_("medium") #define CPDB_PRIORITY_LOW N_("low") #define CPDB_STATE_IDLE N_("idle") #define CPDB_STATE_PRINTING N_("printing") #define CPDB_STATE_STOPPED N_("stopped") #define CPDB_SIGNAL_STOP_BACKEND "StopListing" #define CPDB_SIGNAL_REFRESH_BACKEND "RefreshBackend" #define CPDB_SIGNAL_PRINTER_ADDED "PrinterAdded" #define CPDB_SIGNAL_PRINTER_STATE_CHANGED "PrinterStateChanged" #define CPDB_SIGNAL_PRINTER_REMOVED "PrinterRemoved" #define CPDB_SIGNAL_HIDE_REMOTE "HideRemotePrinters" #define CPDB_SIGNAL_UNHIDE_REMOTE "UnhideRemotePrinters" #define CPDB_SIGNAL_HIDE_TEMP "HideTemporaryPrinters" #define CPDB_SIGNAL_UNHIDE_TEMP "UnhideTemporaryPrinters" #define CPDB_JOB_STATE_ABORTED N_("Aborted") #define CPDB_JOB_STATE_CANCELLED N_("Cancelled") #define CPDB_JOB_STATE_COMPLETED N_("Completed") #define CPDB_JOB_STATE_HELD N_("Held") #define CPDB_JOB_STATE_PENDING N_("Pending") #define CPDB_JOB_STATE_PRINTING N_("Printing") #define CPDB_JOB_STATE_STOPPED N_("Stopped") #ifdef __cplusplus } #endif #endif /* !_CPDB_CPDB_H_ */ cpdb-libs-2.0b5/cpdb/frontend.h000066400000000000000000000001661446253655700163650ustar00rootroot00000000000000#ifndef _CPDB_FRONTEND_H_ #define _CPDB_FRONTEND_H_ #include #endif /* !_CPDB_FRONTEND_H_ */ cpdb-libs-2.0b5/cpdb/interface/000077500000000000000000000000001446253655700163325ustar00rootroot00000000000000cpdb-libs-2.0b5/cpdb/interface/org.openprinting.Backend.xml000066400000000000000000000126021446253655700237050ustar00rootroot00000000000000 cpdb-libs-2.0b5/cpdb/interface/org.openprinting.Frontend.xml000066400000000000000000000004651446253655700241410ustar00rootroot00000000000000 cpdb-libs-2.0b5/m4/000077500000000000000000000000001446253655700140025ustar00rootroot00000000000000cpdb-libs-2.0b5/m4/cpdb-common.m4000066400000000000000000000010431446253655700164400ustar00rootroot00000000000000dnl Common configuration stuff for CPDB. # Check for a C compiler AC_PROG_CC PKG_CHECK_MODULES([GIO],[gio-2.0]) PKG_CHECK_MODULES([GIOUNIX],[gio-unix-2.0]) PKG_CHECK_MODULES([GLIB],[glib-2.0]) # Checks for header files. AC_CHECK_HEADERS([stdlib.h string.h unistd.h sys/stat.h]) # Checks for typedefs, structures, and compiler characteristics. AC_TYPE_SIZE_T # Checks for library functions. AC_FUNC_MALLOC AC_CHECK_FUNCS([access getcwd mkdir getenv setenv]) AC_DEFINE([CPDB_GETTEXT_PACKAGE], ["cpdb2.0"], [Domain for CPDB package])cpdb-libs-2.0b5/m4/cpdb-directories.m4000066400000000000000000000054501446253655700174720ustar00rootroot00000000000000dnl Directory stuff for CPDB. dnl Fix "prefix" variable if it hasn't been specified... AS_IF([test "$prefix" = "NONE"], [ prefix="/usr/local" ]) dnl Fix "exec_prefix" variable if it hasn't been specified... AS_IF([test "$exec_prefix" = "NONE"], [ AS_IF([test "$prefix" = "/usr/local"], [ exec_prefix="/usr/local" ], [ exec_prefix="$prefix" ]) ]) dnl Fix "bindir" variable... AS_IF([test "$bindir" = "\${exec_prefix}/bin"], [ bindir="$exec_prefix/bin" ]) dnl Fix "sbindir" variable... AS_IF([test "$sbindir" = "\${exec_prefix}/sbin"], [ sbindir="$exec_prefix/sbin" ]) dnl Fix "datarootdir" variable if it hasn't been specified... AS_IF([test "$datarootdir" = "\${prefix}/share"], [ AS_IF([test "$prefix" = "/usr/local"], [ datarootdir="/usr/local/share" ], [ datarootdir="$prefix/share" ]) ]) dnl Fix "datadir" variable if it hasn't been specified... AS_IF([test "$datadir" = "\${prefix}/share"], [ AS_IF([test "$prefix" = "/usr/local"], [ datadir="/usr/local/share" ], [ datadir="$prefix/share" ]) ], [test "$datadir" = "\${datarootdir}"], [ datadir="$datarootdir" ]) dnl Fix "includedir" variable if it hasn't been specified... AS_IF([test "$includedir" = "\${prefix}/include" -a "$prefix" = "/usr/local"], [ includedir="/usr/local/include" ]) dnl Fix "localstatedir" variable if it hasn't been specified... AS_IF([test "$localstatedir" = "\${prefix}/var"], [ AS_IF([test "$prefix" = "/usr/local"], [ localstatedir="/usr/local/var" ], [ localstatedir="$prefix/var" ]) ]) dnl Fix "sysconfdir" variable if it hasn't been specified... AS_IF([test "$sysconfdir" = "\${prefix}/etc"], [ AS_IF([test "$prefix" = "/usr/local"], [ sysconfdir="/usr/local/etc" ], [ sysconfdir="$prefix/etc" ]) ]) dnl Fix "libdir" variable... AS_IF([test "$libdir" = "\${exec_prefix}/lib"], [ AS_CASE(["$host_os_name"], [linux*], [ AS_IF([test -d /usr/lib64 -a ! -d /usr/lib64/fakeroot], [ libdir="$exec_prefix/lib64" ], [ libdir="$exec_prefix/lib" ]) ], [*], [ libdir="$exec_prefix/lib" ]) ]) dnl Fix "sysconfdir" variable if it hasn't been specified... AS_IF([test "$sysconfdir" = "\${prefix}/etc"], [ AS_IF([test "$prefix" = "/usr/local"], [ sysconfdir="/usr/local/etc" ], [ sysconfdir="$prefix/etc" ]) ]) AC_DEFINE_UNQUOTED([CPDB_LOCALEDIR], ["$localedir"], [Location for locale files]) AC_DEFINE_UNQUOTED([CPDB_SYSCONFDIR], ["$sysconfdir"], [Location for system-wide configuration files]) # The info directory which will be read by the frontend CPDB_BACKEND_INFO_DIR="$datadir/print-backends" AC_SUBST([CPDB_BACKEND_INFO_DIR]) AC_DEFINE_UNQUOTED([CPDB_BACKEND_INFO_DIR], ["$CPDB_BACKEND_INFO_DIR"]) # The directory for the backend executables CPDB_BACKEND_EXEC_DIR="$libdir/print-backends" AC_SUBST([CPDB_BACKEND_EXEC_DIR]) cpdb-libs-2.0b5/po/000077500000000000000000000000001446253655700141005ustar00rootroot00000000000000cpdb-libs-2.0b5/po/Makevars000066400000000000000000000070161446253655700156000ustar00rootroot00000000000000# Makefile variables for PO directory in any package using GNU gettext. # # Copyright (C) 2003-2019 Free Software Foundation, Inc. # This file is free software; the Free Software Foundation gives # unlimited permission to use, copy, distribute, and modify it. # Usually the message domain is the same as the package name. DOMAIN = $(PACKAGE) # These two variables depend on the location of this directory. subdir = po top_builddir = .. # These options get passed to xgettext. XGETTEXT_OPTIONS = --keyword=_ --keyword=N_ # This is the copyright holder that gets inserted into the header of the # $(DOMAIN).pot file. Set this to the copyright holder of the surrounding # package. (Note that the msgstr strings, extracted from the package's # sources, belong to the copyright holder of the package.) Translators are # expected to transfer the copyright for their translations to this person # or entity, or to disclaim their copyright. The empty string stands for # the public domain; in this case the translators are expected to disclaim # their copyright. COPYRIGHT_HOLDER = OpenPrinting # This tells whether or not to prepend "GNU " prefix to the package # name that gets inserted into the header of the $(DOMAIN).pot file. # Possible values are "yes", "no", or empty. If it is empty, try to # detect it automatically by scanning the files in $(top_srcdir) for # "GNU packagename" string. PACKAGE_GNU = no # This is the email address or URL to which the translators shall report # bugs in the untranslated strings: # - Strings which are not entire sentences, see the maintainer guidelines # in the GNU gettext documentation, section 'Preparing Strings'. # - Strings which use unclear terms or require additional context to be # understood. # - Strings which make invalid assumptions about notation of date, time or # money. # - Pluralisation problems. # - Incorrect English spelling. # - Incorrect formatting. # It can be your email address, or a mailing list address where translators # can write to without being subscribed, or the URL of a web page through # which the translators can contact you. MSGID_BUGS_ADDRESS = https://github.com/OpenPrinting/cpdb-libs/issues # This is the list of locale categories, beyond LC_MESSAGES, for which the # message catalogs shall be used. It is usually empty. EXTRA_LOCALE_CATEGORIES = # This tells whether the $(DOMAIN).pot file contains messages with an 'msgctxt' # context. Possible values are "yes" and "no". Set this to yes if the # package uses functions taking also a message context, like pgettext(), or # if in $(XGETTEXT_OPTIONS) you define keywords with a context argument. USE_MSGCTXT = no # These options get passed to msgmerge. # Useful options are in particular: # --previous to keep previous msgids of translated messages, # --quiet to reduce the verbosity. MSGMERGE_OPTIONS = # These options get passed to msginit. # If you want to disable line wrapping when writing PO files, add # --no-wrap to MSGMERGE_OPTIONS, XGETTEXT_OPTIONS, and # MSGINIT_OPTIONS. MSGINIT_OPTIONS = # This tells whether or not to regenerate a PO file when $(DOMAIN).pot # has changed. Possible values are "yes" and "no". Set this to no if # the POT file is checked in the repository and the version control # program ignores timestamps. PO_DEPENDS_ON_POT = yes # This tells whether or not to forcibly update $(DOMAIN).pot and # regenerate PO files on "make dist". Possible values are "yes" and # "no". Set this to no if the POT file and PO files are maintained # externally. DIST_DEPENDS_ON_UPDATE_PO = yes cpdb-libs-2.0b5/po/POTFILES.in000066400000000000000000000001051446253655700156510ustar00rootroot00000000000000# List of source files containing translatable strings. cpdb/cpdb.h cpdb-libs-2.0b5/tools/000077500000000000000000000000001446253655700146225ustar00rootroot00000000000000cpdb-libs-2.0b5/tools/Makefile.am000066400000000000000000000013141446253655700166550ustar00rootroot00000000000000toolsdir = $(bindir) tools_PROGRAMS = \ cpdb-text-frontend \ cpdb-pickle-print cpdb_text_frontend_SOURCES = cpdb-text-frontend.c cpdb_text_frontend_LDADD = \ -L../cpdb/.libs \ ../cpdb/libcpdb-frontend.la \ ../cpdb/libcpdb.la \ $(GLIB_LIBS) cpdb_text_frontend_CFLAGS = \ -Wno-unused-result \ -I .. \ $(GLIB_CFLAGS) cpdb_pickle_print_SOURCES = cpdb-pickle-print.c cpdb_pickle_print_LDADD = \ -L../cpdb/.libs \ ../cpdb/libcpdb-frontend.la \ ../cpdb/libcpdb.la \ $(GLIB_LIBS) cpdb_pickle_print_CFLAGS = \ -I .. \ $(GLIB_CFLAGS) # ================================ # Tests ("make test"/"make check") # ================================ TESTS = \ run-tests.sh EXTRA_DIST = \ run-tests.sh cpdb-libs-2.0b5/tools/cpdb-pickle-print.c000066400000000000000000000010521446253655700202730ustar00rootroot00000000000000#include #include int main(int argc, char **argv) { if (argc != 2) { printf("Usage : %s filepath_to_print\n", argv[0]); exit(EXIT_SUCCESS); } cpdb_printer_obj_t *p = cpdbResurrectPrinterFromFile("/tmp/.printer-pickle"); if (p == NULL) { printf("No serialized printer found. " "You must first 'pickle' a printer using the " "'pickle-printer' command inside cpdb-text-frontend\n"); exit(EXIT_FAILURE); } cpdbPrintFile(p, argv[1]); } cpdb-libs-2.0b5/tools/cpdb-text-frontend.c000066400000000000000000000517201446253655700205020ustar00rootroot00000000000000#include #include #include #include #include #include #include #define BUFSIZE 1024 void display_help(); gpointer parse_commands(gpointer user_data); cpdb_frontend_obj_t *f; static const char *locale; static void printBasicOptions(const cpdb_printer_obj_t *p) { printf("-------------------------\n"); printf("Printer %s\n", p->id); printf("name: %s\n", p->name); printf("location: %s\n", p->location); printf("info: %s\n", p->info); printf("make and model: %s\n", p->make_and_model); printf("accepting jobs? %s\n", (p->accepting_jobs ? "yes" : "no")); printf("state: %s\n", p->state); printf("backend: %s\n", p->backend_name); printf("-------------------------\n\n"); } static void printMedia(const cpdb_media_t *media) { printf("[+] Media: %s\n", media->name); printf(" * width = %d\n", media->width); printf(" * length = %d\n", media->length); printf(" --> Supported margins: %d\n", media->num_margins); printf(" left, right, top, bottom\n"); for (int i = 0; i < media->num_margins; i++) { printf(" * %d, %d, %d, %d,\n", media->margins[i].left, media->margins[i].right, media->margins[i].top, media->margins[i].bottom); } printf("\n"); } static void printOption(const cpdb_option_t *opt) { int i; printf("[+] %s\n", opt->option_name); printf(" --> GROUP: %s\n", opt->group_name); for (i = 0; i < opt->num_supported; i++) { printf(" * %s\n", opt->supported_values[i]); } printf(" --> DEFAULT: %s\n\n", opt->default_value); } static void printTranslations(cpdb_printer_obj_t *p) { GHashTableIter iter; gpointer key, value; if (p->locale == NULL || p->translations == NULL) { printf("No translations found\n"); return; } g_hash_table_iter_init(&iter, p->translations); while (g_hash_table_iter_next(&iter, &key, &value)) { printf("'%s' : '%s'\n", (char *)key, (char *)value); } } static void displayAllPrinters(cpdb_frontend_obj_t *f) { GHashTableIter iter; gpointer key, value; g_hash_table_iter_init(&iter, f->printer); while (g_hash_table_iter_next(&iter, &key, &value)) { const cpdb_printer_obj_t *p = value; printBasicOptions(p); } } static void printer_callback(cpdb_frontend_obj_t *f, cpdb_printer_obj_t *p, cpdb_printer_update_t change) { switch(change) { case CPDB_CHANGE_PRINTER_ADDED: g_message("Added printer %s : %s!\n", p->name, p->backend_name); printBasicOptions(p); break; case CPDB_CHANGE_PRINTER_REMOVED: g_message("Removed printer %s : %s!\n", p->name, p->backend_name); cpdbDeletePrinterObj(p); break; case CPDB_CHANGE_PRINTER_STATE_CHANGED: g_message("Printer state changed for %s : %s to \"%s\"", p->name, p->backend_name, p->state); break; } } static void acquire_details_callback(cpdb_printer_obj_t *p, int success, void *user_data) { if (success) g_message("Details acquired for %s : %s\n", p->name, p->backend_name); else g_message("Could not acquire printer details for %s : %s\n", p->name, p->backend_name); } static void acquire_translations_callback(cpdb_printer_obj_t *p, int success, void *user_data) { if (!success) g_message("Could not acquire printer translations for %s : %s\n", p->name, p->backend_name); g_message("Translations acquired for %s : %s\n", p->name, p->backend_name); printTranslations(p); } int main(int argc, char **argv) { cpdb_printer_callback printer_cb = (cpdb_printer_callback)printer_callback; setlocale (LC_ALL, ""); cpdbInit(); locale = getenv("LANGUAGE"); char *dialog_bus_name = malloc(300); if (argc > 1) //this is for creating multiple instances of a dialog simultaneously f = cpdbGetNewFrontendObj(argv[1], printer_cb); else f = cpdbGetNewFrontendObj(NULL, printer_cb); /** Uncomment the line below if you don't want to use the previously saved settings**/ cpdbIgnoreLastSavedSettings(f); g_thread_new("parse_commands_thread", parse_commands, NULL); cpdbConnectToDBus(f); displayAllPrinters(f); GMainLoop *loop = g_main_loop_new(NULL, FALSE); g_main_loop_run(loop); } gpointer parse_commands(gpointer user_data) { fflush(stdout); char buf[BUFSIZE]; while (1) { printf("> "); fflush(stdout); scanf("%1023s", buf); if (strcmp(buf, "stop") == 0) { cpdbDeleteFrontendObj(f); g_message("Stopping front end..\n"); exit(0); } else if (strcmp(buf, "restart") == 0) { cpdbDisconnectFromDBus(f); cpdbConnectToDBus(f); } else if (strcmp(buf, "hide-remote") == 0) { cpdbHideRemotePrinters(f); g_message("Hiding remote printers discovered by the backend..\n"); } else if (strcmp(buf, "unhide-remote") == 0) { cpdbUnhideRemotePrinters(f); g_message("Unhiding remote printers discovered by the backend..\n"); } else if (strcmp(buf, "hide-temporary") == 0) { cpdbHideTemporaryPrinters(f); g_message("Hiding remote printers discovered by the backend..\n"); } else if (strcmp(buf, "unhide-temporary") == 0) { cpdbUnhideTemporaryPrinters(f); g_message("Unhiding remote printers discovered by the backend..\n"); } else if (strcmp(buf, "get-all-options") == 0) { char printer_id[BUFSIZE]; char backend_name[BUFSIZE]; scanf("%1023s%1023s", printer_id, backend_name); g_message("Getting all attributes ..\n"); cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name); if(p == NULL) continue; cpdb_options_t *opts = cpdbGetAllOptions(p); printf("Retrieved %d options.\n", opts->count); GHashTableIter iter; gpointer value; g_hash_table_iter_init(&iter, opts->table); while (g_hash_table_iter_next(&iter, NULL, &value)) { printOption(value); } } else if (strcmp(buf, "get-all-media") == 0) { char printer_id[BUFSIZE]; char backend_name[BUFSIZE]; scanf("%1023s%1023s", printer_id, backend_name); g_message("Getting all attributes ..\n"); cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name); if(p == NULL) continue; cpdb_options_t *opts = cpdbGetAllOptions(p); printf("Retrieved %d medias.\n", opts->media_count); GHashTableIter iter; gpointer value; g_hash_table_iter_init(&iter, opts->media); while (g_hash_table_iter_next(&iter, NULL, &value)) { printMedia(value); } } else if (strcmp(buf, "get-default") == 0) { char printer_id[BUFSIZE], backend_name[BUFSIZE], option_name[BUFSIZE]; scanf("%1023s%1023s%1023s", option_name, printer_id, backend_name); cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name); char *ans = cpdbGetDefault(p, option_name); if (!ans) printf("cpdb_option_t %s doesn't exist.", option_name); else printf("Default : %s\n", ans); } else if (strcmp(buf, "get-setting") == 0) { char printer_id[BUFSIZE], backend_name[BUFSIZE], setting_name[BUFSIZE]; scanf("%1023s%1023s%1023s", setting_name, printer_id, backend_name); cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name); char *ans = cpdbGetSetting(p, setting_name); if (!ans) printf("Setting %s doesn't exist.\n", setting_name); else printf("Setting value : %s\n", ans); } else if (strcmp(buf, "get-current") == 0) { char printer_id[BUFSIZE], backend_name[BUFSIZE], option_name[BUFSIZE]; scanf("%1023s%1023s%1023s", option_name, printer_id, backend_name); cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name); char *ans = cpdbGetCurrent(p, option_name); if (!ans) printf("cpdb_option_t %s doesn't exist.", option_name); else printf("Current value : %s\n", ans); } else if (strcmp(buf, "add-setting") == 0) { char printer_id[BUFSIZE], backend_name[BUFSIZE], option_name[BUFSIZE], option_val[BUFSIZE]; scanf("%1023s %1023s %1023s %1023s", option_name, option_val, printer_id, backend_name); cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name); printf("%s : %s\n", option_name, option_val); cpdbAddSettingToPrinter(p, cpdbGetStringCopy(option_name), cpdbGetStringCopy(option_val)); } else if (strcmp(buf, "clear-setting") == 0) { char printer_id[BUFSIZE], backend_name[BUFSIZE], option_name[BUFSIZE]; scanf("%1023s%1023s%1023s", option_name, printer_id, backend_name); cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name); cpdbClearSettingFromPrinter(p, option_name); } else if (strcmp(buf, "get-state") == 0) { char printer_id[BUFSIZE]; char backend_name[BUFSIZE]; scanf("%1023s%1023s", printer_id, backend_name); cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name); printf("%s\n", cpdbGetState(p)); } else if (strcmp(buf, "is-accepting-jobs") == 0) { char printer_id[BUFSIZE]; char backend_name[BUFSIZE]; scanf("%1023s%1023s", printer_id, backend_name); cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name); printf("Accepting jobs ? : %d \n", cpdbIsAcceptingJobs(p)); } else if (strcmp(buf, "help") == 0) { display_help(); } else if (strcmp(buf, "ping") == 0) { char printer_id[BUFSIZE], backend_name[BUFSIZE]; scanf("%1023s%1023s", printer_id, backend_name); cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name); print_backend_call_ping_sync(p->backend_proxy, p->id, NULL, NULL); } else if (strcmp(buf, "get-default-printer") == 0) { cpdb_printer_obj_t *p = cpdbGetDefaultPrinter(f); if (p) printf("%s#%s\n", p->name, p->backend_name); else printf("No default printer found\n"); } else if (strcmp(buf, "get-default-printer-for-backend") == 0) { char backend_name[BUFSIZE]; scanf("%1023s", backend_name); /** * Backend name = The last part of the backend dbus service * Eg. "CUPS" or "GCP" */ cpdb_printer_obj_t *p = cpdbGetDefaultPrinterForBackend(f, backend_name); printf("%s\n", p->name); } else if (strcmp(buf, "set-user-default-printer") == 0) { char printer_id[BUFSIZE]; char backend_name[BUFSIZE]; scanf("%1023s%1023s", printer_id, backend_name); cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name); if (p) { if (cpdbSetUserDefaultPrinter(p)) printf("Set printer as user default\n"); else printf("Couldn't set printer as user default\n"); } } else if (strcmp(buf, "set-system-default-printer") == 0) { char printer_id[BUFSIZE]; char backend_name[BUFSIZE]; scanf("%1023s%1023s", printer_id, backend_name); cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name); if (p) { if (cpdbSetSystemDefaultPrinter(p)) printf("Set printer as system default\n"); else printf("Couldn't set printer as system default\n"); } } else if (strcmp(buf, "print-file") == 0) { char printer_id[BUFSIZE], backend_name[BUFSIZE], file_path[BUFSIZE]; scanf("%1023s%1023s%1023s", file_path, printer_id, backend_name); /** * Try adding some settings here .. change them and experiment */ cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name); if(strcmp(backend_name, "FILE") == 0) { char final_file_path[BUFSIZE]; printf("Please give the final file path: "); scanf("%1023s", final_file_path); cpdbPrintFilePath(p, file_path, final_file_path); continue; } cpdbAddSettingToPrinter(p, "copies", "3"); cpdbPrintFile(p, file_path); } else if (strcmp(buf, "get-active-jobs-count") == 0) { char printer_id[BUFSIZE]; char backend_name[BUFSIZE]; scanf("%1023s%1023s", printer_id, backend_name); cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name); printf("%d jobs currently active.\n", cpdbGetActiveJobsCount(p)); } else if (strcmp(buf, "get-all-jobs") == 0) { int active_only; scanf("%d", &active_only); cpdb_job_t *j; int x = cpdbGetAllJobs(f, &j, active_only); printf("Total %d jobs\n", x); int i; for (i = 0; i < x; i++) { printf("%s .. %s .. %s .. %s .. %s\n", j[i].job_id, j[i].title, j[i].printer_id, j[i].state, j[i].submitted_at); } } else if (strcmp(buf, "cancel-job") == 0) { char printer_id[BUFSIZE]; char backend_name[BUFSIZE]; char job_id[BUFSIZE]; scanf("%1023s%1023s%1023s", job_id, printer_id, backend_name); cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name); if (cpdbCancelJob(p, job_id)) printf("cpdb_job_t %s has been cancelled.\n", job_id); else printf("Unable to cancel job %s\n", job_id); } else if (strcmp(buf, "pickle-printer") == 0) { char printer_id[BUFSIZE]; char backend_name[BUFSIZE]; char job_id[BUFSIZE]; scanf("%1023s%1023s", printer_id, backend_name); cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name); cpdbPicklePrinterToFile(p, "/tmp/.printer-pickle", f); } else if (strcmp(buf, "get-option-translation") == 0) { char printer_id[BUFSIZE]; char backend_name[BUFSIZE]; char option_name[BUFSIZE]; scanf("%1023s%1023s%1023s", option_name, printer_id, backend_name); cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name); printf("%s\n", cpdbGetOptionTranslation(p, option_name, locale)); } else if (strcmp(buf, "get-choice-translation") == 0) { char printer_id[BUFSIZE]; char backend_name[BUFSIZE]; char option_name[BUFSIZE]; char choice_name[BUFSIZE]; scanf("%1023s%1023s%1023s%1023s", option_name, choice_name, printer_id, backend_name); cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name); printf("%s\n", cpdbGetChoiceTranslation(p, option_name, choice_name, locale)); } else if (strcmp(buf, "get-group-translation") == 0) { char printer_id[BUFSIZE]; char backend_name[BUFSIZE]; char group_name[BUFSIZE]; scanf("%1023s%1023s%1023s", group_name, printer_id, backend_name); cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name); printf("%s\n", cpdbGetGroupTranslation(p, group_name, locale)); } else if (strcmp(buf, "get-all-translations") == 0) { char printer_id[BUFSIZE]; char backend_name[BUFSIZE]; scanf("%1023s%1023s", printer_id, backend_name); cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name); cpdbGetAllTranslations(p, locale); printTranslations(p); } else if (strcmp(buf, "get-media-size") == 0) { char printer_id[BUFSIZE]; char backend_name[BUFSIZE]; char media[BUFSIZE]; int width, length; scanf("%1023s%1023s%1023s", media, printer_id, backend_name); cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name); int ok = cpdbGetMediaSize(p, media, &width, &length); if (ok) printf("%dx%d\n", width, length); } else if (strcmp(buf, "get-media-margins") == 0) { char printer_id[BUFSIZE]; char backend_name[BUFSIZE]; char media[BUFSIZE]; scanf("%1023s%1023s%1023s", media, printer_id, backend_name); cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name); cpdb_margin_t *margins; int num_margins = cpdbGetMediaMargins(p, media, &margins); for (int i = 0; i < num_margins; i++) printf("%d %d %d %d\n", margins[i].left, margins[i].right, margins[i].top, margins[i].bottom); } else if (strcmp(buf, "acquire-details") == 0) { char printer_id[BUFSIZE]; char backend_name[BUFSIZE]; scanf("%1023s%1023s", printer_id, backend_name); cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name); if(p == NULL) continue; g_message("Acquiring printer details asynchronously...\n"); cpdbAcquireDetails(p, acquire_details_callback, NULL); } else if (strcmp(buf, "acquire-translations") == 0) { char printer_id[BUFSIZE]; char backend_name[BUFSIZE]; scanf("%1023s%1023s", printer_id, backend_name); cpdb_printer_obj_t *p = cpdbFindPrinterObj(f, printer_id, backend_name); if(p == NULL) continue; g_message("Acquiring printer translations asynchronously...\n"); cpdbAcquireTranslations(p, locale, acquire_translations_callback, NULL); } } } void display_help() { g_message("Available commands .. "); printf("%s\n", "stop"); printf("%s\n", "hide-remote"); printf("%s\n", "unhide-remote"); printf("%s\n", "hide-temporary"); printf("%s\n", "unhide-temporary"); //printf("%s\n", "ping "); printf("%s\n", "get-default-printer"); printf("%s\n", "get-default-printer-for-backend "); printf("%s\n", "set-user-default-printer "); printf("%s\n", "set-system-default-printer "); printf("%s\n", "print-file "); printf("%s\n", "get-active-jobs-count "); printf("%s\n", "get-all-jobs <0 for all jobs; 1 for only active>"); printf("%s\n", "get-state "); printf("%s\n", "is-accepting-jobs "); printf("%s\n", "cancel-job "); printf("%s\n", "acquire-details "); printf("%s\n", "acquire-translations "); printf("%s\n", "get-all-options "); printf("%s\n", "get-default