1/*
2 * Copyright (C) 2016 The Android Open Source Project
3 * Copyright (C) 2016 Mopria Alliance, Inc.
4 * Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 *      http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18
19#include <stdint.h>
20#include <stdlib.h>
21#include <stdio.h>
22#include "lib_wprint.h"
23#include "ippstatus_capabilities.h"   // move these to above the calls to cups files
24#include "ipphelper.h"
25#include "cups.h"
26#include "http-private.h"
27#include "wprint_debug.h"
28
29#define TAG "ippstatus_capabilities"
30
31/*
32 * Requested printer attributes
33 */
34static const char *pattrs[] = {
35        "ipp-versions-supported",
36        "printer-make-and-model",
37        "printer-info",
38        "printer-dns-sd-name",
39        "printer-name",
40        "printer-location",
41        "printer-uuid",
42        "printer-uri-supported",
43        "uri-security-supported",
44        "uri-authentication-supported",
45        "color-supported",
46        "copies-supported",
47        "document-format-supported",
48        "media-col-default",
49        "media-default",
50        "media-left-margin-supported",
51        "media-right-margin-supported",
52        "media-top-margin-supported",
53        "media-bottom-margin-supported",
54        "media-supported",
55        "media-type-supported",
56        "output-bin-supported",
57        "print-color-mode-supported",
58        "printer-resolution-supported",
59        "sides-supported",
60        "printer-device-id",
61        "epcl-version-supported",
62        "pclm-raster-back-side",
63        "pclm-strip-height-preferred",
64        "pclm-compression-method-preferred",
65        "pclm-source-resolution-supported",
66        "document-format-details-supported"
67};
68
69static void _init(const ifc_printer_capabilities_t *this_p,
70        const wprint_connect_info_t *info);
71
72static status_t _get_capabilities(const ifc_printer_capabilities_t *this_p,
73        printer_capabilities_t *capabilities);
74
75static void _destroy(const ifc_printer_capabilities_t *this_p);
76
77static ifc_printer_capabilities_t _capabilities_ifc = {
78        .init = _init, .get_capabilities = _get_capabilities, .get_margins = NULL,
79        .destroy = _destroy,
80};
81
82typedef struct {
83    http_t *http;
84    printer_capabilities_t printer_caps;
85    ifc_printer_capabilities_t ifc;
86} ipp_capabilities_t;
87
88const ifc_printer_capabilities_t *ipp_status_get_capabilities_ifc(const ifc_wprint_t *wprint_ifc) {
89    LOGD("ipp_status_get_capabilities_ifc: Enter");
90    ipp_capabilities_t *caps = (ipp_capabilities_t *) malloc(sizeof(ipp_capabilities_t));
91    if (caps == NULL) {
92        return NULL;
93    }
94
95    memset(caps, 0, sizeof(ipp_capabilities_t));
96    caps->http = NULL;
97
98    memcpy(&caps->ifc, &_capabilities_ifc, sizeof(ifc_printer_capabilities_t));
99    return &caps->ifc;
100}
101
102static void _init(const ifc_printer_capabilities_t *this_p,
103        const wprint_connect_info_t *connect_info) {
104    LOGD("_init: Enter");
105    ipp_capabilities_t *caps;
106    do {
107        if (this_p == NULL) {
108            continue;
109        }
110        caps = IMPL(ipp_capabilities_t, ifc, this_p);
111
112        if (caps->http != NULL) {
113            LOGD("_init(): http != NULL closing HTTP");
114            httpClose(caps->http);
115        }
116
117        caps->http = ipp_cups_connect(connect_info, caps->printer_caps.printerUri,
118                sizeof(caps->printer_caps.printerUri));
119        getResourceFromURI(caps->printer_caps.printerUri, caps->printer_caps.httpResource, 1024);
120        if (caps->http == NULL) {
121            LOGE("_init(): http is NULL ");
122        }
123    } while (0);
124}
125
126static status_t _get_capabilities(const ifc_printer_capabilities_t *this_p,
127        printer_capabilities_t *capabilities) {
128    LOGD("_get_capabilities: Enter");
129    status_t result = ERROR;
130    ipp_capabilities_t *caps = NULL;
131    ipp_t *request = NULL; // IPP request object
132    ipp_t *response = NULL; // IPP response object
133    ipp_attribute_t *attrptr; // Attribute pointer
134    int op = IPP_GET_PRINTER_ATTRIBUTES;
135
136    ipp_status_t ipp_status; // Status of IPP request
137
138    if (capabilities != NULL) {
139        memset(capabilities, 0, sizeof(printer_capabilities_t));
140    }
141
142    do {
143        if (this_p == NULL) {
144            break;
145        }
146
147        caps = IMPL(ipp_capabilities_t, ifc, this_p);
148        if (caps->http == NULL) {
149            LOGD("_get_capabilities: caps->http is NULL");
150            break;
151        }
152
153        request = ippNewRequest(op);
154
155        ippAddString(request, IPP_TAG_OPERATION, IPP_TAG_URI, "printer-uri", NULL,
156                caps->printer_caps.printerUri);
157
158        ippAddStrings(request, IPP_TAG_OPERATION, IPP_TAG_KEYWORD, "requested-attributes",
159                sizeof(pattrs) / sizeof(pattrs[0]), NULL, pattrs);
160
161        LOGD("IPP_GET_PRINTER_ATTRIBUTES %s request:", ippOpString(op));
162        for (attrptr = ippFirstAttribute(request); attrptr; attrptr = ippNextAttribute(request)) {
163            print_attr(attrptr);
164        }
165
166        response = ipp_doCupsRequest(caps->http, request, caps->printer_caps.httpResource,
167                caps->printer_caps.printerUri);
168        if (response == NULL) {
169            ipp_status = cupsLastError();
170            LOGE("_get_capabilities: %s response is null:  ipp_status %d %s",
171                    caps->printer_caps.printerUri, ipp_status, ippErrorString(ipp_status));
172        } else {
173            ipp_status = cupsLastError();
174            LOGD("ipp CUPS last ERROR: %d, %s", ipp_status, ippErrorString(ipp_status));
175            LOGD("%s received, now call parse_printerAttributes:", ippOpString(op));
176            parse_printerAttributes(response, capabilities);
177
178#if LOG_LEVEL <= LEVEL_DEBUG
179            for (attrptr = ippFirstAttribute(response); attrptr; attrptr = ippNextAttribute(
180                    response)) {
181                print_attr(attrptr);
182            }
183#endif // LOG_LEVEL <= LEVEL_DEBUG
184            if ((attrptr = ippFindAttribute(response, "printer-state", IPP_TAG_ENUM)) == NULL) {
185                LOGD("printer-state: null");
186            } else {
187                LOGI("printer-state %d", (ipp_pstate_t) ippGetInteger(attrptr, 0));
188            }
189        }
190
191        if (ipp_status >= IPP_OK && ipp_status < IPP_REDIRECTION_OTHER_SITE && response != NULL) {
192            result = OK;
193        } else {
194            result = ERROR;
195        }
196    } while (0);
197
198    ippDelete(response);
199    ippDelete(request);
200
201    if ((caps != NULL) && (capabilities != NULL)) {
202        memcpy(capabilities->httpResource, caps->printer_caps.httpResource,
203                sizeof(capabilities->httpResource));
204    }
205
206    LOGI(" ippstatus_capabilities: _get_capabilities: returning %d:", result);
207    return result;
208}
209
210static void _destroy(const ifc_printer_capabilities_t *this_p) {
211    ipp_capabilities_t *caps;
212    LOGD("_destroy(): enter");
213    do {
214        if (this_p == NULL) {
215            continue;
216        }
217
218        caps = IMPL(ipp_capabilities_t, ifc, this_p);
219        if (caps->http != NULL) {
220            httpClose(caps->http);
221        }
222        free(caps);
223    } while (0);
224}