diff options
author | thierry1970 <thierry@ordissimo.com> | 2020-02-06 17:22:55 +0100 |
---|---|---|
committer | thierry1970 <thierry@ordissimo.com> | 2020-02-06 17:22:55 +0100 |
commit | 9b4be30a8dddc54006550bcf84d18c473504d24e (patch) | |
tree | e97e1b672762764ea6f606763d3fdc6e89a65b19 /src | |
parent | 7cafed5a748a9cdd79de022514098f18dd7c1cf2 (diff) |
Txt recording for eSCL scanner.
Diffstat (limited to 'src')
-rw-r--r-- | src/capabilities.c | 235 | ||||
-rw-r--r-- | src/capabilities.h | 19 | ||||
-rw-r--r-- | src/dnssd.c | 53 |
3 files changed, 283 insertions, 24 deletions
diff --git a/src/capabilities.c b/src/capabilities.c new file mode 100644 index 0000000..6d07bbc --- /dev/null +++ b/src/capabilities.c @@ -0,0 +1,235 @@ +#ifndef _DEFAULT_SOURCE +# define _DEFAULT_SOURCE +#endif +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <wchar.h> +#include <libxml/tree.h> +#include <libxml/parser.h> +#include <curl/curl.h> +#include "capabilities.h" + +struct cap +{ + char *memory; + size_t size; +}; + +typedef void (*fct_parcours_t)(xmlNodePtr, ippScanner *ippscanner); + +void parcours_prefixe(xmlNodePtr noeud, fct_parcours_t f, ippScanner *ippscanner); +void afficher_noeud(xmlNodePtr noeud, ippScanner *ippscanner); + +void parcours_prefixe(xmlNodePtr noeud, fct_parcours_t f, ippScanner *ippscanner) { + xmlNodePtr n; + + for (n = noeud; n != NULL; n = n->next) { + f(n, ippscanner); + if ((n->type == XML_ELEMENT_NODE) && (n->children != NULL)) + parcours_prefixe(n->children, f, ippscanner); + } +} + +int is_array(const char *name, ippScanner *ippscanner) { + if (!strcmp(name, "Platen") || !strcmp(name, "Adf")) { + char is[256] = { 0 }; + if (!strcmp(name, "Platen")) + snprintf(is, sizeof(is), "platen"); + else if (!strcmp(name, "Adf")) + snprintf(is, sizeof(is), "adf"); + if (is[0]) { + if (ippscanner->is) { + if (!strstr(ippscanner->is, is)) { + int len = (strlen(ippscanner->is) + strlen(is) + 2); + ippscanner->is = (char *) realloc(ippscanner->is, len); + strcat(ippscanner->is, ","); + strcat(ippscanner->is, is); + } + } + else + ippscanner->is = strdup(is); + } + return 1; + } + if (!strcmp(name, "AdfDuplexInputCaps")) { + ippscanner->duplex = strdup("T"); + return 1; + } + if (!strcmp(name, "ScannerCapabilities") || + !strcmp(name, "SharpenSupport") || + !strcmp(name, "SupportedIntents") || + !strcmp(name, "CcdChannels") || + !strcmp(name, "ColorSpaces") || + !strcmp(name, "ColorModes") || + !strcmp(name, "DiscreteResolutions") || + !strcmp(name, "SupportedResolutions") || + !strcmp(name, "DocumentFormats") || + !strcmp(name, "ContentTypes") || + !strcmp(name, "DiscreteResolution") || + !strcmp(name, "CompressionFactorSupport") || + !strcmp(name, "SupportedMediaTypes") || + !strcmp(name, "SettingProfiles") || + !strcmp(name, "SettingProfile") || + !strcmp(name, "PlatenInputCaps")) + return 1; + return 0; + } + +void set_value_escl_scanner(const char *noeud, const char *contenu, ippScanner *ippscanner) +{ + if (!strcmp(noeud, "Version")) { + ippscanner->vers = strdup(contenu); + } else if (!strcmp(noeud, "MakeAndModel")) { + ippscanner->ty = strdup(contenu); + } else if (!strcmp(noeud, "UUID")) { + ippscanner->uuid = strdup(contenu); + } else if (!strcmp(noeud, "AdminURI")) { + ippscanner->adminurl = strdup(contenu); + } else if (!strcmp(noeud, "IconURI")) { + ippscanner->representation = strdup(contenu); + } else if (!strcmp(noeud, "DocumentFormat")){ + if (ippscanner->pdl) { + if (!strstr(ippscanner->pdl, contenu)) { + int len = (strlen(ippscanner->pdl) + strlen(contenu) + 2); + ippscanner->pdl = (char *) realloc(ippscanner->pdl, len); + strcat(ippscanner->pdl, ","); + strcat(ippscanner->pdl, contenu); + } + } + else { + ippscanner->pdl = strdup(contenu); + } + } else if (!strcmp(noeud, "ColorMode")){ + char modecolor[256] = { 0 }; + if (!strcmp(contenu, "Grayscale8")) + snprintf(modecolor, sizeof(modecolor), "grayscale"); + else if (!strcmp(contenu, "RGB24")) + snprintf(modecolor, sizeof(modecolor), "color"); + else if (!strcmp(contenu, "BlackAndWhite1")) + snprintf(modecolor, sizeof(modecolor), "binary"); + if (modecolor[0]) { + if (ippscanner->cs) { + if (!strstr(ippscanner->cs, modecolor)) { + int len = (strlen(ippscanner->cs) + strlen(modecolor) + 2); + ippscanner->cs = (char *) realloc(ippscanner->cs, len); + strcat(ippscanner->cs, ","); + strcat(ippscanner->cs, modecolor); + } + } + else { + ippscanner->cs = strdup(modecolor); + } + } + } +} + +void afficher_noeud(xmlNodePtr noeud, ippScanner *ippscanner) { + if (is_array((const char*)noeud->name, ippscanner)) return; + if (noeud->type == XML_ELEMENT_NODE) { + xmlChar *chemin = xmlGetNodePath(noeud); + if (noeud->children != NULL && noeud->children->type == XML_TEXT_NODE) { + xmlChar *contenu = xmlNodeGetContent(noeud); + if (noeud->name != NULL) + set_value_escl_scanner((const char*)noeud->name , (const char*)contenu, ippscanner); + xmlFree(contenu); + } + xmlFree(chemin); + } +} + +/** + * \fn static size_t memory_callback_c(void *contents, size_t size, size_t nmemb, void *userp) + * \brief Callback function that stocks in memory the content of the scanner capabilities. + * + * \return realsize (size of the content needed -> the scanner capabilities) + */ +static size_t +memory_callback_c(void *contents, size_t size, size_t nmemb, void *userp) +{ + size_t realsize = size * nmemb; + struct cap *mem = (struct cap *)userp; + + char *str = realloc(mem->memory, mem->size + realsize + 1); + if (str == NULL) { + fprintf(stderr, "not enough memory (realloc returned NULL)\n"); + return (0); + } + mem->memory = str; + memcpy(&(mem->memory[mem->size]), contents, realsize); + mem->size = mem->size + realsize; + mem->memory[mem->size] = 0; + return (realsize); +} + +int +is_scanner_present(ippScanner *scanner, const char *name) { + xmlDocPtr doc; + xmlNodePtr racine; + CURL *curl_handle = NULL; + struct cap *var = NULL; + char tmp[1024] = { 0 }; + + if (!scanner || name[0] == 0) return 0; + const char *scanner_capabilities = "eSCL/ScannerCapabilities"; + + var = (struct cap *)calloc(1, sizeof(struct cap)); + if (var == NULL) + return 0; + var->memory = malloc(1); + var->size = 0; + curl_handle = curl_easy_init(); + strcpy(tmp, name); + strcat(tmp, scanner_capabilities); + fprintf(stderr, "Path : %s\n", tmp); + curl_easy_setopt(curl_handle, CURLOPT_URL, tmp); + if (strncmp(name, "https", 5) == 0) { + curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L); + curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L); + } + curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, memory_callback_c); + curl_easy_setopt(curl_handle, CURLOPT_WRITEDATA, (void *)var); + if (curl_easy_perform(curl_handle) != CURLE_OK) { + fprintf(stderr, "Error : Curl\n"); + return 0; + } + // Ouverture du fichier XML + doc = xmlReadMemory(var->memory, var->size, "ScannerCapabilities.xml", NULL, 0); //xmlParseFile("ScannerCapabilities.xml"); + if (doc == NULL) { + fprintf(stderr, "Document XML invalide\n"); + return 0; + } + // Récupération de la racine + racine = xmlDocGetRootElement(doc); + if (racine == NULL) { + fprintf(stderr, "Document XML vierge\n"); + xmlFreeDoc(doc); + return 0; + } + // Parcours + parcours_prefixe(racine, afficher_noeud, scanner); + if (!scanner->duplex) scanner->duplex = strdup("F"); + + //printf("txt = [\n\"representation=%s\"\n\"note=\"\n\"UUID=%s\"\n\"adminurl=%s\"\n\"duplex=%s\"\n\"is=%s\"\n\"cs=%s\"\n\"pdl=%s\"\n\"ty=%s\"\n\"rs=eSCL\"\n\"vers=%s\"\n\"txtvers=1\"\n]", + // ippscanner->representation, ippscanner->uuid, ippscanner->adminurl, ippscanner->duplex, ippscanner->is, ippscanner->cs, ippscanner->pdl, ippscanner->ty, ippscanner->vers); + xmlFreeDoc(doc); + + return 1; +} + +ippScanner * +free_scanner (ippScanner *scanner) { + if (!scanner) return NULL; + + free(scanner->representation); + free(scanner->uuid); + free(scanner->adminurl); + free(scanner->duplex); + free(scanner->is); + free(scanner->cs); + free(scanner->pdl); + free(scanner->ty); + free(scanner->vers); + free(scanner); + return NULL; +} diff --git a/src/capabilities.h b/src/capabilities.h new file mode 100644 index 0000000..35f0f30 --- /dev/null +++ b/src/capabilities.h @@ -0,0 +1,19 @@ +#ifndef __CAPABILITIES_H__ +#define __CAPABILITIES_H__ + +typedef struct { + char *representation; + char *uuid; + char *adminurl; + char *duplex; + char *is; + char *cs; + char *pdl; + char *ty; + char *vers; +} ippScanner; + +int is_scanner_present(ippScanner *scanner, const char *name); +ippScanner *free_scanner(ippScanner *scanner); + +#endif diff --git a/src/dnssd.c b/src/dnssd.c index 33e2149..692ec26 100644 --- a/src/dnssd.c +++ b/src/dnssd.c @@ -21,9 +21,10 @@ #include "dnssd.h" #include "logging.h" #include "options.h" +#include "capabilities.h" /* - * 'dnssd_callback()' - Handle generic DNS-SD registration events + * 'dnssd_callback()' - Handle DNS-SD registration events generic. */ static void @@ -51,7 +52,7 @@ dnssd_callback(AvahiEntryGroup *g, /* I - Service */ } /* - * 'dnssd_callback()' - Handle IPP DNS-SD registration events + * 'dnssd_callback()' - Handle DNS-SD registration events ipp. */ static void @@ -68,7 +69,7 @@ dnssd_callback_ipp(AvahiEntryGroup *g, /* I - Service */ } /* - * 'dnssd_callback()' - Handle uscan DNS-SD registration events + * 'dnssd_callback()' - Handle DNS-SD registration events uscan. */ static void @@ -211,7 +212,7 @@ void dnssd_shutdown() int dnssd_register(AvahiClient *c) { AvahiStringList *ipp_txt; /* DNS-SD IPP TXT record */ - AvahiStringList *uscan_txt; /* DNS-SD USCAN TXT record */ + AvahiStringList *uscan_txt; /* DNS-SD USCAN TXT record */ char temp[256]; /* Subtype service string */ char dnssd_name[1024]; char *dev_id = NULL; @@ -231,6 +232,7 @@ int dnssd_register(AvahiClient *c) char formats[1024]; /* I - Supported formats */ char *ptr; int error; + ippScanner *scanner = NULL; /* * Parse the device ID for MFG, MDL, and CMD @@ -339,7 +341,7 @@ int dnssd_register(AvahiClient *c) snprintf(dnssd_name, sizeof(dnssd_name), "%s", model); /* - * Create the TXT record for the printer part ... + * Create the TXT record for printer ... */ ipp_txt = NULL; @@ -362,6 +364,7 @@ int dnssd_register(AvahiClient *c) ipp_txt = avahi_string_list_add_printf(ipp_txt, "priority=60"); ipp_txt = avahi_string_list_add_printf(ipp_txt, "txtvers=1"); ipp_txt = avahi_string_list_add_printf(ipp_txt, "qtotal=1"); + free(dev_id); /* * Register _printer._tcp (LPD) with port 0 to reserve the service name... @@ -459,34 +462,36 @@ int dnssd_register(AvahiClient *c) } /* - * Commit it for thr printer part ... + * Commit it printer ... */ avahi_entry_group_commit(g_options.dnssd_data->ipp_ref); avahi_string_list_free(ipp_txt); - if (g_options.scanner_present == 0) + + scanner = (ippScanner*) calloc(1, sizeof(ippScanner)); + if (is_scanner_present(scanner, temp) == 0 || scanner == NULL) goto noscanner; - /* - * Create the TXT record for the scanner part ... - */ + /* + * Create the TXT record for scanner ... + */ uscan_txt = NULL; - uscan_txt = avahi_string_list_add_printf(uscan_txt, "duplex=U"); - uscan_txt = avahi_string_list_add_printf(uscan_txt, "is=platen"); - uscan_txt = avahi_string_list_add_printf(uscan_txt, "cs=U"); + uscan_txt = avahi_string_list_add_printf(uscan_txt, "representation=%s", scanner->representation); + uscan_txt = avahi_string_list_add_printf(uscan_txt, "note="); + uscan_txt = avahi_string_list_add_printf(uscan_txt, "UUID=%s", scanner->uuid); + uscan_txt = avahi_string_list_add_printf(uscan_txt, "adminurl=%s", scanner->adminurl); + uscan_txt = avahi_string_list_add_printf(uscan_txt, "dupplex=%s", scanner->duplex); + uscan_txt = avahi_string_list_add_printf(uscan_txt, "cs=%s", scanner->cs); + uscan_txt = avahi_string_list_add_printf(uscan_txt, "pdl=%s", scanner->pdl); + uscan_txt = avahi_string_list_add_printf(uscan_txt, "ty=%s", scanner->ty); uscan_txt = avahi_string_list_add_printf(uscan_txt, "rs=eSCL"); - uscan_txt = avahi_string_list_add_printf(uscan_txt, "representation="); - uscan_txt = avahi_string_list_add_printf(uscan_txt, "ty=%s %s", make, model); - if (strcasecmp(g_options.interface, "lo") == 0) - uscan_txt = avahi_string_list_add_printf(uscan_txt, "adminurl=%s", temp); - uscan_txt = avahi_string_list_add_printf(uscan_txt, "pdl=image/jpeg"); - uscan_txt = avahi_string_list_add_printf(uscan_txt, "vers=2.0"); + uscan_txt = avahi_string_list_add_printf(uscan_txt, "vers=%s", scanner->vers); uscan_txt = avahi_string_list_add_printf(uscan_txt, "txtvers=1"); /* - * Register _uscan._tcp (Scanner) ... + * Register _uscan._tcp (LPD) with port 0 to reserve the service name... */ NOTE("Registering scanner %s on interface %s for DNS-SD broadcasting ...", @@ -500,6 +505,7 @@ int dnssd_register(AvahiClient *c) if (g_options.dnssd_data->uscan_ref == NULL) { ERR("Could not establish Avahi entry group"); avahi_string_list_free(uscan_txt); + scanner = free_scanner(scanner); return -1; } @@ -511,8 +517,7 @@ int dnssd_register(AvahiClient *c) AVAHI_PROTO_UNSPEC, 0, dnssd_name, "_uscan._tcp", NULL, NULL, - g_options.real_port, - uscan_txt); + g_options.real_port, uscan_txt); if (error) ERR("Error registering %s as Unix scanner (_uscan._tcp): %d", dnssd_name, error); @@ -520,14 +525,14 @@ int dnssd_register(AvahiClient *c) NOTE("Registered %s as Unix scanner (_uscan._tcp).", dnssd_name); /* - * Commit it for the scanner part ... + * Commit it scanner ... */ avahi_entry_group_commit(g_options.dnssd_data->uscan_ref); avahi_string_list_free(uscan_txt); + scanner = free_scanner(scanner); noscanner: - free(dev_id); return 0; } |