1141cc406Sopenharmony_ci/*
2141cc406Sopenharmony_ci * epsonds-net.c - SANE library for Epson scanners.
3141cc406Sopenharmony_ci *
4141cc406Sopenharmony_ci * Copyright (C) 2006-2016 Tower Technologies
5141cc406Sopenharmony_ci * Author: Alessandro Zummo <a.zummo@towertech.it>
6141cc406Sopenharmony_ci *
7141cc406Sopenharmony_ci * This file is part of the SANE package.
8141cc406Sopenharmony_ci *
9141cc406Sopenharmony_ci * This program is free software; you can redistribute it and/or
10141cc406Sopenharmony_ci * modify it under the terms of the GNU General Public License as
11141cc406Sopenharmony_ci * published by the Free Software Foundation, version 2.
12141cc406Sopenharmony_ci */
13141cc406Sopenharmony_ci
14141cc406Sopenharmony_ci#define DEBUG_DECLARE_ONLY
15141cc406Sopenharmony_ci
16141cc406Sopenharmony_ci#include "sane/config.h"
17141cc406Sopenharmony_ci
18141cc406Sopenharmony_ci#ifdef HAVE_SYS_SELECT_H
19141cc406Sopenharmony_ci#include <sys/select.h>
20141cc406Sopenharmony_ci#endif
21141cc406Sopenharmony_ci
22141cc406Sopenharmony_ci#include "sane/sane.h"
23141cc406Sopenharmony_ci#include "sane/saneopts.h"
24141cc406Sopenharmony_ci#include "sane/sanei_tcp.h"
25141cc406Sopenharmony_ci#include "sane/sanei_config.h"
26141cc406Sopenharmony_ci#include "sane/sanei_backend.h"
27141cc406Sopenharmony_ci
28141cc406Sopenharmony_ci#include "epsonds.h"
29141cc406Sopenharmony_ci#include "epsonds-net.h"
30141cc406Sopenharmony_ci
31141cc406Sopenharmony_ci#include "byteorder.h"
32141cc406Sopenharmony_ci
33141cc406Sopenharmony_ci#include "sane/sanei_debug.h"
34141cc406Sopenharmony_ci
35141cc406Sopenharmony_ci
36141cc406Sopenharmony_cistatic ssize_t
37141cc406Sopenharmony_ciepsonds_net_read_raw(epsonds_scanner *s, unsigned char *buf, ssize_t wanted,
38141cc406Sopenharmony_ci		       SANE_Status *status)
39141cc406Sopenharmony_ci{
40141cc406Sopenharmony_ci	DBG(15, "%s: wanted: %ld\n", __func__, wanted);
41141cc406Sopenharmony_ci
42141cc406Sopenharmony_ci	if (wanted == 0)
43141cc406Sopenharmony_ci	{
44141cc406Sopenharmony_ci	    *status = SANE_STATUS_GOOD;
45141cc406Sopenharmony_ci		return 0;
46141cc406Sopenharmony_ci	}
47141cc406Sopenharmony_ci
48141cc406Sopenharmony_ci	int ready;
49141cc406Sopenharmony_ci	ssize_t read = -1;
50141cc406Sopenharmony_ci	fd_set readable;
51141cc406Sopenharmony_ci	struct timeval tv;
52141cc406Sopenharmony_ci
53141cc406Sopenharmony_ci	tv.tv_sec = 10;
54141cc406Sopenharmony_ci	tv.tv_usec = 0;
55141cc406Sopenharmony_ci
56141cc406Sopenharmony_ci	FD_ZERO(&readable);
57141cc406Sopenharmony_ci	FD_SET(s->fd, &readable);
58141cc406Sopenharmony_ci
59141cc406Sopenharmony_ci	ready = select(s->fd + 1, &readable, NULL, NULL, &tv);
60141cc406Sopenharmony_ci	if (ready > 0) {
61141cc406Sopenharmony_ci		read = sanei_tcp_read(s->fd, buf, wanted);
62141cc406Sopenharmony_ci	} else {
63141cc406Sopenharmony_ci		DBG(15, "%s: select failed: %d\n", __func__, ready);
64141cc406Sopenharmony_ci	}
65141cc406Sopenharmony_ci
66141cc406Sopenharmony_ci	*status = SANE_STATUS_GOOD;
67141cc406Sopenharmony_ci
68141cc406Sopenharmony_ci	if (read < wanted) {
69141cc406Sopenharmony_ci		*status = SANE_STATUS_IO_ERROR;
70141cc406Sopenharmony_ci	}
71141cc406Sopenharmony_ci
72141cc406Sopenharmony_ci	return read;
73141cc406Sopenharmony_ci}
74141cc406Sopenharmony_ci
75141cc406Sopenharmony_cistatic ssize_t
76141cc406Sopenharmony_ciepsonds_net_read_buf(epsonds_scanner *s, unsigned char *buf, ssize_t wanted,
77141cc406Sopenharmony_ci		       SANE_Status * status)
78141cc406Sopenharmony_ci{
79141cc406Sopenharmony_ci	ssize_t read = 0;
80141cc406Sopenharmony_ci
81141cc406Sopenharmony_ci	DBG(23, "%s: reading up to %lu from buffer at %p, %lu available\n",
82141cc406Sopenharmony_ci		__func__, (u_long) wanted, (void *) s->netptr, (u_long) s->netlen);
83141cc406Sopenharmony_ci
84141cc406Sopenharmony_ci	if ((size_t) wanted > s->netlen) {
85141cc406Sopenharmony_ci		*status = SANE_STATUS_IO_ERROR;
86141cc406Sopenharmony_ci		wanted = s->netlen;
87141cc406Sopenharmony_ci	}
88141cc406Sopenharmony_ci
89141cc406Sopenharmony_ci	memcpy(buf, s->netptr, wanted);
90141cc406Sopenharmony_ci	read = wanted;
91141cc406Sopenharmony_ci
92141cc406Sopenharmony_ci	s->netptr += read;
93141cc406Sopenharmony_ci	s->netlen -= read;
94141cc406Sopenharmony_ci
95141cc406Sopenharmony_ci	if (s->netlen == 0) {
96141cc406Sopenharmony_ci		DBG(23, "%s: freeing %p\n", __func__, (void *) s->netbuf);
97141cc406Sopenharmony_ci		free(s->netbuf);
98141cc406Sopenharmony_ci		s->netbuf = s->netptr = NULL;
99141cc406Sopenharmony_ci		s->netlen = 0;
100141cc406Sopenharmony_ci	}
101141cc406Sopenharmony_ci
102141cc406Sopenharmony_ci	return read;
103141cc406Sopenharmony_ci}
104141cc406Sopenharmony_ci
105141cc406Sopenharmony_cissize_t
106141cc406Sopenharmony_ciepsonds_net_read(epsonds_scanner *s, unsigned char *buf, ssize_t wanted,
107141cc406Sopenharmony_ci		       SANE_Status * status)
108141cc406Sopenharmony_ci{
109141cc406Sopenharmony_ci	if (wanted < 0) {
110141cc406Sopenharmony_ci		*status = SANE_STATUS_INVAL;
111141cc406Sopenharmony_ci		return 0;
112141cc406Sopenharmony_ci	}
113141cc406Sopenharmony_ci
114141cc406Sopenharmony_ci	size_t size;
115141cc406Sopenharmony_ci	ssize_t read = 0;
116141cc406Sopenharmony_ci	unsigned char header[12];
117141cc406Sopenharmony_ci
118141cc406Sopenharmony_ci	/* read from remainder of buffer */
119141cc406Sopenharmony_ci	if (s->netptr) {
120141cc406Sopenharmony_ci		return epsonds_net_read_buf(s, buf, wanted, status);
121141cc406Sopenharmony_ci	}
122141cc406Sopenharmony_ci
123141cc406Sopenharmony_ci	/* receive net header */
124141cc406Sopenharmony_ci	read = epsonds_net_read_raw(s, header, 12, status);
125141cc406Sopenharmony_ci	if (read != 12) {
126141cc406Sopenharmony_ci		return 0;
127141cc406Sopenharmony_ci	}
128141cc406Sopenharmony_ci
129141cc406Sopenharmony_ci	/* validate header */
130141cc406Sopenharmony_ci	if (header[0] != 'I' || header[1] != 'S') {
131141cc406Sopenharmony_ci		DBG(1, "header mismatch: %02X %02x\n", header[0], header[1]);
132141cc406Sopenharmony_ci		*status = SANE_STATUS_IO_ERROR;
133141cc406Sopenharmony_ci		return 0;
134141cc406Sopenharmony_ci	}
135141cc406Sopenharmony_ci
136141cc406Sopenharmony_ci	/* parse payload size */
137141cc406Sopenharmony_ci	size = be32atoh(&header[6]);
138141cc406Sopenharmony_ci
139141cc406Sopenharmony_ci	*status = SANE_STATUS_GOOD;
140141cc406Sopenharmony_ci
141141cc406Sopenharmony_ci	if (!s->netbuf) {
142141cc406Sopenharmony_ci		DBG(15, "%s: direct read\n", __func__);
143141cc406Sopenharmony_ci		DBG(23, "%s: wanted = %lu, available = %lu\n", __func__,
144141cc406Sopenharmony_ci			(u_long) wanted, (u_long) size);
145141cc406Sopenharmony_ci
146141cc406Sopenharmony_ci		if ((size_t) wanted > size) {
147141cc406Sopenharmony_ci			wanted = size;
148141cc406Sopenharmony_ci		}
149141cc406Sopenharmony_ci
150141cc406Sopenharmony_ci		read = epsonds_net_read_raw(s, buf, wanted, status);
151141cc406Sopenharmony_ci	} else {
152141cc406Sopenharmony_ci		DBG(15, "%s: buffered read\n", __func__);
153141cc406Sopenharmony_ci		DBG(23, "%s: bufferable = %lu, available = %lu\n", __func__,
154141cc406Sopenharmony_ci			(u_long) s->netlen, (u_long) size);
155141cc406Sopenharmony_ci
156141cc406Sopenharmony_ci		if (s->netlen > size) {
157141cc406Sopenharmony_ci			s->netlen = size;
158141cc406Sopenharmony_ci		}
159141cc406Sopenharmony_ci
160141cc406Sopenharmony_ci		/* fill buffer */
161141cc406Sopenharmony_ci		read = epsonds_net_read_raw(s, s->netbuf, s->netlen, status);
162141cc406Sopenharmony_ci		s->netptr = s->netbuf;
163141cc406Sopenharmony_ci		s->netlen = (read > 0 ? read : 0);
164141cc406Sopenharmony_ci
165141cc406Sopenharmony_ci		/* copy wanted part */
166141cc406Sopenharmony_ci		read = epsonds_net_read_buf(s, buf, wanted, status);
167141cc406Sopenharmony_ci	}
168141cc406Sopenharmony_ci
169141cc406Sopenharmony_ci	return read;
170141cc406Sopenharmony_ci}
171141cc406Sopenharmony_ci
172141cc406Sopenharmony_ciSANE_Status
173141cc406Sopenharmony_ciepsonds_net_request_read(epsonds_scanner *s, size_t len)
174141cc406Sopenharmony_ci{
175141cc406Sopenharmony_ci	SANE_Status status;
176141cc406Sopenharmony_ci	epsonds_net_write(s, 0x2000, NULL, 0, len, &status);
177141cc406Sopenharmony_ci	return status;
178141cc406Sopenharmony_ci}
179141cc406Sopenharmony_ci
180141cc406Sopenharmony_cisize_t
181141cc406Sopenharmony_ciepsonds_net_write(epsonds_scanner *s, unsigned int cmd, const unsigned char *buf,
182141cc406Sopenharmony_ci			size_t buf_size, size_t reply_len, SANE_Status *status)
183141cc406Sopenharmony_ci{
184141cc406Sopenharmony_ci	unsigned char *h1, *h2;
185141cc406Sopenharmony_ci	unsigned char *packet = malloc(12 + 8);
186141cc406Sopenharmony_ci
187141cc406Sopenharmony_ci	if (!packet) {
188141cc406Sopenharmony_ci		*status = SANE_STATUS_NO_MEM;
189141cc406Sopenharmony_ci		return 0;
190141cc406Sopenharmony_ci	}
191141cc406Sopenharmony_ci
192141cc406Sopenharmony_ci	h1 = packet;		// packet header
193141cc406Sopenharmony_ci	h2 = packet + 12;	// data header
194141cc406Sopenharmony_ci
195141cc406Sopenharmony_ci	if (reply_len) {
196141cc406Sopenharmony_ci		if (s->netbuf) {
197141cc406Sopenharmony_ci			DBG(23, "%s, freeing %p, %ld bytes unprocessed\n",
198141cc406Sopenharmony_ci				__func__, (void *) s->netbuf, (u_long) s->netlen);
199141cc406Sopenharmony_ci			free(s->netbuf);
200141cc406Sopenharmony_ci			s->netbuf = s->netptr = NULL;
201141cc406Sopenharmony_ci			s->netlen = 0;
202141cc406Sopenharmony_ci		}
203141cc406Sopenharmony_ci		s->netbuf = malloc(reply_len);
204141cc406Sopenharmony_ci		if (!s->netbuf) {
205141cc406Sopenharmony_ci			free(packet);
206141cc406Sopenharmony_ci			*status = SANE_STATUS_NO_MEM;
207141cc406Sopenharmony_ci			return 0;
208141cc406Sopenharmony_ci		}
209141cc406Sopenharmony_ci		s->netlen = reply_len;
210141cc406Sopenharmony_ci		DBG(24, "%s: allocated %lu bytes at %p\n", __func__,
211141cc406Sopenharmony_ci			(u_long) s->netlen, (void *) s->netbuf);
212141cc406Sopenharmony_ci	}
213141cc406Sopenharmony_ci
214141cc406Sopenharmony_ci	DBG(24, "%s: cmd = %04x, buf = %p, buf_size = %lu, reply_len = %lu\n",
215141cc406Sopenharmony_ci		__func__, cmd, (void *) buf, (u_long) buf_size, (u_long) reply_len);
216141cc406Sopenharmony_ci
217141cc406Sopenharmony_ci	memset(h1, 0x00, 12);
218141cc406Sopenharmony_ci	memset(h2, 0x00, 8);
219141cc406Sopenharmony_ci
220141cc406Sopenharmony_ci	h1[0] = 'I';
221141cc406Sopenharmony_ci	h1[1] = 'S';
222141cc406Sopenharmony_ci
223141cc406Sopenharmony_ci	h1[2] = cmd >> 8;	// packet type
224141cc406Sopenharmony_ci	h1[3] = cmd;		// data type
225141cc406Sopenharmony_ci
226141cc406Sopenharmony_ci	h1[4] = 0x00;
227141cc406Sopenharmony_ci	h1[5] = 0x0C; // data offset
228141cc406Sopenharmony_ci
229141cc406Sopenharmony_ci	DBG(24, "H1[0]: %02x %02x %02x %02x\n", h1[0], h1[1], h1[2], h1[3]);
230141cc406Sopenharmony_ci
231141cc406Sopenharmony_ci	// 0x20 passthru
232141cc406Sopenharmony_ci	// 0x21 job control
233141cc406Sopenharmony_ci
234141cc406Sopenharmony_ci	if (buf_size) {
235141cc406Sopenharmony_ci		htobe32a(&h1[6], buf_size);
236141cc406Sopenharmony_ci	}
237141cc406Sopenharmony_ci
238141cc406Sopenharmony_ci	if((cmd >> 8) == 0x20) {
239141cc406Sopenharmony_ci
240141cc406Sopenharmony_ci		htobe32a(&h1[6], buf_size + 8);	// data size (data header + payload)
241141cc406Sopenharmony_ci
242141cc406Sopenharmony_ci		htobe32a(&h2[0], buf_size);	// payload size
243141cc406Sopenharmony_ci		htobe32a(&h2[4], reply_len);	// expected answer size
244141cc406Sopenharmony_ci
245141cc406Sopenharmony_ci		DBG(24, "H1[6]: %02x %02x %02x %02x (%lu)\n", h1[6], h1[7], h1[8], h1[9], (u_long) (buf_size + 8));
246141cc406Sopenharmony_ci		DBG(24, "H2[0]: %02x %02x %02x %02x (%lu)\n", h2[0], h2[1], h2[2], h2[3], (u_long) buf_size);
247141cc406Sopenharmony_ci		DBG(24, "H2[4]: %02x %02x %02x %02x (%lu)\n", h2[4], h2[5], h2[6], h2[7], (u_long) reply_len);
248141cc406Sopenharmony_ci	}
249141cc406Sopenharmony_ci
250141cc406Sopenharmony_ci	if ((cmd >> 8) == 0x20 && (buf_size || reply_len)) {
251141cc406Sopenharmony_ci
252141cc406Sopenharmony_ci		// send header + data header
253141cc406Sopenharmony_ci		sanei_tcp_write(s->fd, packet, 12 + 8);
254141cc406Sopenharmony_ci
255141cc406Sopenharmony_ci	} else {
256141cc406Sopenharmony_ci		sanei_tcp_write(s->fd, packet, 12);
257141cc406Sopenharmony_ci	}
258141cc406Sopenharmony_ci
259141cc406Sopenharmony_ci	// send payload
260141cc406Sopenharmony_ci	if (buf_size)
261141cc406Sopenharmony_ci		sanei_tcp_write(s->fd, buf, buf_size);
262141cc406Sopenharmony_ci
263141cc406Sopenharmony_ci	free(packet);
264141cc406Sopenharmony_ci
265141cc406Sopenharmony_ci	*status = SANE_STATUS_GOOD;
266141cc406Sopenharmony_ci	return buf_size;
267141cc406Sopenharmony_ci}
268141cc406Sopenharmony_ci
269141cc406Sopenharmony_ciSANE_Status
270141cc406Sopenharmony_ciepsonds_net_lock(struct epsonds_scanner *s)
271141cc406Sopenharmony_ci{
272141cc406Sopenharmony_ci	SANE_Status status;
273141cc406Sopenharmony_ci	unsigned char buf[7] = "\x01\xa0\x04\x00\x00\x01\x2c";
274141cc406Sopenharmony_ci
275141cc406Sopenharmony_ci	DBG(1, "%s\n", __func__);
276141cc406Sopenharmony_ci
277141cc406Sopenharmony_ci	epsonds_net_write(s, 0x2100, buf, 7, 0, &status);
278141cc406Sopenharmony_ci	epsonds_net_read(s, buf, 1, &status);
279141cc406Sopenharmony_ci
280141cc406Sopenharmony_ci	// buf[0] should be ACK, 0x06
281141cc406Sopenharmony_ci
282141cc406Sopenharmony_ci	return status;
283141cc406Sopenharmony_ci}
284141cc406Sopenharmony_ci
285141cc406Sopenharmony_ciSANE_Status
286141cc406Sopenharmony_ciepsonds_net_unlock(struct epsonds_scanner *s)
287141cc406Sopenharmony_ci{
288141cc406Sopenharmony_ci	SANE_Status status;
289141cc406Sopenharmony_ci
290141cc406Sopenharmony_ci	DBG(1, "%s\n", __func__);
291141cc406Sopenharmony_ci
292141cc406Sopenharmony_ci	epsonds_net_write(s, 0x2101, NULL, 0, 0, &status);
293141cc406Sopenharmony_ci/*	epsonds_net_read(s, buf, 1, &status); */
294141cc406Sopenharmony_ci	return status;
295141cc406Sopenharmony_ci}
296141cc406Sopenharmony_ci#if WITH_AVAHI
297141cc406Sopenharmony_ci
298141cc406Sopenharmony_ci#include <assert.h>
299141cc406Sopenharmony_ci#include <stdio.h>
300141cc406Sopenharmony_ci#include <stdlib.h>
301141cc406Sopenharmony_ci#include <string.h>
302141cc406Sopenharmony_ci#include <avahi-client/lookup.h>
303141cc406Sopenharmony_ci#include <avahi-common/error.h>
304141cc406Sopenharmony_ci#include <avahi-common/simple-watch.h>
305141cc406Sopenharmony_ci#include <sys/time.h>
306141cc406Sopenharmony_ci#include <errno.h>
307141cc406Sopenharmony_ci
308141cc406Sopenharmony_cistatic AvahiSimplePoll *simple_poll = NULL;
309141cc406Sopenharmony_ci
310141cc406Sopenharmony_cistatic struct timeval borowseEndTime;
311141cc406Sopenharmony_ci
312141cc406Sopenharmony_cistatic int resolvedCount = 0;
313141cc406Sopenharmony_cistatic int browsedCount = 0;
314141cc406Sopenharmony_cistatic int waitResolver = 0;
315141cc406Sopenharmony_ci
316141cc406Sopenharmony_citypedef struct {
317141cc406Sopenharmony_ci    AvahiClient* client;
318141cc406Sopenharmony_ci    Device_Found_CallBack callBack;
319141cc406Sopenharmony_ci}EDSAvahiUserData;
320141cc406Sopenharmony_ci
321141cc406Sopenharmony_cistatic int my_avahi_simple_poll_loop(AvahiSimplePoll *s) {
322141cc406Sopenharmony_ci    struct timeval currentTime;
323141cc406Sopenharmony_ci
324141cc406Sopenharmony_ci    for (;;)
325141cc406Sopenharmony_ci    {
326141cc406Sopenharmony_ci         int r = avahi_simple_poll_iterate(s, 1);
327141cc406Sopenharmony_ci		if (r != 0)
328141cc406Sopenharmony_ci		{
329141cc406Sopenharmony_ci			if (r >= 0 || errno != EINTR)
330141cc406Sopenharmony_ci			{
331141cc406Sopenharmony_ci					DBG(10, "my_avahi_simple_poll_loop end\n");
332141cc406Sopenharmony_ci					return r;
333141cc406Sopenharmony_ci			}
334141cc406Sopenharmony_ci		}
335141cc406Sopenharmony_ci
336141cc406Sopenharmony_ci		if (waitResolver) {
337141cc406Sopenharmony_ci			gettimeofday(&currentTime, NULL);
338141cc406Sopenharmony_ci
339141cc406Sopenharmony_ci			if ((currentTime.tv_sec - borowseEndTime.tv_sec) >= 3)
340141cc406Sopenharmony_ci			{
341141cc406Sopenharmony_ci				avahi_simple_poll_quit(simple_poll);
342141cc406Sopenharmony_ci				DBG(10, "resolve timeout\n");
343141cc406Sopenharmony_ci				return 0;
344141cc406Sopenharmony_ci			}
345141cc406Sopenharmony_ci		}
346141cc406Sopenharmony_ci    }
347141cc406Sopenharmony_ci}
348141cc406Sopenharmony_ci
349141cc406Sopenharmony_cistatic void
350141cc406Sopenharmony_ciepsonds_resolve_callback(AvahiServiceResolver *r, AVAHI_GCC_UNUSED AvahiIfIndex interface,
351141cc406Sopenharmony_ci                            AVAHI_GCC_UNUSED AvahiProtocol protocol,
352141cc406Sopenharmony_ci                            AvahiResolverEvent event, const char *name,
353141cc406Sopenharmony_ci                            const char  *type,
354141cc406Sopenharmony_ci                            const char  *domain,
355141cc406Sopenharmony_ci                            const char  *host_name,
356141cc406Sopenharmony_ci                            const AvahiAddress *address, uint16_t port, AvahiStringList *txt,
357141cc406Sopenharmony_ci                            AvahiLookupResultFlags  flags,
358141cc406Sopenharmony_ci                            void  *userdata)
359141cc406Sopenharmony_ci{
360141cc406Sopenharmony_ci	// unused parameter
361141cc406Sopenharmony_ci	(void)r;
362141cc406Sopenharmony_ci	(void)type;
363141cc406Sopenharmony_ci	(void)domain;
364141cc406Sopenharmony_ci	(void)host_name;
365141cc406Sopenharmony_ci	(void)port;
366141cc406Sopenharmony_ci	(void)flags;
367141cc406Sopenharmony_ci    EDSAvahiUserData* data = userdata;
368141cc406Sopenharmony_ci    char ipAddr[AVAHI_ADDRESS_STR_MAX];
369141cc406Sopenharmony_ci
370141cc406Sopenharmony_ci	DBG(10, "epsonds_searchDevices resolve_callback\n");
371141cc406Sopenharmony_ci
372141cc406Sopenharmony_ci
373141cc406Sopenharmony_ci    resolvedCount++;
374141cc406Sopenharmony_ci
375141cc406Sopenharmony_ci    switch (event) {
376141cc406Sopenharmony_ci    case AVAHI_RESOLVER_FAILURE:
377141cc406Sopenharmony_ci        break;
378141cc406Sopenharmony_ci    case AVAHI_RESOLVER_FOUND:
379141cc406Sopenharmony_ci        avahi_address_snprint(ipAddr, sizeof(ipAddr), address);
380141cc406Sopenharmony_ci	   DBG(10, "epsonds_searchDevices name = %s \n", name);
381141cc406Sopenharmony_ci        if (strlen(name) > 7)
382141cc406Sopenharmony_ci        {
383141cc406Sopenharmony_ci            if (strncmp(name, "EPSON", 5) == 0)
384141cc406Sopenharmony_ci            {
385141cc406Sopenharmony_ci				while(txt != NULL)
386141cc406Sopenharmony_ci				{
387141cc406Sopenharmony_ci					char* text = (char*)avahi_string_list_get_text(txt);
388141cc406Sopenharmony_ci					DBG(10, "avahi string = %s\n", text);
389141cc406Sopenharmony_ci
390141cc406Sopenharmony_ci					if (strlen(text) > 4 && strncmp(text, "mdl=", 4) == 0)
391141cc406Sopenharmony_ci					{
392141cc406Sopenharmony_ci						if (data->callBack)
393141cc406Sopenharmony_ci                		{
394141cc406Sopenharmony_ci							data->callBack(&text[4], ipAddr);
395141cc406Sopenharmony_ci							break;
396141cc406Sopenharmony_ci                		}
397141cc406Sopenharmony_ci					}
398141cc406Sopenharmony_ci					txt = avahi_string_list_get_next(txt);
399141cc406Sopenharmony_ci				}
400141cc406Sopenharmony_ci
401141cc406Sopenharmony_ci            }
402141cc406Sopenharmony_ci        }
403141cc406Sopenharmony_ci		break;
404141cc406Sopenharmony_ci    }
405141cc406Sopenharmony_ci}
406141cc406Sopenharmony_ci
407141cc406Sopenharmony_cistatic void
408141cc406Sopenharmony_cibrowse_callback(AvahiServiceBrowser *b, AvahiIfIndex interface,
409141cc406Sopenharmony_ci                            AvahiProtocol protocol, AvahiBrowserEvent event,
410141cc406Sopenharmony_ci                            const char *name, const char *type,
411141cc406Sopenharmony_ci                            const char *domain,
412141cc406Sopenharmony_ci                            AvahiLookupResultFlags flags,
413141cc406Sopenharmony_ci                            void* userdata)
414141cc406Sopenharmony_ci{
415141cc406Sopenharmony_ci    DBG(10, "browse_callback event = %d\n", event);
416141cc406Sopenharmony_ci
417141cc406Sopenharmony_ci	//unused parameter
418141cc406Sopenharmony_ci	(void)b;
419141cc406Sopenharmony_ci	(void)flags;
420141cc406Sopenharmony_ci
421141cc406Sopenharmony_ci    EDSAvahiUserData *data = userdata;
422141cc406Sopenharmony_ci    switch (event) {
423141cc406Sopenharmony_ci    case AVAHI_BROWSER_FAILURE:
424141cc406Sopenharmony_ci        avahi_simple_poll_quit(simple_poll);
425141cc406Sopenharmony_ci        return;
426141cc406Sopenharmony_ci    case AVAHI_BROWSER_NEW:
427141cc406Sopenharmony_ci	    DBG(10, "browse_callback name = %s\n", name);
428141cc406Sopenharmony_ci		browsedCount++;
429141cc406Sopenharmony_ci        if (!(avahi_service_resolver_new(data->client, interface, protocol, name,
430141cc406Sopenharmony_ci                                                               type, domain,
431141cc406Sopenharmony_ci                                                               AVAHI_PROTO_UNSPEC, 0,
432141cc406Sopenharmony_ci                                                               epsonds_resolve_callback, data)))
433141cc406Sopenharmony_ci		{
434141cc406Sopenharmony_ci			DBG(10, "avahi_service_resolver_new fails\n");
435141cc406Sopenharmony_ci		    break;
436141cc406Sopenharmony_ci		}
437141cc406Sopenharmony_ci    case AVAHI_BROWSER_REMOVE:
438141cc406Sopenharmony_ci        break;
439141cc406Sopenharmony_ci    case AVAHI_BROWSER_ALL_FOR_NOW:
440141cc406Sopenharmony_ci		DBG(10, "AVAHI_BROWSER_ALL_FOR_NOW\n");
441141cc406Sopenharmony_ci        gettimeofday(&borowseEndTime, NULL);
442141cc406Sopenharmony_ci
443141cc406Sopenharmony_ci        if (browsedCount > resolvedCount)
444141cc406Sopenharmony_ci        {
445141cc406Sopenharmony_ci			  DBG(10, "WAIT RESOLVER\n");
446141cc406Sopenharmony_ci               waitResolver = 1;
447141cc406Sopenharmony_ci         }else{
448141cc406Sopenharmony_ci			 DBG(10, "QUIT POLL\n");
449141cc406Sopenharmony_ci             avahi_simple_poll_quit(simple_poll);
450141cc406Sopenharmony_ci         }
451141cc406Sopenharmony_ci		break;
452141cc406Sopenharmony_ci    case AVAHI_BROWSER_CACHE_EXHAUSTED:
453141cc406Sopenharmony_ci		 DBG(10, "AVAHI_BROWSER_CACHE_EXHAUSTED\n");
454141cc406Sopenharmony_ci        break;
455141cc406Sopenharmony_ci    }
456141cc406Sopenharmony_ci}
457141cc406Sopenharmony_ci
458141cc406Sopenharmony_cistatic void
459141cc406Sopenharmony_ciclient_callback(AvahiClient *c, AvahiClientState state,
460141cc406Sopenharmony_ci                         AVAHI_GCC_UNUSED void *userdata)
461141cc406Sopenharmony_ci{
462141cc406Sopenharmony_ci    assert(c);
463141cc406Sopenharmony_ci    if (state == AVAHI_CLIENT_FAILURE)
464141cc406Sopenharmony_ci        avahi_simple_poll_quit(simple_poll);
465141cc406Sopenharmony_ci}
466141cc406Sopenharmony_ci
467141cc406Sopenharmony_ciSANE_Status epsonds_searchDevices(Device_Found_CallBack deviceFoundCallBack)
468141cc406Sopenharmony_ci{
469141cc406Sopenharmony_ci	int result = SANE_STATUS_GOOD;
470141cc406Sopenharmony_ci
471141cc406Sopenharmony_ci    AvahiClient *client = NULL;
472141cc406Sopenharmony_ci    AvahiServiceBrowser *sb = NULL;
473141cc406Sopenharmony_ci
474141cc406Sopenharmony_ci    EDSAvahiUserData data;
475141cc406Sopenharmony_ci
476141cc406Sopenharmony_ci    resolvedCount = 0;
477141cc406Sopenharmony_ci	browsedCount = 0;
478141cc406Sopenharmony_ci	waitResolver = 0;
479141cc406Sopenharmony_ci
480141cc406Sopenharmony_ci
481141cc406Sopenharmony_ci	int error = 0;
482141cc406Sopenharmony_ci    DBG(10, "epsonds_searchDevices\n");
483141cc406Sopenharmony_ci
484141cc406Sopenharmony_ci    if (!(simple_poll = avahi_simple_poll_new())) {
485141cc406Sopenharmony_ci        DBG(10, "avahi_simple_poll_new failed\n");
486141cc406Sopenharmony_ci		result = SANE_STATUS_INVAL;
487141cc406Sopenharmony_ci        goto fail;
488141cc406Sopenharmony_ci    }
489141cc406Sopenharmony_ci    client = avahi_client_new(avahi_simple_poll_get(simple_poll), 0,
490141cc406Sopenharmony_ci                                               client_callback, NULL, &error);
491141cc406Sopenharmony_ci    if (!client) {
492141cc406Sopenharmony_ci        DBG(10, "avahi_client_new failed %s\n", avahi_strerror(error));
493141cc406Sopenharmony_ci		result = SANE_STATUS_INVAL;
494141cc406Sopenharmony_ci        goto fail;
495141cc406Sopenharmony_ci    }
496141cc406Sopenharmony_ci    data.client = client;
497141cc406Sopenharmony_ci    data.callBack = deviceFoundCallBack;
498141cc406Sopenharmony_ci
499141cc406Sopenharmony_ci    if (!(sb = avahi_service_browser_new(client, AVAHI_IF_UNSPEC,
500141cc406Sopenharmony_ci                                                                   AVAHI_PROTO_UNSPEC, "_scanner._tcp",
501141cc406Sopenharmony_ci                                                                   NULL, 0, browse_callback, &data))) {
502141cc406Sopenharmony_ci        DBG(10, "avahi_service_browser_new failed: %s\n",
503141cc406Sopenharmony_ci                              avahi_strerror(avahi_client_errno(client)));
504141cc406Sopenharmony_ci		result = SANE_STATUS_INVAL;
505141cc406Sopenharmony_ci        goto fail;
506141cc406Sopenharmony_ci    }
507141cc406Sopenharmony_ci    my_avahi_simple_poll_loop(simple_poll);
508141cc406Sopenharmony_cifail:
509141cc406Sopenharmony_ci    if (sb)
510141cc406Sopenharmony_ci        avahi_service_browser_free(sb);
511141cc406Sopenharmony_ci    if (client)
512141cc406Sopenharmony_ci        avahi_client_free(client);
513141cc406Sopenharmony_ci    if (simple_poll)
514141cc406Sopenharmony_ci        avahi_simple_poll_free(simple_poll);
515141cc406Sopenharmony_ci
516141cc406Sopenharmony_ci    DBG(10, "epsonds_searchDevices fin\n");
517141cc406Sopenharmony_ci
518141cc406Sopenharmony_ci    return result;
519141cc406Sopenharmony_ci}
520141cc406Sopenharmony_ci#endif
521