summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorthierry1970 <thierry@ordissimo.com>2020-02-06 17:22:55 +0100
committerthierry1970 <thierry@ordissimo.com>2020-02-06 17:22:55 +0100
commit9b4be30a8dddc54006550bcf84d18c473504d24e (patch)
treee97e1b672762764ea6f606763d3fdc6e89a65b19 /src
parent7cafed5a748a9cdd79de022514098f18dd7c1cf2 (diff)
Txt recording for eSCL scanner.
Diffstat (limited to 'src')
-rw-r--r--src/capabilities.c235
-rw-r--r--src/capabilities.h19
-rw-r--r--src/dnssd.c53
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;
}