[gnome-control-center] printers: Add dialog for adding new printers



commit 3fb4d4af2745124c3d370c0fcc94fdb5886af245
Author: Marek Kasik <mkasik redhat com>
Date:   Mon Mar 7 17:09:00 2011 +0100

    printers: Add dialog for adding new printers
    
    The dialog is able to add printers discovered by cupsGetDevices().
    It can also add printers from a remote CUPS server by typing
    its address and selecting printer we want to add (#640734).

 panels/printers/Makefile.am             |    5 +
 panels/printers/cc-printers-panel.c     |  273 +++------
 panels/printers/new-printer-dialog.ui   |  247 +++++++
 panels/printers/pp-new-printer-dialog.c | 1066 +++++++++++++++++++++++++++++++
 panels/printers/pp-new-printer-dialog.h |   39 ++
 panels/printers/pp-utils.c              |  385 +++++++++++
 panels/printers/pp-utils.h              |   59 ++
 7 files changed, 1887 insertions(+), 187 deletions(-)
---
diff --git a/panels/printers/Makefile.am b/panels/printers/Makefile.am
index 96caf47..4f319eb 100644
--- a/panels/printers/Makefile.am
+++ b/panels/printers/Makefile.am
@@ -2,6 +2,7 @@ cappletname = printers
 
 uidir = $(pkgdatadir)/ui/printers
 dist_ui_DATA = \
+	new-printer-dialog.ui	\
 	printers.ui
 
 INCLUDES = 						\
@@ -17,6 +18,10 @@ ccpanels_LTLIBRARIES = libprinters.la
 
 libprinters_la_SOURCES =		\
 	printers-module.c	\
+	pp-utils.c	\
+	pp-utils.h	\
+	pp-new-printer-dialog.c	\
+	pp-new-printer-dialog.h	\
 	cc-printers-panel.c	\
 	cc-printers-panel.h
 
diff --git a/panels/printers/cc-printers-panel.c b/panels/printers/cc-printers-panel.c
index 84bd7f7..9dc6401 100644
--- a/panels/printers/cc-printers-panel.c
+++ b/panels/printers/cc-printers-panel.c
@@ -33,6 +33,8 @@
 #include <math.h>
 
 #include "cc-lockbutton.h"
+#include "pp-new-printer-dialog.h"
+#include "pp-utils.h"
 
 G_DEFINE_DYNAMIC_TYPE (CcPrintersPanel, cc_printers_panel, CC_TYPE_PANEL)
 
@@ -71,6 +73,8 @@ struct _CcPrintersPanelPrivate
 
   GPermission *permission;
 
+  PpNewPrinterDialog *pp_new_printer_dialog;
+
   gpointer dummy;
 };
 
@@ -172,32 +176,6 @@ cc_printers_panel_class_finalize (CcPrintersPanelClass *klass)
 {
 }
 
-gchar *
-get_ppd_attribute (const gchar *printer_name, const gchar *attribute_name)
-{
-  gchar *file_name = NULL;
-  ppd_file_t *ppd_file = NULL;
-  ppd_attr_t *ppd_attr = NULL;
-  gchar *result = NULL;
-
-  file_name = cupsGetPPD (printer_name);
-
-  if (file_name)
-    {
-      ppd_file = ppdOpenFile (file_name);
-      if (ppd_file)
-        {
-          ppd_attr = ppdFindAttr (ppd_file, attribute_name, NULL);
-          if (ppd_attr != NULL)
-            result = g_strdup (ppd_attr->value);
-          ppdClose (ppd_file);
-        }
-      g_unlink (file_name);
-    }
-
-  return result;
-}
-
 enum
 {
   PRINTER_ID_COLUMN,
@@ -1168,73 +1146,6 @@ enum
   ALLOWED_USERS_N_COLUMNS
 };
 
-static int
-ccGetAllowedUsers (gchar ***allowed_users, char *printer_name)
-{
-  const char * const   attrs[1] = { "requesting-user-name-allowed" };
-  http_t              *http;
-  ipp_t               *request = NULL;
-  gchar              **users = NULL;
-  ipp_t               *response;
-  char                 uri[HTTP_MAX_URI + 1];
-  int                  num_allowed_users = 0;
-
-  http = httpConnectEncrypt (cupsServer (),
-                             ippPort (),
-                             cupsEncryption ());
-
-  if (http || !allowed_users)
-    {
-      request = ippNewRequest (IPP_GET_PRINTER_ATTRIBUTES);
-
-      g_snprintf (uri, sizeof (uri), "ipp://localhost/printers/%s", printer_name);
-      ippAddString (request,
-                    IPP_TAG_OPERATION,
-                    IPP_TAG_URI,
-                    "printer-uri",
-                    NULL,
-                    uri);
-      ippAddStrings (request,
-                     IPP_TAG_OPERATION,
-                     IPP_TAG_KEYWORD,
-                     "requested-attributes",
-                     1,
-                     NULL,
-                     attrs);
-
-      response = cupsDoRequest (http, request, "/");
-      if (response)
-        {
-          ipp_attribute_t *attr = NULL;
-          ipp_attribute_t *allowed = NULL;
-
-          for (attr = response->attrs; attr != NULL; attr = attr->next)
-            {
-              if (attr->group_tag == IPP_TAG_PRINTER &&
-                  attr->value_tag == IPP_TAG_NAME &&
-                  !g_strcmp0 (attr->name, "requesting-user-name-allowed"))
-                allowed = attr;
-            }
-
-          if (allowed && allowed->num_values > 0)
-            {
-              int i;
-
-              num_allowed_users = allowed->num_values;
-              users = g_new (gchar*, num_allowed_users);
-
-              for (i = 0; i < num_allowed_users; i ++)
-                users[i] = g_strdup (allowed->values[i].string.text);
-            }
-          ippDelete(response);
-        }
-       httpClose (http);
-     }
-
-  *allowed_users = users;
-  return num_allowed_users;
-}
-
 static void
 actualize_allowed_users_list (CcPrintersPanel *self)
 {
@@ -1330,33 +1241,6 @@ populate_allowed_users_list (CcPrintersPanel *self)
                     "changed", G_CALLBACK (allowed_users_selection_changed_cb), self);
 }
 
-static DBusGProxy *
-get_dbus_proxy ()
-{
-  DBusGConnection *system_bus;
-  DBusGProxy      *proxy;
-  GError          *error;
-
-  error = NULL;
-  system_bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
-  if (system_bus == NULL)
-    {
-      /* Translators: Program cannot connect to DBus' system bus */
-      g_warning (_("Could not connect to system bus: %s"),
-                 error->message);
-      g_error_free (error);
-      return NULL;
-    }
-
-  error = NULL;
-
-  proxy = dbus_g_proxy_new_for_name (system_bus,
-                                     MECHANISM_BUS,
-                                     "/",
-                                     MECHANISM_BUS);
-  return proxy;
-}
-
 static void
 job_process_cb (GtkButton *button,
                 gpointer   user_data)
@@ -1378,7 +1262,10 @@ job_process_cb (GtkButton *button,
 
   if (id >= 0)
     {
-      proxy = get_dbus_proxy ();
+      proxy = get_dbus_proxy (MECHANISM_BUS,
+                              "/",
+                              MECHANISM_BUS,
+                              TRUE);
 
       if (!proxy)
         return;
@@ -1471,7 +1358,10 @@ printer_disable_cb (GObject    *gobject,
 
   if (name)
     {
-      proxy = get_dbus_proxy ();
+      proxy = get_dbus_proxy (MECHANISM_BUS,
+                              "/",
+                              MECHANISM_BUS,
+                              TRUE);
 
       if (!proxy)
         return;
@@ -1718,7 +1608,10 @@ allowed_user_remove_cb (GtkToolButton *button,
 
   if (name && printer_name)
     {
-      proxy = get_dbus_proxy ();
+      proxy = get_dbus_proxy (MECHANISM_BUS,
+                              "/",
+                              MECHANISM_BUS,
+                              TRUE);
 
       if (!proxy)
         return;
@@ -1788,7 +1681,10 @@ allowed_user_add_cb (GtkCellRendererText *renderer,
 
   if (new_text && new_text[0] != '\0' && printer_name)
     {
-      proxy = get_dbus_proxy ();
+      proxy = get_dbus_proxy (MECHANISM_BUS,
+                              "/",
+                              MECHANISM_BUS,
+                              TRUE);
 
       if (!proxy)
         return;
@@ -1889,7 +1785,10 @@ printer_set_default_cb (GtkToggleButton *button,
 
   if (name)
     {
-      proxy = get_dbus_proxy ();
+      proxy = get_dbus_proxy (MECHANISM_BUS,
+                              "/",
+                              MECHANISM_BUS,
+                              TRUE);
 
       if (!proxy)
         return;
@@ -1923,6 +1822,58 @@ printer_set_default_cb (GtkToggleButton *button,
 }
 
 static void
+new_printer_dialog_response_cb (GtkDialog *dialog,
+                                gint       response_id,
+                                gpointer   user_data)
+{
+  CcPrintersPanelPrivate *priv;
+  CcPrintersPanel        *self = (CcPrintersPanel*) user_data;
+
+  priv = PRINTERS_PANEL_PRIVATE (self);
+
+  pp_new_printer_dialog_free (priv->pp_new_printer_dialog);
+  priv->pp_new_printer_dialog = NULL;
+
+  if (response_id == GTK_RESPONSE_OK)
+    actualize_printers_list (self);
+  else if (response_id == GTK_RESPONSE_REJECT)
+    {
+      GtkWidget *message_dialog;
+
+      message_dialog = gtk_message_dialog_new (NULL,
+                                               0,
+                                               GTK_MESSAGE_ERROR,
+                                               GTK_BUTTONS_CLOSE,
+      /* Translators: Addition of the new printer failed. */
+                                               _("Failed to add new printer."));
+      g_signal_connect (message_dialog,
+                        "response",
+                        G_CALLBACK (gtk_widget_destroy),
+                        NULL);
+      gtk_widget_show (message_dialog);
+    }
+}
+
+static void
+printer_add_cb (GtkToolButton *toolbutton,
+                gpointer       user_data)
+{
+  CcPrintersPanelPrivate *priv;
+  CcPrintersPanel        *self = (CcPrintersPanel*) user_data;
+  GtkWidget              *widget;
+
+  priv = PRINTERS_PANEL_PRIVATE (self);
+
+  widget = (GtkWidget*)
+    gtk_builder_get_object (priv->builder, "main-vbox");
+
+  priv->pp_new_printer_dialog = pp_new_printer_dialog_new (
+    GTK_WINDOW (gtk_widget_get_toplevel (widget)),
+    new_printer_dialog_response_cb,
+    self);
+}
+
+static void
 printer_remove_cb (GtkToolButton *toolbutton,
                    gpointer       user_data)
 {
@@ -1942,7 +1893,10 @@ printer_remove_cb (GtkToolButton *toolbutton,
 
   if (name)
     {
-      proxy = get_dbus_proxy ();
+      proxy = get_dbus_proxy (MECHANISM_BUS,
+                              "/",
+                              MECHANISM_BUS,
+                              TRUE);
 
       if (!proxy)
         return;
@@ -1966,67 +1920,6 @@ printer_remove_cb (GtkToolButton *toolbutton,
   }
 }
 
-static ipp_t *
-execute_maintenance_command (const char *printer_name,
-                             const char *command,
-                             const char *title)
-{
-  http_t *http;
-  GError *error = NULL;
-  ipp_t  *request = NULL;
-  ipp_t  *response = NULL;
-  char    uri[HTTP_MAX_URI + 1];
-  int     fd = -1;
-
-  http = httpConnectEncrypt (cupsServer (),
-                             ippPort (),
-                             cupsEncryption ());
-
-  if (http)
-    {
-      request = ippNewRequest (IPP_PRINT_JOB);
-
-      g_snprintf (uri,
-                  sizeof (uri),
-                  "ipp://localhost/printers/%s",
-                  printer_name);
-
-      ippAddString (request,
-                    IPP_TAG_OPERATION,
-                    IPP_TAG_URI,
-                    "printer-uri",
-                    NULL,
-                    uri);
-
-      ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name",
-                    NULL, title);
-
-      ippAddString (request, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format",
-                    NULL, "application/vnd.cups-command");
-
-      gchar *file_name = NULL;
-      fd = g_file_open_tmp ("ccXXXXXX", &file_name, &error);
-
-      if (fd != -1 && !error)
-        {
-          FILE *file;
-
-          file = fdopen (fd, "w");
-          fprintf (file, "#CUPS-COMMAND\n");
-          fprintf (file, "%s\n", command);
-          fclose (file);
-
-          response = cupsDoFileRequest (http, request, "/", file_name);
-          g_unlink (file_name);
-        }
-
-      g_free (file_name);
-      httpClose (http);
-    }
-
-  return response;
-}
-
 static void
 printer_maintenance_cb (GtkButton *button,
                         gpointer   user_data)
@@ -2185,6 +2078,8 @@ cc_printers_panel_init (CcPrintersPanel *self)
   priv->num_allowed_users = 0;
   priv->current_allowed_user = -1;
 
+  priv->pp_new_printer_dialog = NULL;
+
   gtk_builder_add_objects_from_file (priv->builder,
                                      DATADIR"/printers.ui",
                                      objects, &error);
@@ -2215,6 +2110,10 @@ cc_printers_panel_init (CcPrintersPanel *self)
   g_signal_connect (widget, "clicked", G_CALLBACK (job_process_cb), self);
 
   widget = (GtkWidget*)
+    gtk_builder_get_object (priv->builder, "printer-add-button");
+  g_signal_connect (widget, "clicked", G_CALLBACK (printer_add_cb), self);
+
+  widget = (GtkWidget*)
     gtk_builder_get_object (priv->builder, "printer-remove-button");
   g_signal_connect (widget, "clicked", G_CALLBACK (printer_remove_cb), self);
 
diff --git a/panels/printers/new-printer-dialog.ui b/panels/printers/new-printer-dialog.ui
new file mode 100644
index 0000000..f76c105
--- /dev/null
+++ b/panels/printers/new-printer-dialog.ui
@@ -0,0 +1,247 @@
+<?xml version="1.0"?>
+<interface>
+  <requires lib="gtk+" version="2.16"/>
+  <!-- interface-naming-policy project-wide -->
+  <object class="GtkDialog" id="dialog">
+    <property name="width_request">500</property>
+    <property name="height_request">350</property>
+    <property name="border_width">5</property>
+    <property name="resizable">False</property>
+    <property name="type_hint">normal</property>
+    <child internal-child="vbox">
+      <object class="GtkVBox" id="dialog-vbox1">
+        <property name="visible">True</property>
+        <property name="orientation">vertical</property>
+        <property name="spacing">2</property>
+        <child>
+          <object class="GtkVBox" id="vbox1">
+            <property name="visible">True</property>
+            <property name="orientation">vertical</property>
+            <property name="spacing">10</property>
+            <child>
+              <object class="GtkLabel" id="label1">
+                <property name="visible">True</property>
+                <property name="xalign">0</property>
+                <property name="label" translatable="yes">Add a New Printer</property>
+                <attributes>
+                  <attribute name="weight" value="bold"/>
+                </attributes>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkHBox" id="hbox1">
+                <property name="visible">True</property>
+                <property name="spacing">10</property>
+                <child>
+                  <object class="GtkTreeView" id="device-types-treeview">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="headers_visible">False</property>
+                    <property name="headers_clickable">False</property>
+                  </object>
+                  <packing>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkNotebook" id="device-type-notebook">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="show_tabs">False</property>
+                    <property name="show_border">False</property>
+                    <child>
+                      <object class="GtkScrolledWindow" id="scrolledwindow2">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                        <property name="hscrollbar_policy">automatic</property>
+                        <property name="vscrollbar_policy">automatic</property>
+                        <child>
+                          <object class="GtkTreeView" id="local-devices-treeview">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="headers_visible">False</property>
+                          </object>
+                        </child>
+                      </object>
+                    </child>
+                    <child type="tab">
+                      <object class="GtkLabel" id="label2">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">page 1</property>
+                      </object>
+                      <packing>
+                        <property name="tab_fill">False</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <object class="GtkVBox" id="vbox2">
+                        <property name="visible">True</property>
+                        <property name="orientation">vertical</property>
+                        <child>
+                          <object class="GtkScrolledWindow" id="scrolledwindow1">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="hscrollbar_policy">never</property>
+                            <property name="vscrollbar_policy">automatic</property>
+                            <child>
+                              <object class="GtkTreeView" id="network-devices-treeview">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="headers_visible">False</property>
+                                <property name="headers_clickable">False</property>
+                              </object>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkHBox" id="hbox2">
+                            <property name="visible">True</property>
+                            <child>
+                              <object class="GtkLabel" id="label5">
+                                <property name="visible">True</property>
+                                <property name="label" translatable="yes">Address</property>
+                              </object>
+                              <packing>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkEntry" id="address-entry">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="invisible_char">&#x25CF;</property>
+                              </object>
+                              <packing>
+                                <property name="position">1</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="position">1</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkHBox" id="hbox3">
+                            <property name="visible">True</property>
+                            <child>
+                              <object class="GtkCheckButton" id="search-by-address-checkbutton">
+                                <property name="label" translatable="yes">Search by Address</property>
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="receives_default">False</property>
+                                <property name="draw_indicator">True</property>
+                              </object>
+                              <packing>
+                                <property name="position">0</property>
+                              </packing>
+                            </child>
+                            <child>
+                              <object class="GtkLabel" id="search-state-label">
+                                <property name="visible">True</property>
+                              </object>
+                              <packing>
+                                <property name="position">2</property>
+                              </packing>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="position">2</property>
+                          </packing>
+                        </child>
+                      </object>
+                      <packing>
+                        <property name="position">1</property>
+                      </packing>
+                    </child>
+                    <child type="tab">
+                      <object class="GtkLabel" id="label3">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">page 2</property>
+                      </object>
+                      <packing>
+                        <property name="position">1</property>
+                        <property name="tab_fill">False</property>
+                      </packing>
+                    </child>
+                    <child>
+                      <placeholder/>
+                    </child>
+                    <child type="tab">
+                      <object class="GtkLabel" id="label4">
+                        <property name="visible">True</property>
+                        <property name="label" translatable="yes">page 3</property>
+                      </object>
+                      <packing>
+                        <property name="position">2</property>
+                        <property name="tab_fill">False</property>
+                      </packing>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child internal-child="action_area">
+          <object class="GtkHButtonBox" id="dialog-action_area1">
+            <property name="visible">True</property>
+            <property name="layout_style">end</property>
+            <child>
+              <object class="GtkButton" id="new-printer-cancel-button">
+                <property name="label" translatable="yes">Cancel</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkButton" id="new-printer-add-button">
+                <property name="label" translatable="yes">Add</property>
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="receives_default">True</property>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">False</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="expand">False</property>
+            <property name="pack_type">end</property>
+            <property name="position">0</property>
+          </packing>
+        </child>
+      </object>
+    </child>
+    <action-widgets>
+      <action-widget response="0">new-printer-cancel-button</action-widget>
+      <action-widget response="0">new-printer-add-button</action-widget>
+    </action-widgets>
+  </object>
+</interface>
diff --git a/panels/printers/pp-new-printer-dialog.c b/panels/printers/pp-new-printer-dialog.c
new file mode 100644
index 0000000..7c0f318
--- /dev/null
+++ b/panels/printers/pp-new-printer-dialog.c
@@ -0,0 +1,1066 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright 2009-2010  Red Hat, Inc,
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+#include <gtk/gtk.h>
+
+#include <cups/cups.h>
+
+#include "pp-new-printer-dialog.h"
+#include "pp-utils.h"
+
+#include <dbus/dbus-glib.h>
+
+#ifdef GDK_WINDOWING_X11
+#include <gdk/gdkx.h>
+#endif
+
+#define MECHANISM_BUS "org.opensuse.CupsPkHelper.Mechanism"
+
+#define PACKAGE_KIT_BUS "org.freedesktop.PackageKit"
+#define PACKAGE_KIT_PATH "/org/freedesktop/PackageKit"
+#define PACKAGE_KIT_IFACE "org.freedesktop.PackageKit.Modify"
+
+#define ALLOWED_CHARACTERS "abcdefghijklmnopqrtsuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_/"
+
+static void pp_new_printer_dialog_hide (PpNewPrinterDialog *pp);
+static void actualize_devices_list (PpNewPrinterDialog *pp, gboolean get_devices);
+
+enum
+{
+  NOTEBOOK_LOCAL_PAGE = 0,
+  NOTEBOOK_NETWORK_PAGE,
+  NOTEBOOK_HP_JETDIRECT_PAGE,
+  NOTEBOOK_N_PAGES
+};
+
+enum
+{
+  DEVICE_TYPE_ID_COLUMN = 0,
+  DEVICE_TYPE_NAME_COLUMN,
+  DEVICE_TYPE_TYPE_COLUMN,
+  DEVICE_TYPE_N_COLUMNS
+};
+
+enum
+{
+  DEVICE_ID_COLUMN = 0,
+  DEVICE_NAME_COLUMN,
+  DEVICE_N_COLUMNS
+};
+
+enum
+{
+  DEVICE_TYPE_LOCAL = 0,
+  DEVICE_TYPE_NETWORK,
+  DEVICE_TYPE_HP_JETDIRECT,
+  DEVICE_TYPE_N
+};
+
+typedef struct{
+  gchar *device_class;
+  gchar *device_id;
+  gchar *device_info;
+  gchar *device_make_and_model;
+  gchar *device_uri;
+  gchar *device_location;
+  gchar *device_ppd_uri;
+  gchar *display_name;
+  gchar *hostname;
+  gint   host_port;
+  gboolean show;
+  gboolean found;
+} CupsDevice;
+
+struct _PpNewPrinterDialog {
+  GtkBuilder *builder;
+  GtkWidget  *parent;
+
+  GtkWidget  *dialog;
+
+  gchar **device_connection_types;
+  gint    num_device_connection_types;
+
+  CupsDevice *devices;
+  gint        num_devices;
+
+  UserResponseCallback user_callback;
+  gpointer             user_data;
+};
+
+static void
+device_type_selection_changed_cb (GtkTreeSelection *selection,
+                                  gpointer          user_data)
+{
+  PpNewPrinterDialog *pp = (PpNewPrinterDialog *) user_data;
+  GtkTreeModel       *model;
+  GtkTreeIter         iter;
+  gchar              *device_type_name = NULL;
+  gint                device_type_id = -1;
+  gint                device_type = -1;
+
+  if (gtk_tree_selection_get_selected (selection, &model, &iter))
+    {
+      gtk_tree_model_get (model, &iter,
+			  DEVICE_TYPE_ID_COLUMN, &device_type_id,
+			  DEVICE_TYPE_NAME_COLUMN, &device_type_name,
+			  DEVICE_TYPE_TYPE_COLUMN, &device_type,
+			  -1);
+    }
+
+  if (device_type >= 0)
+    {
+      GtkWidget *widget;
+
+      widget = (GtkWidget*)
+        gtk_builder_get_object (pp->builder, "device-type-notebook");
+
+      gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), device_type);
+    }
+}
+
+static void
+free_devices (PpNewPrinterDialog *pp)
+{
+  int i;
+
+  for (i = 0; i < pp->num_devices; i++)
+    {
+      g_free (pp->devices[i].device_class);
+      g_free (pp->devices[i].device_id);
+      g_free (pp->devices[i].device_info);
+      g_free (pp->devices[i].device_make_and_model);
+      g_free (pp->devices[i].device_uri);
+      g_free (pp->devices[i].device_location);
+      g_free (pp->devices[i].device_ppd_uri);
+      g_free (pp->devices[i].display_name);
+      g_free (pp->devices[i].hostname);
+    }
+
+  pp->num_devices = 0;
+  pp->devices = NULL;
+}
+
+static void
+store_device_parameter (gpointer key,
+                        gpointer value,
+                        gpointer user_data)
+{
+  PpNewPrinterDialog *pp = (PpNewPrinterDialog *) user_data;
+  gchar *cut;
+  gint   index = -1;
+
+  cut = g_strrstr ((gchar *)key, ":");
+  if (cut)
+    index = atoi ((gchar *)cut + 1);
+
+  if (index >= 0)
+    {
+      if (g_str_has_prefix ((gchar *)key, "device-class"))
+        pp->devices[index].device_class = g_strdup ((gchar *)value);
+      else if (g_str_has_prefix ((gchar *)key, "device-id"))
+        pp->devices[index].device_id = g_strdup ((gchar *)value);
+      else if (g_str_has_prefix ((gchar *)key, "device-info"))
+        pp->devices[index].device_info = g_strdup ((gchar *)value);
+      else if (g_str_has_prefix ((gchar *)key, "device-make-and-model"))
+        pp->devices[index].device_make_and_model = g_strdup ((gchar *)value);
+      else if (g_str_has_prefix ((gchar *)key, "device-uri"))
+        pp->devices[index].device_uri = g_strdup ((gchar *)value);
+      else if (g_str_has_prefix ((gchar *)key, "device-location"))
+        pp->devices[index].device_location = g_strdup ((gchar *)value);
+    }
+}
+
+static void
+devices_get (PpNewPrinterDialog *pp)
+{
+  DBusGProxy *proxy;
+  GError     *error = NULL;
+  char       *ret_error = NULL;
+  gint        i, j;
+
+  proxy = get_dbus_proxy (MECHANISM_BUS,
+                          "/",
+                          MECHANISM_BUS,
+                          TRUE);
+
+  if (!proxy)
+    return;
+
+  GHashTable *devices = NULL;
+  dbus_g_proxy_call (proxy, "DevicesGet", &error,
+                     G_TYPE_INT, 60,
+                     G_TYPE_STRING, CUPS_INCLUDE_ALL,
+                     G_TYPE_STRING, CUPS_EXCLUDE_NONE,
+                     G_TYPE_INVALID,
+                     G_TYPE_STRING, &ret_error,
+                     DBUS_TYPE_G_STRING_STRING_HASHTABLE, &devices,
+                     G_TYPE_INVALID);
+
+  g_object_unref (proxy);
+
+  if (error || (ret_error && ret_error[0] != '\0'))
+    {
+      if (error)
+        g_warning ("%s", error->message);
+
+      if (ret_error && ret_error[0] != '\0')
+        g_warning ("%s", ret_error);
+    }
+
+  free_devices (pp);
+  if (devices)
+    {
+      GList *keys;
+      GList *iter;
+      gchar *cut;
+      gint   max_index = -1;
+      gint   index;
+
+      keys = g_hash_table_get_keys (devices);
+      for (iter = keys; iter; iter = iter->next)
+        {
+          index = -1;
+
+          cut = g_strrstr ((gchar *)iter->data, ":");
+          if (cut)
+            index = atoi (cut + 1);
+
+          if (index > max_index)
+            max_index = index;
+        }
+
+      if (max_index >= 0)
+        {
+          pp->num_devices = max_index + 1;
+          pp->devices = g_new0 (CupsDevice, pp->num_devices);
+
+          g_hash_table_foreach (devices, store_device_parameter, pp);
+
+          /* Assign names to devices */
+          for (i = 0; i < pp->num_devices; i++)
+            {
+              gchar *name = NULL;
+
+              if (pp->devices[i].device_id)
+                {
+                  name = get_tag_value (pp->devices[i].device_id, "mdl");
+                  name = g_strcanon (name, ALLOWED_CHARACTERS, '-');
+                }
+              else if (pp->devices[i].device_info)
+                {
+                  name = g_strdup (pp->devices[i].device_info);
+                  name = g_strcanon (name, ALLOWED_CHARACTERS, '-');
+                }
+
+              pp->devices[i].display_name = name;
+            }
+
+          /* Set show bool
+           * Don't show duplicates.
+           * Show devices with device-id.
+           * Other preferences should apply here.
+           */
+          for (i = 0; i < pp->num_devices; i++)
+            {
+              for (j = 0; j < pp->num_devices; j++)
+                {
+                  if (i != j)
+                    {
+                      if (g_strcmp0 (pp->devices[i].display_name, pp->devices[j].display_name) == 0)
+                        {
+                          if (pp->devices[i].device_id && !pp->devices[j].show)
+                            {
+                              pp->devices[i].show = TRUE;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+      g_hash_table_destroy (devices);
+    }
+
+  g_clear_error (&error);
+}
+
+static void
+search_address_cb (GtkToggleButton *togglebutton,
+                   gpointer         user_data)
+{
+  PpNewPrinterDialog *pp = (PpNewPrinterDialog*) user_data;
+  GtkWidget *widget;
+  gint i;
+
+  widget = (GtkWidget*)
+    gtk_builder_get_object (pp->builder, "search-by-address-checkbutton");
+
+  if (widget && gtk_toggle_button_get_active (togglebutton))
+    {
+      gchar *uri = NULL;
+
+      widget = (GtkWidget*)
+        gtk_builder_get_object (pp->builder, "address-entry");
+      uri = g_strdup (gtk_entry_get_text (GTK_ENTRY (widget)));
+
+      if (uri && uri[0] != '\0')
+        {
+          http_t *http;
+          cups_dest_t *dests = NULL;
+          gint num_dests = 0;
+          gchar *tmp = NULL;
+          gchar *host = NULL;
+          gchar *port_string = NULL;
+          int  port = 631;
+          gchar *position;
+
+          if (g_strrstr (uri, "://"))
+            tmp = g_strrstr (uri, "://") + 3;
+          else
+            tmp = uri;
+
+          if (g_strrstr (tmp, "@"))
+            tmp = g_strrstr (tmp, "@") + 1;
+
+          if ((position = g_strrstr (tmp, "/")))
+            {
+              *position = '\0';
+              host = g_strdup (tmp);
+              *position = '/';
+            }
+          else
+            host = g_strdup (tmp);
+
+          if ((position = g_strrstr (host, ":")))
+            {
+              *position = '\0';
+              port_string = position + 1;
+            }
+
+          if (port_string)
+            port = atoi (port_string);
+
+          /* Search for CUPS server */
+          if (host)
+            {
+              http = httpConnectEncrypt (host, port, cupsEncryption ());
+              if (http)
+                {
+                  gchar *device_uri = NULL;
+                  gchar *device_ppd_uri = NULL;
+
+                  num_dests = cupsGetDests2 (http, &dests);
+
+                  if (num_dests > 0)
+                    {
+                      CupsDevice *devices = NULL;
+                      devices = g_new0 (CupsDevice, pp->num_devices + num_dests);
+
+                      for (i = 0; i < pp->num_devices; i++)
+                        {
+                          devices[i] = pp->devices[i];
+                          pp->devices[i].device_class = NULL;
+                          pp->devices[i].device_id = NULL;
+                          pp->devices[i].device_info = NULL;
+                          pp->devices[i].device_make_and_model = NULL;
+                          pp->devices[i].device_uri = NULL;
+                          pp->devices[i].device_location = NULL;
+                          pp->devices[i].device_ppd_uri = NULL;
+                          pp->devices[i].display_name = NULL;
+                          pp->devices[i].hostname = NULL;
+                        }
+
+                      g_free (pp->devices);
+                      pp->devices = devices;
+
+                      for (i = 0; i < num_dests; i++)
+                        {
+                          device_uri = g_strdup_printf ("ipp://%s:%d/printers/%s", host, port, dests[i].name);
+                          device_ppd_uri = g_strdup_printf ("%s.ppd", device_uri);
+
+                          pp->devices[pp->num_devices + i].device_class = g_strdup ("network");
+                          pp->devices[pp->num_devices + i].device_uri = device_uri;
+                          pp->devices[pp->num_devices + i].display_name = g_strdup (dests[i].name);
+                          pp->devices[pp->num_devices + i].device_ppd_uri = device_ppd_uri;
+                          pp->devices[pp->num_devices + i].show = TRUE;
+                          pp->devices[pp->num_devices + i].hostname = g_strdup (host);
+                          pp->devices[pp->num_devices + i].host_port = port;
+                          pp->devices[pp->num_devices + i].found = TRUE;
+                        }
+
+                      pp->num_devices += num_dests;
+                    }
+
+                  httpClose (http);
+                }
+              g_free (host);
+            }
+        }
+      g_free (uri);
+    }
+  else
+    {
+      gint length = 0;
+      gint j = 0;
+
+      for (i = 0; i < pp->num_devices; i++)
+        if (!pp->devices[i].found)
+          length++;
+
+      CupsDevice *devices = NULL;
+      devices = g_new0 (CupsDevice, length);
+
+      for (i = 0; i < pp->num_devices; i++)
+        {
+          if (!pp->devices[i].found)
+            {
+              devices[j] = pp->devices[i];
+              pp->devices[i].device_class = NULL;
+              pp->devices[i].device_id = NULL;
+              pp->devices[i].device_info = NULL;
+              pp->devices[i].device_make_and_model = NULL;
+              pp->devices[i].device_uri = NULL;
+              pp->devices[i].device_location = NULL;
+              pp->devices[i].device_ppd_uri = NULL;
+              pp->devices[i].display_name = NULL;
+              pp->devices[i].hostname = NULL;
+              j++;
+            }
+        }
+
+      g_free (pp->devices);
+      pp->devices = devices;
+      pp->num_devices = length;
+    }
+
+  actualize_devices_list (pp, FALSE);
+}
+
+static void
+actualize_devices_list (PpNewPrinterDialog *pp, gboolean get_devices)
+{
+  GtkListStore *network_store;
+  GtkListStore *local_store;
+  GtkTreeView  *network_treeview;
+  GtkTreeView  *local_treeview;
+  GtkTreeIter   iter;
+  gint          i;
+
+  if (get_devices)
+    devices_get (pp);
+
+  network_treeview = (GtkTreeView*)
+    gtk_builder_get_object (pp->builder, "network-devices-treeview");
+
+  local_treeview = (GtkTreeView*)
+    gtk_builder_get_object (pp->builder, "local-devices-treeview");
+
+  network_store = gtk_list_store_new (DEVICE_N_COLUMNS,
+                                      G_TYPE_INT,
+                                      G_TYPE_STRING);
+
+  local_store = gtk_list_store_new (DEVICE_N_COLUMNS,
+                                    G_TYPE_INT,
+                                    G_TYPE_STRING);
+
+  for (i = 0; i < pp->num_devices; i++)
+    {
+      if (pp->devices[i].device_id || pp->devices[i].device_ppd_uri)
+        {
+          if (g_strcmp0 (pp->devices[i].device_class, "network") == 0)
+            {
+              gtk_list_store_append (network_store, &iter);
+              gtk_list_store_set (network_store, &iter,
+                                  DEVICE_ID_COLUMN, i,
+                                  DEVICE_NAME_COLUMN, pp->devices[i].display_name,
+                                  -1);
+            }
+          else if (g_strcmp0 (pp->devices[i].device_class, "direct") == 0)
+            {
+              gtk_list_store_append (local_store, &iter);
+              gtk_list_store_set (local_store, &iter,
+                                  DEVICE_ID_COLUMN, i,
+                                  DEVICE_NAME_COLUMN, pp->devices[i].display_name,
+                                  -1);
+            }
+        }
+    }
+
+  gtk_tree_view_set_model (network_treeview, GTK_TREE_MODEL (network_store));
+  gtk_tree_view_set_model (local_treeview, GTK_TREE_MODEL (local_store));
+
+  gtk_tree_model_get_iter_first ((GtkTreeModel *) network_store, &iter);
+  gtk_tree_selection_select_iter (
+    gtk_tree_view_get_selection (GTK_TREE_VIEW (network_treeview)),
+    &iter);
+
+  gtk_tree_model_get_iter_first ((GtkTreeModel *) local_store, &iter);
+  gtk_tree_selection_select_iter (
+    gtk_tree_view_get_selection (GTK_TREE_VIEW (local_treeview)),
+    &iter);
+
+  g_object_unref (network_store);
+  g_object_unref (local_store);
+}
+
+static void
+populate_devices_list (PpNewPrinterDialog *pp)
+{
+  GtkTreeViewColumn *column;
+  GtkCellRenderer   *renderer;
+  GtkWidget         *network_treeview;
+  GtkWidget         *local_treeview;
+
+  network_treeview = (GtkWidget*)
+    gtk_builder_get_object (pp->builder, "network-devices-treeview");
+
+  local_treeview = (GtkWidget*)
+    gtk_builder_get_object (pp->builder, "local-devices-treeview");
+
+  actualize_devices_list (pp, TRUE);
+
+  renderer = gtk_cell_renderer_text_new ();
+
+  /* Translators: Column of devices which can be installed */
+  column = gtk_tree_view_column_new_with_attributes (_("Devices"), renderer,
+                                                     "text", DEVICE_NAME_COLUMN, NULL);
+  gtk_tree_view_append_column (GTK_TREE_VIEW (network_treeview), column);
+
+  /* Translators: Column of devices which can be installed */
+  column = gtk_tree_view_column_new_with_attributes (_("Devices"), renderer,
+                                                     "text", DEVICE_NAME_COLUMN, NULL);
+  gtk_tree_view_append_column (GTK_TREE_VIEW (local_treeview), column);
+}
+
+static void
+actualize_device_types_list (PpNewPrinterDialog *pp)
+{
+  GtkListStore *store;
+  GtkTreeView  *treeview;
+  GtkTreeIter   iter;
+  gint          i;
+
+  treeview = (GtkTreeView*)
+    gtk_builder_get_object (pp->builder, "device-types-treeview");
+
+  store = gtk_list_store_new (DEVICE_TYPE_N_COLUMNS,
+                              G_TYPE_INT,
+                              G_TYPE_STRING,
+                              G_TYPE_INT);
+
+  pp->device_connection_types = g_new (gchar*, 2);
+  pp->num_device_connection_types = 2;
+
+  /* Translators: Local means local printers */
+  pp->device_connection_types[0] = g_strdup (_("Local"));
+  /* Translators: Network means network printers */
+  pp->device_connection_types[1] = g_strdup (_("Network"));
+
+  for (i = 0; i < pp->num_device_connection_types; i++)
+    {
+      gtk_list_store_append (store, &iter);
+      gtk_list_store_set (store, &iter,
+                          DEVICE_TYPE_ID_COLUMN, i,
+                          DEVICE_TYPE_NAME_COLUMN, pp->device_connection_types[i],
+                          DEVICE_TYPE_TYPE_COLUMN, i,
+                          -1);
+    }
+
+  gtk_tree_view_set_model (treeview, GTK_TREE_MODEL (store));
+
+  gtk_tree_model_get_iter_first ((GtkTreeModel *) store,
+                                 &iter);
+
+  gtk_tree_selection_select_iter (
+    gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
+    &iter);
+
+  g_object_unref (store);
+}
+
+static void
+populate_device_types_list (PpNewPrinterDialog *pp)
+{
+  GtkTreeViewColumn *column;
+  GtkCellRenderer   *renderer;
+  GtkWidget         *treeview;
+
+  treeview = (GtkWidget*)
+    gtk_builder_get_object (pp->builder, "device-types-treeview");
+
+  actualize_device_types_list (pp);
+
+  g_signal_connect (gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)),
+                    "changed", G_CALLBACK (device_type_selection_changed_cb), pp);
+
+  renderer = gtk_cell_renderer_text_new ();
+  /* Translators: Device types column (network or local) */
+  column = gtk_tree_view_column_new_with_attributes (_("Device types"), renderer,
+                                                     "text", DEVICE_TYPE_NAME_COLUMN, NULL);
+  gtk_tree_view_append_column (GTK_TREE_VIEW (treeview), column);
+}
+
+static void
+dialog_closed (GtkWidget          *dialog,
+               gint                response_id,
+               PpNewPrinterDialog *pp)
+{
+  gtk_widget_destroy (dialog);
+}
+
+static void
+new_printer_add_button_cb (GtkButton *button,
+                           gpointer   user_data)
+{
+  PpNewPrinterDialog *pp = (PpNewPrinterDialog*) user_data;
+  GtkResponseType     dialog_response = GTK_RESPONSE_OK;
+  GtkTreeModel       *model;
+  GtkTreeIter         iter;
+  GtkWidget          *treeview;
+  gchar              *device_name = NULL;
+  gchar              *ppd_name = NULL;
+  gint                device_id = -1;
+  gint                device_type = -1;
+
+  treeview = (GtkWidget*)
+    gtk_builder_get_object (pp->builder, "device-types-treeview");
+
+  if (gtk_tree_selection_get_selected (
+        gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)), &model, &iter))
+    gtk_tree_model_get (model, &iter,
+                        DEVICE_TYPE_TYPE_COLUMN, &device_type,
+                        -1);
+
+  switch (device_type)
+    {
+      case DEVICE_TYPE_LOCAL:
+        treeview = (GtkWidget*)
+          gtk_builder_get_object (pp->builder, "local-devices-treeview");
+        break;
+      case DEVICE_TYPE_NETWORK:
+        treeview = (GtkWidget*)
+          gtk_builder_get_object (pp->builder, "network-devices-treeview");
+        break;
+      default:
+        treeview = NULL;
+        break;
+    }
+
+  if (treeview &&
+      gtk_tree_selection_get_selected (
+        gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)), &model, &iter))
+    {
+      gtk_tree_model_get (model, &iter,
+			  DEVICE_ID_COLUMN, &device_id,
+			  DEVICE_NAME_COLUMN, &device_name,
+			  -1);
+    }
+
+  if (device_id >= 0)
+    {
+      if (pp->devices[device_id].device_ppd_uri)
+        {
+          http_t *http;
+
+          http = httpConnectEncrypt (pp->devices[device_id].hostname,
+                                     pp->devices[device_id].host_port,
+                                     cupsEncryption ());
+
+          if (http)
+            {
+              const char *ppd_file_name;
+
+              ppd_file_name = cupsGetPPD2 (http, pp->devices[device_id].display_name);
+
+              if (ppd_file_name)
+                {
+                  DBusGProxy *proxy;
+                  GError     *error = NULL;
+                  char       *ret_error = NULL;
+
+                  proxy = get_dbus_proxy (MECHANISM_BUS,
+                                          "/",
+                                          MECHANISM_BUS,
+                                          TRUE);
+                  if (proxy)
+                    {
+                      dbus_g_proxy_call (proxy, "PrinterAddWithPpdFile", &error,
+                                         G_TYPE_STRING, pp->devices[device_id].display_name,
+                                         G_TYPE_STRING, pp->devices[device_id].device_uri,
+                                         G_TYPE_STRING, ppd_file_name,
+                                         G_TYPE_STRING, pp->devices[device_id].device_info,
+                                         G_TYPE_STRING, pp->devices[device_id].device_location,
+                                         G_TYPE_INVALID,
+                                         G_TYPE_STRING, &ret_error,
+                                         G_TYPE_INVALID);
+
+                      if (error || (ret_error && ret_error[0] != '\0'))
+                        {
+                          dialog_response = GTK_RESPONSE_REJECT;
+
+                          if (error)
+                            g_warning ("%s", error->message);
+
+                          if (ret_error && ret_error[0] != '\0')
+                            g_warning ("%s", ret_error);
+
+                          g_clear_error (&error);
+                        }
+                      else
+                        {
+                          ret_error = NULL;
+
+                          dbus_g_proxy_call (proxy, "PrinterSetAcceptJobs", &error,
+                                             G_TYPE_STRING, pp->devices[device_id].display_name,
+                                             G_TYPE_BOOLEAN, TRUE,
+                                             G_TYPE_STRING, "none",
+                                             G_TYPE_INVALID,
+                                             G_TYPE_STRING, &ret_error,
+                                             G_TYPE_INVALID);
+
+                          dbus_g_proxy_call (proxy, "PrinterSetEnabled", &error,
+                                             G_TYPE_STRING, pp->devices[device_id].display_name,
+                                             G_TYPE_BOOLEAN, TRUE,
+                                             G_TYPE_INVALID,
+                                             G_TYPE_STRING, &ret_error,
+                                             G_TYPE_INVALID);
+
+                          if (error || (ret_error && ret_error[0] != '\0'))
+                            {
+                              if (error)
+                                g_warning ("%s", error->message);
+
+                              if (ret_error && ret_error[0] != '\0')
+                                g_warning ("%s", ret_error);
+
+                              g_clear_error (&error);
+                            }
+                          else
+                            {
+                              if (g_strcmp0 (pp->devices[device_id].device_class, "direct") == 0)
+                                {
+                                  gchar *commands = get_dest_attr (pp->devices[device_id].display_name, "printer-commands");
+                                  gchar *commands_lowercase = g_ascii_strdown (commands, -1);
+                                  ipp_t *response = NULL;
+
+                                  if (g_strrstr (commands_lowercase, "AutoConfigure"))
+                                    {
+                                      response = execute_maintenance_command (pp->devices[device_id].display_name,
+                                                                              "AutoConfigure",
+                                      /* Translators: Name of job which makes printer to autoconfigure itself */
+                                                                              _("Automatic configuration"));
+                                      if (response)
+                                        {
+                                          if (response->state == IPP_ERROR)
+                                          /* Translators: An error has occured during execution of AutoConfigure CUPS maintenance command */
+                                            g_warning ("An error has occured during automatic configuration of new printer.");
+                                          ippDelete (response);
+                                        }
+                                    }
+                                  g_free (commands);
+                                  g_free (commands_lowercase);
+                                }
+                            }
+                        }
+                      g_object_unref (proxy);
+                    }
+
+                  g_unlink (ppd_file_name);
+                }
+              else
+                {
+                  dialog_response = GTK_RESPONSE_REJECT;
+                  g_warning ("Getting of PPD for %s from %s:%d failed.",
+                             pp->devices[device_id].display_name,
+                             pp->devices[device_id].hostname,
+                             pp->devices[device_id].host_port);
+                }
+            }
+        }
+      else if (pp->devices[device_id].device_id)
+        {
+          /* Try whether CUPS has a driver for the new printer */
+          ppd_name = get_ppd_name (pp->devices[device_id].device_class,
+                           pp->devices[device_id].device_id,
+                           pp->devices[device_id].device_info,
+                           pp->devices[device_id].device_make_and_model,
+                           pp->devices[device_id].device_uri,
+                           pp->devices[device_id].device_location);
+
+          if (ppd_name == NULL)
+            {
+              /* Try PackageKit to install printer driver */
+              DBusGProxy *proxy;
+              GError     *error = NULL;
+
+              proxy = get_dbus_proxy (PACKAGE_KIT_BUS,
+                                      PACKAGE_KIT_PATH,
+                                      PACKAGE_KIT_IFACE,
+                                      FALSE);
+
+              if (proxy)
+                {
+                  gchar **device_ids = NULL;
+
+                  device_ids = g_new (gchar *, 2);
+                  device_ids[0] = pp->devices[device_id].device_id;
+                  device_ids[1] = NULL;
+
+                  dbus_g_proxy_call (proxy, "InstallPrinterDrivers", &error,
+
+#ifdef GDK_WINDOWING_X11
+                                     G_TYPE_UINT, GDK_WINDOW_XID (gtk_widget_get_window (GTK_WIDGET (pp->dialog))),
+#else
+                                     G_TYPE_UINT, 0,
+#endif
+                                     G_TYPE_STRV, device_ids,
+                                     G_TYPE_STRING, "hide-finished",
+                                     G_TYPE_INVALID,
+                                     G_TYPE_INVALID);
+
+                  g_object_unref (proxy);
+
+                  if (error)
+                    g_warning ("%s", error->message);
+
+                  g_clear_error (&error);
+
+                  /* Search CUPS for driver */
+                  ppd_name = get_ppd_name (pp->devices[device_id].device_class,
+                               pp->devices[device_id].device_id,
+                               pp->devices[device_id].device_info,
+                               pp->devices[device_id].device_make_and_model,
+                               pp->devices[device_id].device_uri,
+                               pp->devices[device_id].device_location);
+
+                  g_free (device_ids);
+                }
+            }
+
+          /* Add the new printer */
+          if (ppd_name)
+            {
+              DBusGProxy *proxy;
+              GError     *error = NULL;
+              char       *ret_error = NULL;
+
+              proxy = get_dbus_proxy (MECHANISM_BUS,
+                                      "/",
+                                      MECHANISM_BUS,
+                                      TRUE);
+              if (proxy)
+                {
+                  dbus_g_proxy_call (proxy, "PrinterAdd", &error,
+                                     G_TYPE_STRING, pp->devices[device_id].display_name,
+                                     G_TYPE_STRING, pp->devices[device_id].device_uri,
+                                     G_TYPE_STRING, ppd_name,
+                                     G_TYPE_STRING, pp->devices[device_id].device_info,
+                                     G_TYPE_STRING, pp->devices[device_id].device_location,
+                                     G_TYPE_INVALID,
+                                     G_TYPE_STRING, &ret_error,
+                                     G_TYPE_INVALID);
+
+                  if (error || (ret_error && ret_error[0] != '\0'))
+                    {
+                      dialog_response = GTK_RESPONSE_REJECT;
+
+                      if (error)
+                        g_warning ("%s", error->message);
+
+                      if (ret_error && ret_error[0] != '\0')
+                        g_warning ("%s", ret_error);
+
+                      g_clear_error (&error);
+                    }
+                  else
+                    {
+                      ret_error = NULL;
+
+                      dbus_g_proxy_call (proxy, "PrinterSetAcceptJobs", &error,
+                                         G_TYPE_STRING, pp->devices[device_id].display_name,
+                                         G_TYPE_BOOLEAN, TRUE,
+                                         G_TYPE_STRING, "none",
+                                         G_TYPE_INVALID,
+                                         G_TYPE_STRING, &ret_error,
+                                         G_TYPE_INVALID);
+
+                      dbus_g_proxy_call (proxy, "PrinterSetEnabled", &error,
+                                         G_TYPE_STRING, pp->devices[device_id].display_name,
+                                         G_TYPE_BOOLEAN, TRUE,
+                                         G_TYPE_INVALID,
+                                         G_TYPE_STRING, &ret_error,
+                                         G_TYPE_INVALID);
+
+                      if (error || (ret_error && ret_error[0] != '\0'))
+                        {
+                          if (error)
+                            g_warning ("%s", error->message);
+
+                          if (ret_error && ret_error[0] != '\0')
+                            g_warning ("%s", ret_error);
+
+                          g_clear_error (&error);
+                        }
+                      else
+                        {
+                          if (g_strcmp0 (pp->devices[device_id].device_class, "direct") == 0)
+                            {
+                              gchar *commands = get_dest_attr (pp->devices[device_id].display_name, "printer-commands");
+                              gchar *commands_lowercase = g_ascii_strdown (commands, -1);
+                              ipp_t *response = NULL;
+
+                              if (g_strrstr (commands_lowercase, "AutoConfigure"))
+                                {
+                                  response = execute_maintenance_command (pp->devices[device_id].display_name,
+                                                                          "AutoConfigure",
+                                  /* Translators: Name of job which makes printer to autoconfigure itself */
+                                                                          _("Automatic configuration"));
+                                  if (response)
+                                    {
+                                      if (response->state == IPP_ERROR)
+                                      /* Translators: An error has occured during execution of AutoConfigure CUPS maintenance command */
+                                        g_warning ("An error has occured during automatic configuration of new printer.");
+                                      ippDelete (response);
+                                    }
+                                }
+                              g_free (commands);
+                              g_free (commands_lowercase);
+                            }
+                        }
+                    }
+                  g_object_unref (proxy);
+                }
+            }
+        }
+    }
+
+  pp_new_printer_dialog_hide (pp);
+  pp->user_callback (GTK_DIALOG (pp->dialog), dialog_response, pp->user_data);
+}
+
+static void
+new_printer_cancel_button_cb (GtkButton *button,
+                              gpointer   user_data)
+{
+  PpNewPrinterDialog *pp = (PpNewPrinterDialog*) user_data;
+
+  pp_new_printer_dialog_hide (pp);
+  pp->user_callback (GTK_DIALOG (pp->dialog), GTK_RESPONSE_CANCEL, pp->user_data);
+}
+
+PpNewPrinterDialog *
+pp_new_printer_dialog_new (GtkWindow            *parent,
+                           UserResponseCallback  user_callback,
+                           gpointer              user_data)
+{
+  PpNewPrinterDialog *pp;
+  GtkWidget          *widget;
+  GError             *error = NULL;
+  gchar              *objects[] = { "dialog", "main-vbox", NULL };
+
+  pp = g_new0 (PpNewPrinterDialog, 1);
+
+  pp->builder = gtk_builder_new ();
+  pp->parent = GTK_WIDGET (parent);
+
+  gtk_builder_add_objects_from_file (pp->builder,
+                                     DATADIR"/new-printer-dialog.ui",
+                                     objects, &error);
+
+  if (error)
+    {
+      g_warning ("Could not load ui: %s", error->message);
+      g_error_free (error);
+      return NULL;
+    }
+
+  pp->device_connection_types = NULL;
+  pp->num_device_connection_types = 0;
+
+  pp->devices = NULL;
+  pp->num_devices = 0;
+
+  pp->dialog = (GtkWidget *) gtk_builder_get_object (pp->builder, "dialog");
+
+  pp->user_callback = user_callback;
+  pp->user_data = user_data;
+
+  /* connect signals */
+  g_signal_connect (pp->dialog, "delete-event", G_CALLBACK (gtk_widget_hide_on_delete), NULL);
+
+  widget = (GtkWidget*)
+    gtk_builder_get_object (pp->builder, "new-printer-add-button");
+  g_signal_connect (widget, "clicked", G_CALLBACK (new_printer_add_button_cb), pp);
+
+  widget = (GtkWidget*)
+    gtk_builder_get_object (pp->builder, "new-printer-cancel-button");
+  g_signal_connect (widget, "clicked", G_CALLBACK (new_printer_cancel_button_cb), pp);
+
+  widget = (GtkWidget*)
+    gtk_builder_get_object (pp->builder, "search-by-address-checkbutton");
+  g_signal_connect (widget, "toggled", G_CALLBACK (search_address_cb), pp);
+
+  gtk_window_set_transient_for (GTK_WINDOW (pp->dialog), GTK_WINDOW (parent));
+  gtk_window_set_modal (GTK_WINDOW (pp->dialog), TRUE);
+  gtk_window_present (GTK_WINDOW (pp->dialog));
+  gtk_widget_show_all (GTK_WIDGET (pp->dialog));
+
+  populate_device_types_list (pp);
+  populate_devices_list (pp);
+
+  return pp;
+}
+
+void
+pp_new_printer_dialog_free (PpNewPrinterDialog *pp)
+{
+  gint i;
+
+  for (i = 0; i < pp->num_device_connection_types; i++)
+    g_free (pp->device_connection_types[i]);
+  g_free (pp->device_connection_types);
+  pp->device_connection_types = NULL;
+
+  free_devices (pp);
+
+  gtk_widget_destroy (GTK_WIDGET (pp->dialog));
+  pp->dialog = NULL;
+
+  g_object_unref (pp->builder);
+  pp->builder = NULL;
+
+  g_free (pp);
+}
+
+static void
+pp_new_printer_dialog_hide (PpNewPrinterDialog *pp)
+{
+  gtk_widget_hide (GTK_WIDGET (pp->dialog));
+}
diff --git a/panels/printers/pp-new-printer-dialog.h b/panels/printers/pp-new-printer-dialog.h
new file mode 100644
index 0000000..618c0d7
--- /dev/null
+++ b/panels/printers/pp-new-printer-dialog.h
@@ -0,0 +1,39 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright 2009-2010  Red Hat, Inc,
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef __PP_NEW_PRINTER_DIALOG_H__
+#define __PP_NEW_PRINTER_DIALOG_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+typedef struct _PpNewPrinterDialog PpNewPrinterDialog;
+
+typedef void (*UserResponseCallback) (GtkDialog *dialog, gint response_id, gpointer user_data);
+
+PpNewPrinterDialog *pp_new_printer_dialog_new  (GtkWindow            *parent,
+                                                UserResponseCallback  user_callback,
+                                                gpointer              user_data);
+void                pp_new_printer_dialog_free (PpNewPrinterDialog   *dialog);
+
+G_END_DECLS
+
+#endif
diff --git a/panels/printers/pp-utils.c b/panels/printers/pp-utils.c
new file mode 100644
index 0000000..39a1416
--- /dev/null
+++ b/panels/printers/pp-utils.c
@@ -0,0 +1,385 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright 2009-2010  Red Hat, Inc,
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#include "config.h"
+
+#include <glib.h>
+#include <glib/gi18n.h>
+#include <glib/gstdio.h>
+#include <gtk/gtk.h>
+#include <cups/cups.h>
+#include <dbus/dbus-glib.h>
+
+#include "pp-utils.h"
+
+DBusGProxy *
+get_dbus_proxy (const gchar *name,
+                const gchar *path,
+                const gchar *iface,
+                const gboolean system_bus)
+{
+  DBusGConnection *bus;
+  DBusGProxy      *proxy;
+  GError          *error;
+
+  error = NULL;
+  if (system_bus)
+    bus = dbus_g_bus_get (DBUS_BUS_SYSTEM, &error);
+  else
+    bus = dbus_g_bus_get (DBUS_BUS_SESSION, &error);
+
+  if (bus == NULL)
+    {
+      if (system_bus)
+        /* Translators: Program cannot connect to DBus' system bus */
+        g_warning ("Could not connect to system bus: %s", error->message);
+      else
+        /* Translators: Program cannot connect to DBus' session bus */
+        g_warning ("Could not connect to session bus: %s", error->message);
+      g_error_free (error);
+      return NULL;
+    }
+
+  error = NULL;
+
+  proxy = dbus_g_proxy_new_for_name (bus, name, path, iface);
+
+  return proxy;
+}
+
+gchar *get_tag_value (const gchar *tag_string, const gchar *tag_name)
+{
+  gchar **tag_string_splitted = NULL;
+  gchar  *tag_value = NULL;
+  gint    tag_name_length = strlen (tag_name);
+  gint    i;
+
+  tag_string_splitted = g_strsplit (tag_string, ";", 0);
+  for (i = 0; i < g_strv_length (tag_string_splitted); i++)
+    if (g_ascii_strncasecmp (tag_string_splitted[i], tag_name, tag_name_length) == 0)
+      if (strlen (tag_string_splitted[i]) > tag_name_length + 1)
+        tag_value = g_strdup (tag_string_splitted[i] + tag_name_length + 1);
+  g_strfreev (tag_string_splitted);
+
+  return tag_value;
+}
+
+gchar *
+get_ppd_name (gchar *device_class,
+              gchar *device_id,
+              gchar *device_info,
+              gchar *device_make_and_model,
+              gchar *device_uri,
+              gchar *device_location)
+{
+  http_t *http = NULL;
+  ipp_t  *request = NULL;
+  ipp_t  *response = NULL;
+  gchar  *mfg = NULL;
+  gchar  *mdl = NULL;
+  gchar  *result = NULL;
+
+  mfg = get_tag_value (device_id, "mfg");
+  mdl = get_tag_value (device_id, "mdl");
+
+  http = httpConnectEncrypt (cupsServer (),
+                             ippPort (),
+                             cupsEncryption ());
+
+  if (http)
+    {
+      request = ippNewRequest (CUPS_GET_PPDS);
+      if (device_id)
+        ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT, "ppd-device-id",
+                     NULL, device_id);
+      else if (mfg)
+        ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_TEXT, "ppd-make",
+                     NULL, mfg);
+      response = cupsDoRequest (http, request, "/");
+
+      if (response)
+        {
+          ipp_attribute_t *attr = NULL;
+          const char      *ppd_device_id;
+          const char      *ppd_make_model;
+          const char      *ppd_make;
+          const char      *ppd_name;
+          gchar           *ppd_mfg;
+          gchar           *ppd_mdl;
+
+          for (attr = response->attrs; attr != NULL; attr = attr->next)
+            {
+              while (attr != NULL && attr->group_tag != IPP_TAG_PRINTER)
+                attr = attr->next;
+
+              if (attr == NULL)
+                break;
+
+              ppd_device_id  = "NONE";
+              ppd_make_model = NULL;
+              ppd_make       = NULL;
+              ppd_name       = NULL;
+              ppd_mfg        = NULL;
+              ppd_mdl        = NULL;
+
+              while (attr != NULL && attr->group_tag == IPP_TAG_PRINTER)
+                {
+                  if (!strcmp(attr->name, "ppd-device-id") &&
+                      attr->value_tag == IPP_TAG_TEXT)
+                    ppd_device_id = attr->values[0].string.text;
+                  else if (!strcmp(attr->name, "ppd-name") &&
+                           attr->value_tag == IPP_TAG_NAME)
+                    ppd_name = attr->values[0].string.text;
+                  else if (!strcmp(attr->name, "ppd-make") &&
+                           attr->value_tag == IPP_TAG_TEXT)
+                    ppd_make = attr->values[0].string.text;
+                  else if (!strcmp(attr->name, "ppd-make-and-model") &&
+                           attr->value_tag == IPP_TAG_TEXT)
+                    ppd_make_model = attr->values[0].string.text;
+
+                  attr = attr->next;
+                }
+
+              if (mfg && mdl && !result)
+                {
+                  if (ppd_device_id)
+                    {
+                      ppd_mfg = get_tag_value (ppd_device_id, "mfg");
+
+                      if (ppd_mfg && g_ascii_strcasecmp (ppd_mfg, mfg) == 0)
+                        {
+                          ppd_mdl = get_tag_value (ppd_device_id, "mdl");
+
+                          if (ppd_mdl && g_ascii_strcasecmp (ppd_mdl, mdl) == 0)
+                            {
+                              result = g_strdup (ppd_name);
+                              g_free (ppd_mdl);
+                            }
+                          g_free (ppd_mfg);
+                        }
+                    }
+                }
+
+              if (attr == NULL)
+                break;
+            }
+          ippDelete(response);
+        }
+      httpClose (http);
+    }
+
+  g_free (mfg);
+  g_free (mdl);
+
+  return result;
+}
+
+char *
+get_dest_attr (const char *dest_name,
+               const char *attr)
+{
+  cups_dest_t *dests;
+  int          num_dests;
+  cups_dest_t *dest;
+  const char  *value;
+  char        *ret;
+
+  if (dest_name == NULL)
+          return NULL;
+
+  ret = NULL;
+
+  num_dests = cupsGetDests (&dests);
+  if (num_dests < 1) {
+          g_debug ("Unable to get printer destinations");
+          return NULL;
+  }
+
+  dest = cupsGetDest (dest_name, NULL, num_dests, dests);
+  if (dest == NULL) {
+          g_debug ("Unable to find a printer named '%s'", dest_name);
+          goto out;
+  }
+
+  value = cupsGetOption (attr, dest->num_options, dest->options);
+  if (value == NULL) {
+          g_debug ("Unable to get %s for '%s'", attr, dest_name);
+          goto out;
+  }
+  ret = g_strdup (value);
+out:
+  cupsFreeDests (num_dests, dests);
+
+  return ret;
+}
+
+ipp_t *
+execute_maintenance_command (const char *printer_name,
+                             const char *command,
+                             const char *title)
+{
+  http_t *http;
+  GError *error = NULL;
+  ipp_t  *request = NULL;
+  ipp_t  *response = NULL;
+  char    uri[HTTP_MAX_URI + 1];
+  int     fd = -1;
+
+  http = httpConnectEncrypt (cupsServer (),
+                             ippPort (),
+                             cupsEncryption ());
+
+  if (http)
+    {
+      request = ippNewRequest (IPP_PRINT_JOB);
+
+      g_snprintf (uri,
+                  sizeof (uri),
+                  "ipp://localhost/printers/%s",
+                  printer_name);
+
+      ippAddString (request,
+                    IPP_TAG_OPERATION,
+                    IPP_TAG_URI,
+                    "printer-uri",
+                    NULL,
+                    uri);
+
+      ippAddString (request, IPP_TAG_OPERATION, IPP_TAG_NAME, "job-name",
+                    NULL, title);
+
+      ippAddString (request, IPP_TAG_JOB, IPP_TAG_MIMETYPE, "document-format",
+                    NULL, "application/vnd.cups-command");
+
+      gchar *file_name = NULL;
+      fd = g_file_open_tmp ("ccXXXXXX", &file_name, &error);
+
+      if (fd != -1 && !error)
+        {
+          FILE *file;
+
+          file = fdopen (fd, "w");
+          fprintf (file, "#CUPS-COMMAND\n");
+          fprintf (file, "%s\n", command);
+          fclose (file);
+
+          response = cupsDoFileRequest (http, request, "/", file_name);
+          g_unlink (file_name);
+        }
+
+      g_free (file_name);
+      httpClose (http);
+    }
+
+  return response;
+}
+
+int
+ccGetAllowedUsers (gchar ***allowed_users, const char *printer_name)
+{
+  const char * const   attrs[1] = { "requesting-user-name-allowed" };
+  http_t              *http;
+  ipp_t               *request = NULL;
+  gchar              **users = NULL;
+  ipp_t               *response;
+  char                 uri[HTTP_MAX_URI + 1];
+  int                  num_allowed_users = 0;
+
+  http = httpConnectEncrypt (cupsServer (),
+                             ippPort (),
+                             cupsEncryption ());
+
+  if (http || !allowed_users)
+    {
+      request = ippNewRequest (IPP_GET_PRINTER_ATTRIBUTES);
+
+      g_snprintf (uri, sizeof (uri), "ipp://localhost/printers/%s", printer_name);
+      ippAddString (request,
+                    IPP_TAG_OPERATION,
+                    IPP_TAG_URI,
+                    "printer-uri",
+                    NULL,
+                    uri);
+      ippAddStrings (request,
+                     IPP_TAG_OPERATION,
+                     IPP_TAG_KEYWORD,
+                     "requested-attributes",
+                     1,
+                     NULL,
+                     attrs);
+
+      response = cupsDoRequest (http, request, "/");
+      if (response)
+        {
+          ipp_attribute_t *attr = NULL;
+          ipp_attribute_t *allowed = NULL;
+
+          for (attr = response->attrs; attr != NULL; attr = attr->next)
+            {
+              if (attr->group_tag == IPP_TAG_PRINTER &&
+                  attr->value_tag == IPP_TAG_NAME &&
+                  !g_strcmp0 (attr->name, "requesting-user-name-allowed"))
+                allowed = attr;
+            }
+
+          if (allowed && allowed->num_values > 0)
+            {
+              int i;
+
+              num_allowed_users = allowed->num_values;
+              users = g_new (gchar*, num_allowed_users);
+
+              for (i = 0; i < num_allowed_users; i ++)
+                users[i] = g_strdup (allowed->values[i].string.text);
+            }
+          ippDelete(response);
+        }
+       httpClose (http);
+     }
+
+  *allowed_users = users;
+  return num_allowed_users;
+}
+
+gchar *
+get_ppd_attribute (const gchar *printer_name, const gchar *attribute_name)
+{
+  const char *file_name = NULL;
+  ppd_file_t *ppd_file = NULL;
+  ppd_attr_t *ppd_attr = NULL;
+  gchar *result = NULL;
+
+  file_name = cupsGetPPD (printer_name);
+
+  if (file_name)
+    {
+      ppd_file = ppdOpenFile (file_name);
+      if (ppd_file)
+        {
+          ppd_attr = ppdFindAttr (ppd_file, attribute_name, NULL);
+          if (ppd_attr != NULL)
+            result = g_strdup (ppd_attr->value);
+          ppdClose (ppd_file);
+        }
+      g_unlink (file_name);
+    }
+
+  return result;
+}
diff --git a/panels/printers/pp-utils.h b/panels/printers/pp-utils.h
new file mode 100644
index 0000000..e314f5b
--- /dev/null
+++ b/panels/printers/pp-utils.h
@@ -0,0 +1,59 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
+ *
+ * Copyright 2009-2010  Red Hat, Inc,
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+#ifndef __PP_UTILS_H__
+#define __PP_UTILS_H__
+
+#include <gtk/gtk.h>
+#include <dbus/dbus-glib.h>
+
+G_BEGIN_DECLS
+
+DBusGProxy *get_dbus_proxy (const gchar *name,
+                            const gchar *path,
+                            const gchar *iface,
+                            const gboolean system_bus);
+
+gchar      *get_tag_value (const gchar *tag_string,
+                           const gchar *tag_name);
+
+gchar      *get_ppd_name (gchar *device_class,
+                          gchar *device_id,
+                          gchar *device_info,
+                          gchar *device_make_and_model,
+                          gchar *device_uri,
+                          gchar *device_location);
+
+char       *get_dest_attr (const char *dest_name,
+                           const char *attr);
+
+ipp_t      *execute_maintenance_command (const char *printer_name,
+                                         const char *command,
+                                         const char *title);
+
+int         ccGetAllowedUsers (gchar      ***allowed_users,
+                               const char   *printer_name);
+
+gchar      *get_ppd_attribute (const gchar *printer_name,
+                               const gchar *attribute_name);
+
+G_END_DECLS
+
+#endif /* __PP_UTILS_H */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]