root/usr/src/lib/print/libpapi-ipp/common/printer.c
/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 *
 */

/* $Id: printer.c 146 2006-03-24 00:26:54Z njacobs $ */

/*LINTLIBRARY*/

#include <stdlib.h>
#include <papi_impl.h>

#include <config-site.h>

void
papiPrinterFree(papi_printer_t printer)
{
        printer_t *tmp = printer;

        if (tmp != NULL) {
                if (tmp->attributes != NULL)
                        papiAttributeListFree(tmp->attributes);
                free(tmp);
        }
}

void
papiPrinterListFree(papi_printer_t *printers)
{
        if (printers != NULL) {
                int i;

                for (i = 0; printers[i] != NULL; i++)
                        papiPrinterFree(printers[i]);
                free(printers);
        }
}

/*
 * Enumeration of printers is not part of the IPP specification, so many
 * servers will probably not respond back with a list of printers, but
 * CUPS has implemented an extension to IPP to enumerate printers and
 * classes. the Apache/mod_ipp IPP listener module available in Solaris
 * implements this IPP extension, so CUPS and Solaris can provide this
 * to IPP clients.
 */
#ifndef OPID_CUPS_GET_PRINTERS          /* for servers that will enumerate */
#define OPID_CUPS_GET_PRINTERS          0x4002
#endif  /* OPID_CUPS_GET_PRINTERS */
#ifndef OPID_CUPS_DELETE_PRINTER        /* for servers that can delete */
#define OPID_CUPS_DELETE_PRINTER        0x4004
#endif  /* OPID_CUPS_DELETE_PRINTER */
#ifndef OPID_CUPS_GET_CLASSES           /* for servers that will enumerate */
#define OPID_CUPS_GET_CLASSES           0x4005
#endif  /* OPID_CUPS_GET_CLASSES */

papi_status_t
papiPrintersList(papi_service_t handle, char **requested_attrs,
                papi_filter_t *filter, papi_printer_t **printers)
{
        papi_status_t status, result = PAPI_INTERNAL_ERROR;
        service_t *svc = handle;
        papi_attribute_t **request = NULL, **op = NULL, **response = NULL;
        void *iter = NULL;

        if ((svc == NULL) || (printers == NULL))
                return (PAPI_BAD_ARGUMENT);

        /* if we are already connected, use that connection. */
        if (svc->connection == NULL)
                if ((result = service_connect(svc, DEFAULT_DEST)) != PAPI_OK)
                        return (result);
        ipp_initialize_request(svc, &request, OPID_CUPS_GET_PRINTERS);

        ipp_initialize_operational_attributes(svc, &op, NULL, -1);

        if (requested_attrs != NULL) {
                int i;

                for (i = 0; requested_attrs[i] != NULL; i++)
                        papiAttributeListAddString(&op, PAPI_ATTR_APPEND,
                                "requested-attributes", requested_attrs[i]);
        }

        papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
                        "operational-attributes-group", op);
        papiAttributeListFree(op);
        result = ipp_send_request(svc, request, &response);
        papiAttributeListFree(request);

        op = NULL;
        for (status = papiAttributeListGetCollection(response, &iter,
                                "printer-attributes-group", &op);
             status == PAPI_OK;
             status = papiAttributeListGetCollection(response, &iter,
                                NULL, &op)) {
                printer_t *p = NULL;

                if ((p = calloc(1, sizeof (*p))) == NULL)
                        return (PAPI_TEMPORARY_ERROR);

                copy_attributes(&p->attributes, op);
                op = NULL;
                list_append(printers, p);
        }
        papiAttributeListFree(response);

        return (result);
}

papi_status_t
papiPrinterQuery(papi_service_t handle, char *name,
                char **requested_attrs,
                papi_attribute_t **job_attributes,
                papi_printer_t *printer)
{
        papi_status_t result = PAPI_INTERNAL_ERROR;
        service_t *svc = handle;
        printer_t *p = NULL;
        papi_attribute_t **request = NULL, **op = NULL, **response = NULL;

        if ((svc == NULL) || (name == NULL) || (printer == NULL))
                return (PAPI_BAD_ARGUMENT);

        /* if we are already connected, use that connection. */
        if (svc->connection == NULL)
                if ((result = service_connect(svc, name)) != PAPI_OK)
                        return (result);

        if ((*printer = p = calloc(1, sizeof (*p))) == NULL)
                return (PAPI_TEMPORARY_ERROR);

        ipp_initialize_request(svc, &request, OPID_GET_PRINTER_ATTRIBUTES);

        ipp_initialize_operational_attributes(svc, &op, name, -1);

        if (requested_attrs != NULL) {
                int i;

                for (i = 0; requested_attrs[i] != NULL; i++)
                        papiAttributeListAddString(&op, PAPI_ATTR_APPEND,
                                "requested-attributes", requested_attrs[i]);
        }

        papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
                        "operational-attributes-group", op);
        papiAttributeListFree(op);
        result = ipp_send_request(svc, request, &response);
        papiAttributeListFree(request);

        op = NULL;
        papiAttributeListGetCollection(response, NULL,
                        "printer-attributes-group", &op);
        copy_attributes(&p->attributes, op);
        papiAttributeListFree(response);

        return (result);
}

static papi_status_t
_printer_enable_disable_pause_resume_delete(papi_service_t handle, char *name,
                char *message, uint16_t type)
{
        papi_status_t result = PAPI_INTERNAL_ERROR;
        service_t *svc = handle;
        papi_attribute_t **request = NULL, **op = NULL, **response = NULL;

        if ((svc == NULL) || (name == NULL))
                return (PAPI_BAD_ARGUMENT);

        /* if we are already connected, use that connection. */
        if (svc->connection == NULL)
                if ((result = service_connect(svc, name)) != PAPI_OK)
                        return (result);

        ipp_initialize_request(svc, &request, type);

        ipp_initialize_operational_attributes(svc, &op, name, -1);

        switch (type) {
        case OPID_DISABLE_PRINTER:
                papiAttributeListAddString(&op, PAPI_ATTR_REPLACE,
                                "printer-message-from-operator", message);
                break;
        case OPID_PAUSE_PRINTER:
                papiAttributeListAddString(&op, PAPI_ATTR_REPLACE,
                                "printer-state-message", message);
                break;
        default: /* a message value is of no use */
                break;
        }

        papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
                        "operational-attributes-group", op);
        papiAttributeListFree(op);
        result = ipp_send_request(svc, request, &response);
        papiAttributeListFree(request);
        papiAttributeListFree(response);

        return (result);
}

papi_status_t
papiPrinterEnable(papi_service_t handle, char *name)
{
        return (_printer_enable_disable_pause_resume_delete(handle, name,
                                NULL, OPID_ENABLE_PRINTER));
}

papi_status_t
papiPrinterResume(papi_service_t handle, char *name)
{
        return (_printer_enable_disable_pause_resume_delete(handle, name,
                                NULL, OPID_RESUME_PRINTER));
}

papi_status_t
papiPrinterPause(papi_service_t handle, char *name, char *message)
{
        return (_printer_enable_disable_pause_resume_delete(handle, name,
                                message, OPID_PAUSE_PRINTER));
}

papi_status_t
papiPrinterDisable(papi_service_t handle, char *name, char *message)
{
        return (_printer_enable_disable_pause_resume_delete(handle, name,
                                message, OPID_PAUSE_PRINTER));
}

/*
 * there is no IPP create operation, the set-printer-attibutes operation
 * is the closest we have, so we will assume that the server will create
 * a printer and set attributes if there is none.
 */
papi_status_t
papiPrinterAdd(papi_service_t handle, char *name,
                papi_attribute_t **attributes, papi_printer_t *printer)
{
        return (papiPrinterModify(handle, name, attributes, printer));
}

papi_status_t
papiPrinterModify(papi_service_t handle, char *name,
                papi_attribute_t **attributes, papi_printer_t *printer)
{
        papi_status_t result = PAPI_INTERNAL_ERROR;
        service_t *svc = handle;
        printer_t *p = NULL;
        papi_attribute_t **request = NULL, **op = NULL, **response = NULL;

        if ((svc == NULL) || (name == NULL) || (printer == NULL))
                return (PAPI_BAD_ARGUMENT);

        /* if we are already connected, use that connection. */
        if (svc->connection == NULL)
                if ((result = service_connect(svc, name)) != PAPI_OK)
                        return (result);

        if ((*printer = p = calloc(1, sizeof (*p))) == NULL)
                return (PAPI_TEMPORARY_ERROR);

        ipp_initialize_request(svc, &request, OPID_SET_PRINTER_ATTRIBUTES);

        ipp_initialize_operational_attributes(svc, &op, name, -1);

        papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
                        "operational-attributes-group", op);
        papiAttributeListFree(op);

        papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
                        "printer-attributes-group", attributes);
        result = ipp_send_request(svc, request, &response);
        papiAttributeListFree(request);

        op = NULL;
        papiAttributeListGetCollection(response, NULL,
                        "printer-attributes-group", &op);
        copy_attributes(&p->attributes, op);
        papiAttributeListFree(response);

        return (result);
}

papi_status_t
papiPrinterRemove(papi_service_t handle, char *name)
{
        return (_printer_enable_disable_pause_resume_delete(handle, name,
                                NULL, OPID_CUPS_DELETE_PRINTER));
}

papi_status_t
papiPrinterPurgeJobs(papi_service_t handle, char *name,
                papi_job_t **jobs)
{
        papi_status_t status, result = PAPI_INTERNAL_ERROR;
        service_t *svc = handle;
        papi_attribute_t **request = NULL, **op = NULL, **response = NULL;
        void *iter = NULL;


        if ((svc == NULL) || (name == NULL))
                return (PAPI_BAD_ARGUMENT);

        /* if we are already connected, use that connection. */
        if (svc->connection == NULL)
                if ((result = service_connect(svc, name)) != PAPI_OK)
                        return (result);

        ipp_initialize_request(svc, &request, OPID_PURGE_JOBS);

        ipp_initialize_operational_attributes(svc, &op, name, -1);

        papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
                        "operational-attributes-group", op);
        papiAttributeListFree(op);
        result = ipp_send_request(svc, request, &response);
        papiAttributeListFree(request);

        op = NULL;
        for (status = papiAttributeListGetCollection(response, &iter,
                                "job-attributes-group", &op);
             status == PAPI_OK;
             status = papiAttributeListGetCollection(response, &iter,
                                NULL, &op)) {
                job_t *j = NULL;

                if ((j = calloc(1, sizeof (*j))) == NULL)
                        return (PAPI_TEMPORARY_ERROR);

                copy_attributes(&j->attributes, op);
                op = NULL;
                list_append(jobs, j);
        }
        papiAttributeListFree(response);

        return (result);
}

papi_status_t
papiPrinterListJobs(papi_service_t handle, char *name,
                char **requested_attrs, int type_mask,
                int max_num_jobs, papi_job_t **jobs)
{
        papi_status_t status, result = PAPI_INTERNAL_ERROR;
        service_t *svc = handle;
        papi_attribute_t **request = NULL, **op = NULL, **response = NULL;
        void *iter = NULL;

        if ((svc == NULL) || (name == NULL))
                return (PAPI_BAD_ARGUMENT);

        /* if we are already connected, use that connection. */
        if (svc->connection == NULL)
                if ((result = service_connect(svc, name)) != PAPI_OK)
                        return (result);

        ipp_initialize_request(svc, &request, OPID_GET_JOBS);

        ipp_initialize_operational_attributes(svc, &op, name, -1);

        if (requested_attrs != NULL) {
                int i;

                for (i = 0; requested_attrs[i] != NULL; i++)
                        papiAttributeListAddString(&op, PAPI_ATTR_APPEND,
                                "requested-attributes", requested_attrs[i]);
        }

        papiAttributeListAddCollection(&request, PAPI_ATTR_REPLACE,
                        "operational-attributes-group", op);
        papiAttributeListFree(op);
        result = ipp_send_request(svc, request, &response);
        papiAttributeListFree(request);

        op = NULL;
        for (status = papiAttributeListGetCollection(response, &iter,
                                "job-attributes-group", &op);
             status == PAPI_OK;
             status = papiAttributeListGetCollection(response, &iter,
                                NULL, &op)) {
                job_t *j = NULL;

                if ((j = calloc(1, sizeof (*j))) == NULL)
                        return (PAPI_TEMPORARY_ERROR);

                copy_attributes(&j->attributes, op);
                op = NULL;
                list_append(jobs, j);
        }
        papiAttributeListFree(response);

        return (result);
}

papi_attribute_t **
papiPrinterGetAttributeList(papi_printer_t printer)
{
        papi_attribute_t **result = NULL;
        printer_t *p = printer;

        if (p != NULL)
                result = p->attributes;

        return (result);
}