📄 gtkcupsutils.c
字号:
/* GTK - The GIMP Toolkit * gtkcupsutils.h: Statemachine implementation of POST and GET * cups calls which can be used to create a non-blocking cups API * Copyright (C) 2006, 2007 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */#include "config.h"#include "gtkcupsutils.h"#include "gtkdebug.h"#include <errno.h>#include <unistd.h>#include <sys/types.h>#include <sys/stat.h>#include <stdlib.h>#include <time.h>typedef void (*GtkCupsRequestStateFunc) (GtkCupsRequest *request);static void _connect (GtkCupsRequest *request);static void _post_send (GtkCupsRequest *request);static void _post_write_request (GtkCupsRequest *request);static void _post_write_data (GtkCupsRequest *request);static void _post_check (GtkCupsRequest *request);static void _post_read_response (GtkCupsRequest *request);static void _get_send (GtkCupsRequest *request);static void _get_check (GtkCupsRequest *request);static void _get_read_data (GtkCupsRequest *request);struct _GtkCupsResult{ gchar *error_msg; ipp_t *ipp_response; GtkCupsErrorType error_type; /* some error types like HTTP_ERROR have a status and a code */ int error_status; int error_code; guint is_error : 1; guint is_ipp_response : 1;};#define _GTK_CUPS_MAX_ATTEMPTS 10 #define _GTK_CUPS_MAX_CHUNK_SIZE 8192static GtkCupsRequestStateFunc post_states[] = { _connect, _post_send, _post_write_request, _post_write_data, _post_check, _post_read_response};static GtkCupsRequestStateFunc get_states[] = { _connect, _get_send, _get_check, _get_read_data};static voidgtk_cups_result_set_error (GtkCupsResult *result, GtkCupsErrorType error_type, int error_status, int error_code, const char *error_msg, ...){ va_list args; result->is_ipp_response = FALSE; result->is_error = TRUE; result->error_type = error_type; result->error_status = error_status; result->error_code = error_code; va_start (args, error_msg); result->error_msg = g_strdup_vprintf (error_msg, args); va_end (args);}GtkCupsRequest *gtk_cups_request_new (http_t *connection, GtkCupsRequestType req_type, gint operation_id, GIOChannel *data_io, const char *server, const char *resource){ GtkCupsRequest *request; cups_lang_t *language; request = g_new0 (GtkCupsRequest, 1); request->result = g_new0 (GtkCupsResult, 1); request->result->error_msg = NULL; request->result->ipp_response = NULL; request->result->is_error = FALSE; request->result->is_ipp_response = FALSE; request->type = req_type; request->state = GTK_CUPS_REQUEST_START; if (server) request->server = g_strdup (server); else request->server = g_strdup (cupsServer ()); if (resource) request->resource = g_strdup (resource); else request->resource = g_strdup ("/"); if (connection != NULL) { request->http = connection; request->own_http = FALSE; } else { request->http = NULL; request->http = httpConnectEncrypt (request->server, ippPort (), cupsEncryption ()); if (request->http) httpBlocking (request->http, 0); request->own_http = TRUE; } request->last_status = HTTP_CONTINUE; request->attempts = 0; request->data_io = data_io; request->ipp_request = ippNew (); request->ipp_request->request.op.operation_id = operation_id; request->ipp_request->request.op.request_id = 1; language = cupsLangDefault (); gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_CHARSET, "attributes-charset", NULL, "utf-8"); gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_LANGUAGE, "attributes-natural-language", NULL, language->language); gtk_cups_request_ipp_add_string (request, IPP_TAG_OPERATION, IPP_TAG_NAME, "requesting-user-name", NULL, cupsUser ()); cupsLangFree (language); return request;}static voidgtk_cups_result_free (GtkCupsResult *result){ g_free (result->error_msg); if (result->ipp_response) ippDelete (result->ipp_response); g_free (result);}voidgtk_cups_request_free (GtkCupsRequest *request){ if (request->own_http) { if (request->http) httpClose (request->http); } if (request->ipp_request) ippDelete (request->ipp_request); g_free (request->server); g_free (request->resource); gtk_cups_result_free (request->result); g_free (request);}gboolean gtk_cups_request_read_write (GtkCupsRequest *request){ if (request->type == GTK_CUPS_POST) post_states[request->state] (request); else if (request->type == GTK_CUPS_GET) get_states[request->state] (request); if (request->attempts > _GTK_CUPS_MAX_ATTEMPTS && request->state != GTK_CUPS_REQUEST_DONE) { /* TODO: should add a status or error code for too many failed attempts */ gtk_cups_result_set_error (request->result, GTK_CUPS_ERROR_GENERAL, 0, 0, "Too many failed attempts"); request->state = GTK_CUPS_REQUEST_DONE; request->poll_state = GTK_CUPS_HTTP_IDLE; } if (request->state == GTK_CUPS_REQUEST_DONE) { request->poll_state = GTK_CUPS_HTTP_IDLE; return TRUE; } else return FALSE;}GtkCupsPollState gtk_cups_request_get_poll_state (GtkCupsRequest *request){ return request->poll_state;}GtkCupsResult *gtk_cups_request_get_result (GtkCupsRequest *request){ return request->result;}void gtk_cups_request_ipp_add_string (GtkCupsRequest *request, ipp_tag_t group, ipp_tag_t tag, const char *name, const char *charset, const char *value){ ippAddString (request->ipp_request, group, tag, name, charset, value);}void gtk_cups_request_ipp_add_strings (GtkCupsRequest *request, ipp_tag_t group, ipp_tag_t tag, const char *name, int num_values, const char *charset, const char *const *values){ ippAddStrings (request->ipp_request, group, tag, name, num_values, charset, values);}typedef struct{ const char *name; ipp_tag_t value_tag;} ipp_option_t;static const ipp_option_t ipp_options[] = { { "blackplot", IPP_TAG_BOOLEAN }, { "brightness", IPP_TAG_INTEGER }, { "columns", IPP_TAG_INTEGER }, { "copies", IPP_TAG_INTEGER }, { "finishings", IPP_TAG_ENUM }, { "fitplot", IPP_TAG_BOOLEAN }, { "gamma", IPP_TAG_INTEGER }, { "hue", IPP_TAG_INTEGER }, { "job-k-limit", IPP_TAG_INTEGER }, { "job-page-limit", IPP_TAG_INTEGER }, { "job-priority", IPP_TAG_INTEGER }, { "job-quota-period", IPP_TAG_INTEGER }, { "landscape", IPP_TAG_BOOLEAN }, { "media", IPP_TAG_KEYWORD }, { "mirror", IPP_TAG_BOOLEAN }, { "natural-scaling", IPP_TAG_INTEGER }, { "number-up", IPP_TAG_INTEGER }, { "orientation-requested", IPP_TAG_ENUM }, { "page-bottom", IPP_TAG_INTEGER }, { "page-left", IPP_TAG_INTEGER }, { "page-ranges", IPP_TAG_RANGE }, { "page-right", IPP_TAG_INTEGER }, { "page-top", IPP_TAG_INTEGER }, { "penwidth", IPP_TAG_INTEGER }, { "ppi", IPP_TAG_INTEGER }, { "prettyprint", IPP_TAG_BOOLEAN }, { "printer-resolution", IPP_TAG_RESOLUTION }, { "print-quality", IPP_TAG_ENUM }, { "saturation", IPP_TAG_INTEGER }, { "scaling", IPP_TAG_INTEGER }, { "sides", IPP_TAG_KEYWORD }, { "wrap", IPP_TAG_BOOLEAN }};static ipp_tag_t_find_option_tag (const gchar *option){ int lower_bound, upper_bound, num_options; int current_option; ipp_tag_t result; result = IPP_TAG_ZERO; lower_bound = 0; upper_bound = num_options = (int) G_N_ELEMENTS (ipp_options) - 1; while (1) { int match; current_option = (int) (((upper_bound - lower_bound) / 2) + lower_bound); match = strcasecmp (option, ipp_options[current_option].name); if (match == 0) { result = ipp_options[current_option].value_tag; return result; } else if (match < 0) { upper_bound = current_option - 1; } else { lower_bound = current_option + 1; } if (upper_bound == lower_bound && upper_bound == current_option) return result; if (upper_bound < 0) return result; if (lower_bound > num_options) return result; if (upper_bound < lower_bound) return result; }}/* * Note that this function uses IPP_TAG_JOB, so it is * only suitable for IPP Group 2 attributes. * See RFC 2911. */voidgtk_cups_request_encode_option (GtkCupsRequest *request, const gchar *option, const gchar *value){ ipp_tag_t option_tag; g_return_if_fail (option != NULL); g_return_if_fail (value != NULL); option_tag = _find_option_tag (option); if (option_tag == IPP_TAG_ZERO) { option_tag = IPP_TAG_NAME;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -