diff options
| author | Marcel Holtmann <marcel@holtmann.org> | 2004-05-02 03:36:18 +0000 | 
|---|---|---|
| committer | Marcel Holtmann <marcel@holtmann.org> | 2004-05-02 03:36:18 +0000 | 
| commit | bc085054220d80e9308fe5f4c2260e7ccc06e7e3 (patch) | |
| tree | 0f178396a0abd3b507ca9cc80f5c54c665631c6e | |
| parent | 417d75ccb5aa92384fd75651b6cd8a53193439e4 (diff) | |
Add Bluetooth backend for CUPS
| -rw-r--r-- | Makefile.am | 2 | ||||
| -rw-r--r-- | acinclude.m4 | 65 | ||||
| -rw-r--r-- | configure.in | 4 | ||||
| -rw-r--r-- | cups/Makefile.am | 16 | ||||
| -rw-r--r-- | cups/hcrp.c | 316 | ||||
| -rw-r--r-- | cups/main.c | 188 | ||||
| -rw-r--r-- | cups/sdp.c | 155 | ||||
| -rw-r--r-- | cups/spp.c | 103 | 
8 files changed, 834 insertions, 15 deletions
| diff --git a/Makefile.am b/Makefile.am index d20a2110..1171035e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -2,7 +2,7 @@  #  $Id$  # -SUBDIRS := hcid tools rfcomm sdpd dund pand hidd test scripts pcmcia +SUBDIRS := hcid tools rfcomm sdpd dund pand hidd cups test scripts pcmcia  DISTCLEANFILES = conftest.c conftest diff --git a/acinclude.m4 b/acinclude.m4 index dc885de8..5004e983 100644 --- a/acinclude.m4 +++ b/acinclude.m4 @@ -15,14 +15,18 @@ AC_DEFUN(AC_PREFIX_BLUEZ, [  		if test "$mandir" = '${prefix}/man'; then  			AC_SUBST([mandir], ['${prefix}/share/man'])  		fi + +		bluez_prefix="$ac_default_prefix" +	else +		bluez_prefix="$prefix"  	fi  ])  AC_DEFUN(AC_PATH_BLUEZ, [  	AC_ARG_WITH(bluez, [  --with-bluez=DIR        BlueZ library is installed in DIR], [  		if (test "$withval" = "yes"); then -			bluez_includes=/usr/include -			bluez_libraries=/usr/lib +			bluez_includes=$bluez_prefix/include +			bluez_libraries=$bluez_prefix/lib  		else  			bluez_includes=$withval/include  			bluez_libraries=$withval/lib @@ -62,15 +66,14 @@ AC_DEFUN(AC_PATH_BLUEZ, [  ])  AC_DEFUN(AC_PATH_DBUS, [ -	AC_ARG_ENABLE(dbus, [  --enable-dbus           enable D-BUS support], -		dbus_enable=$enableval, -		dbus_enable=no -	) +	AC_ARG_ENABLE(dbus, [  --enable-dbus           enable D-BUS support], [ +		dbus_enable=$enableval +	])  	AC_ARG_WITH(dbus, [  --with-dbus=DIR         D-BUS library is installed in DIR], [  		if (test "$withval" = "yes"); then -			dbus_includes=/usr/include -			dbus_libraries=/usr/lib +			dbus_includes=$bluez_prefix/include +			dbus_libraries=$bluez_prefix/lib  		else  			dbus_includes=$withval/include  			dbus_libraries=$withval/lib @@ -86,7 +89,7 @@ AC_DEFUN(AC_PATH_DBUS, [  	if test -n "$dbus_includes"; then   		CFLAGS="$CFLAGS -I$dbus_includes -I$dbus_includes/dbus-1.0"  	else -		CFLAGS="$CFLAGS -I/usr/include/dbus-1.0" +		CFLAGS="$CFLAGS -I$bluez_prefix/include/dbus-1.0 -I/usr/include/dbus-1.0"  	fi  	CFLAGS="$CFLAGS -DDBUS_API_SUBJECT_TO_CHANGE" @@ -95,7 +98,7 @@ AC_DEFUN(AC_PATH_DBUS, [  		CFLAGS="$CFLAGS -I$dbus_libraries/dbus-1.0/include"  		LDFLAGS="$LDFLAGS -L$dbus_libraries"  	else -		CFLAGS="$CFLAGS -I/usr/lib/dbus-1.0/include" +		CFLAGS="$CFLAGS -I$bluez_prefix/include/dbus-1.0 -I/usr/lib/dbus-1.0/include"  	fi  	if test "$dbus_enable" = "yes"; then @@ -111,7 +114,7 @@ AC_DEFUN(AC_PATH_DBUS, [  	if test -n "$dbus_includes"; then  		DBUS_INCLUDES="-I$dbus_includes -I$dbus_includes/dbus-1.0"  	else -		DBUS_INCLUDES="-I/usr/include/dbus-1.0" +		DBUS_INCLUDES="-I$bluez_prefix/include/dbus-1.0 -I/usr/include/dbus-1.0"  	fi  	LDFLAGS=$ac_save_LDFLAGS @@ -120,7 +123,7 @@ AC_DEFUN(AC_PATH_DBUS, [  		DBUS_LDFLAGS="-L$dbus_libraries"  		DBUS_LIBS="-L$dbus_libraries $DBUS_LIBS"  	else -		DBUS_INCLUDES="$DBUS_INCLUDES -I/usr/lib/dbus-1.0/include" +		DBUS_INCLUDES="$DBUS_INCLUDES -I$bluez_prefix/include/dbus-1.0 -I/usr/lib/dbus-1.0/include"  	fi  	AC_SUBST(DBUS_INCLUDES) @@ -129,3 +132,41 @@ AC_DEFUN(AC_PATH_DBUS, [  	AM_CONDITIONAL(DBUS, test "$dbus_enable" = "yes")  ]) + +AC_DEFUN(AC_PATH_CUPS, [ +	AC_ARG_ENABLE(cups, [  --enable-cups           enable CUPS support], [ +		cups_enable=$enableval +		cups_prefix=/usr +	]) + +	AC_ARG_WITH(cups, [  --with-cups=DIR         CUPS is installed in DIR], [ +		if (test "$withval" = "yes"); then +			cups_prefix=/usr +		else +			cups_prefix=$withval +		fi +		cups_enable=yes +	]) + +	CUPS_BACKEND_DIR="" + +	if test "$cups_enable" = "yes"; then +		AC_MSG_CHECKING(for CUPS backend directory) + +		if (test -d "$cups_prefix/lib/cups/backend"); then +			CUPS_BACKEND_DIR="$cups_prefix/lib/cups/backend" +		else +			cups_enable=no +		fi + +		if test "$cups_enable" = "yes"; then +			AC_MSG_RESULT($CUPS_BACKEND_DIR) +		else +			AC_MSG_RESULT($cups_enable) +		fi +	fi + +	AC_SUBST(CUPS_BACKEND_DIR) + +	AM_CONDITIONAL(CUPS, test "$cups_enable" = "yes") +]) diff --git a/configure.in b/configure.in index 58b20bf1..fb6db57d 100644 --- a/configure.in +++ b/configure.in @@ -22,7 +22,7 @@ AC_PROG_YACC  AM_PROG_LEX  AC_PATH_BLUEZ -  AC_PATH_DBUS +AC_PATH_CUPS -AC_OUTPUT(Makefile hcid/Makefile tools/Makefile rfcomm/Makefile sdpd/Makefile dund/Makefile pand/Makefile hidd/Makefile test/Makefile scripts/Makefile pcmcia/Makefile) +AC_OUTPUT(Makefile hcid/Makefile tools/Makefile rfcomm/Makefile sdpd/Makefile dund/Makefile pand/Makefile hidd/Makefile cups/Makefile test/Makefile scripts/Makefile pcmcia/Makefile) diff --git a/cups/Makefile.am b/cups/Makefile.am new file mode 100644 index 00000000..2e4ba707 --- /dev/null +++ b/cups/Makefile.am @@ -0,0 +1,16 @@ +# +#  $Id$ +# + +noinst_PROGRAMS = bluetooth + +bluetooth_SOURCES = main.c sdp.c spp.c hcrp.c + +LDFLAGS = @BLUEZ_LIBS@ + +INCLUDES = @BLUEZ_INCLUDES@ + +if CUPS +install-data-local: bluetooth +	$(INSTALL) -D -m 755 $(srcdir)/bluetooth $(DESTDIR)@CUPS_BACKEND_DIR@/bluetooth +endif diff --git a/cups/hcrp.c b/cups/hcrp.c new file mode 100644 index 00000000..f69800a7 --- /dev/null +++ b/cups/hcrp.c @@ -0,0 +1,316 @@ +/* + * + *  BlueZ - Bluetooth protocol stack for Linux + * + *  Copyright (C) 2003-2004  Marcel Holtmann <marcel@holtmann.org> + * + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License version 2 as + *  published by the Free Software Foundation; + * + *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + *  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + *  CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES  + *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN  + *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF  + *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + *  ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,  + *  COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS  + *  SOFTWARE IS DISCLAIMED. + * + * + *  $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <string.h> +#include <signal.h> +#include <sys/socket.h> + +#include <bluetooth/bluetooth.h> +#include <bluetooth/l2cap.h> + +#include <netinet/in.h> + +#define HCRP_PDU_CREDIT_GRANT		0x0001 +#define HCRP_PDU_CREDIT_REQUEST		0x0002 +#define HCRP_PDU_GET_LPT_STATUS		0x0005 + +#define HCRP_STATUS_FEATURE_UNSUPPORTED	0x0000 +#define HCRP_STATUS_SUCCESS		0x0001 +#define HCRP_STATUS_CREDIT_SYNC_ERROR	0x0002 +#define HCRP_STATUS_GENERIC_FAILURE	0xffff + +struct hcrp_pdu_hdr { +	uint16_t pid; +	uint16_t tid; +	uint16_t plen; +} __attribute__ ((packed)); +#define HCRP_PDU_HDR_SIZE 6 + +struct hcrp_credit_grant_cp { +	uint32_t credit; +} __attribute__ ((packed)); +#define HCRP_CREDIT_GRANT_CP_SIZE 4 + +struct hcrp_credit_grant_rp { +	uint16_t status; +} __attribute__ ((packed)); +#define HCRP_CREDIT_GRANT_RP_SIZE 2 + +struct hcrp_credit_request_rp { +	uint16_t status; +	uint32_t credit; +} __attribute__ ((packed)); +#define HCRP_CREDIT_REQUEST_RP_SIZE 6 + +struct hcrp_get_lpt_status_rp { +	uint16_t status; +	uint8_t  lpt_status; +} __attribute__ ((packed)); +#define HCRP_GET_LPT_STATUS_RP_SIZE 3 + +static int hcrp_credit_grant(int sk, uint16_t tid, uint32_t credit) +{ +	struct hcrp_pdu_hdr hdr; +	struct hcrp_credit_grant_cp cp; +	struct hcrp_credit_grant_rp rp; +	unsigned char buf[128]; +	int len; + +	hdr.pid = htons(HCRP_PDU_CREDIT_GRANT); +	hdr.tid = htons(tid); +	hdr.plen = htons(HCRP_CREDIT_GRANT_CP_SIZE); +	cp.credit = credit; +	memcpy(buf, &hdr, HCRP_PDU_HDR_SIZE); +	memcpy(buf + HCRP_PDU_HDR_SIZE, &cp, HCRP_CREDIT_GRANT_CP_SIZE); +	write(sk, buf, HCRP_PDU_HDR_SIZE + HCRP_CREDIT_GRANT_CP_SIZE); + +	len = read(sk, buf, sizeof(buf)); +	memcpy(&hdr, buf, HCRP_PDU_HDR_SIZE); +	memcpy(&rp, buf + HCRP_PDU_HDR_SIZE, HCRP_CREDIT_GRANT_RP_SIZE); + +	if (ntohs(rp.status) != HCRP_STATUS_SUCCESS) { +		errno = EIO; +		return -1; +	} + +	return 0; +} + +static int hcrp_credit_request(int sk, uint16_t tid, uint32_t *credit) +{ +	struct hcrp_pdu_hdr hdr; +	struct hcrp_credit_request_rp rp; +	unsigned char buf[128]; +	int len; + +	hdr.pid = htons(HCRP_PDU_CREDIT_REQUEST); +	hdr.tid = htons(tid); +	hdr.plen = htons(0); +	memcpy(buf, &hdr, HCRP_PDU_HDR_SIZE); +	write(sk, buf, HCRP_PDU_HDR_SIZE); + +	len = read(sk, buf, sizeof(buf)); +	memcpy(&hdr, buf, HCRP_PDU_HDR_SIZE); +	memcpy(&rp, buf + HCRP_PDU_HDR_SIZE, HCRP_CREDIT_REQUEST_RP_SIZE); + +	if (ntohs(rp.status) != HCRP_STATUS_SUCCESS) { +		errno = EIO; +		return -1; +	} + +	if (credit) +		*credit = ntohl(rp.credit); + +	return 0; +} + +static int hcrp_get_lpt_status(int sk, uint16_t tid, uint8_t *lpt_status) +{ +	struct hcrp_pdu_hdr hdr; +	struct hcrp_get_lpt_status_rp rp; +	unsigned char buf[128]; +	int len; + +	hdr.pid = htons(HCRP_PDU_GET_LPT_STATUS); +	hdr.tid = htons(tid); +	hdr.plen = htons(0); +	memcpy(buf, &hdr, HCRP_PDU_HDR_SIZE); +	write(sk, buf, HCRP_PDU_HDR_SIZE); + +	len = read(sk, buf, sizeof(buf)); +	memcpy(&hdr, buf, HCRP_PDU_HDR_SIZE); +	memcpy(&rp, buf + HCRP_PDU_HDR_SIZE, HCRP_GET_LPT_STATUS_RP_SIZE); + +	if (ntohs(rp.status) != HCRP_STATUS_SUCCESS) { +		errno = EIO; +		return -1; +	} + +	if (lpt_status) +		*lpt_status = rp.lpt_status; + +	return 0; +} + +static inline int hcrp_get_next_tid(int tid) +{ +	if (tid > 0xf000) +		return 0; +	else +		return tid + 1; +} + +int hcrp_print(bdaddr_t *src, bdaddr_t *dst, unsigned short ctrl_psm, unsigned short data_psm, int fd, int copies) +{ +	struct sockaddr_l2 addr; +	struct l2cap_options opts; +	unsigned char buf[2048]; +	int i, size, ctrl_sk, data_sk, mtu, count, len, timeout = 0; +	uint8_t status; +	uint16_t tid = 0; +	uint32_t tmp, credit = 0; + +	if ((ctrl_sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0) { +		perror("ERROR: Can't create socket"); +		return 1; +	} + +	addr.l2_family = AF_BLUETOOTH; +	bacpy(&addr.l2_bdaddr, src); +	addr.l2_psm = 0; + +	if (bind(ctrl_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { +		perror("ERROR: Can't bind socket"); +		close(ctrl_sk); +		return 1; +	} + +	addr.l2_family = AF_BLUETOOTH; +	bacpy(&addr.l2_bdaddr, dst); +	addr.l2_psm = htobs(ctrl_psm); + +	if (connect(ctrl_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { +		perror("ERROR: Can't connect to device"); +		close(ctrl_sk); +		return 1; +	} + +	if ((data_sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0) { +		perror("ERROR: Can't create socket"); +		close(ctrl_sk); +		return 1; +	} + +	addr.l2_family = AF_BLUETOOTH; +	bacpy(&addr.l2_bdaddr, src); +	addr.l2_psm = 0; + +	if (bind(data_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { +		perror("ERROR: Can't bind socket"); +		close(data_sk); +		close(ctrl_sk); +		return 1; +	} + +	addr.l2_family = AF_BLUETOOTH; +	bacpy(&addr.l2_bdaddr, dst); +	addr.l2_psm = htobs(data_psm); + +	if (connect(data_sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { +		perror("ERROR: Can't connect to device"); +		close(data_sk); +		close(ctrl_sk); +		return 1; +	} + +	size = sizeof(opts); + +	if (getsockopt(data_sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, &size) < 0) { +		perror("ERROR: Can't get socket options"); +		close(data_sk); +		close(ctrl_sk); +		return 1; +	} + +	mtu = opts.omtu; + +	/* Ignore SIGTERM signals if printing from stdin */ +	if (fd == 0) { +#ifdef HAVE_SIGSET +		sigset(SIGTERM, SIG_IGN); +#elif defined(HAVE_SIGACTION) +		memset(&action, 0, sizeof(action)); +		sigemptyset(&action.sa_mask); +		action.sa_handler = SIG_IGN; +		sigaction(SIGTERM, &action, NULL); +#else +		signal(SIGTERM, SIG_IGN); +#endif /* HAVE_SIGSET */ +	} + +	tid = hcrp_get_next_tid(tid); +	if (hcrp_credit_grant(ctrl_sk, tid, 0) < 0) { +		fprintf(stderr, "ERROR: Can't grant initial credits\n"); +		close(data_sk); +		close(ctrl_sk); +		return 1; +	} + +	for (i = 0; i < copies; i++) { + +		if (fd != 0) { +			fprintf(stderr, "PAGE: 1 1\n"); +			lseek(fd, 0, SEEK_SET); +		} + +		while (1) { +			if (credit < mtu) { +				tid = hcrp_get_next_tid(tid); +				if (!hcrp_credit_request(ctrl_sk, tid, &tmp)) { +					credit += tmp; +					timeout = 0; +				} +			} + +			if (!credit) { +				if (timeout++ > 300) { +					tid = hcrp_get_next_tid(tid); +					if (!hcrp_get_lpt_status(ctrl_sk, tid, &status)) +						fprintf(stderr, "ERROR: LPT status 0x%02x\n", status); +					break; +				} + +				sleep(1); +				continue; +			} + +			count = read(fd, buf, (credit > mtu) ? mtu : credit); +			if (count <= 0) +				break; + +			len = write(data_sk, buf, count); +			if (len != count) +				fprintf(stderr, "ERROR: Can't send complete data\n"); + +			credit -= len; +		} + +	} + +	close(data_sk); +	close(ctrl_sk); + +	return 0; +} diff --git a/cups/main.c b/cups/main.c new file mode 100644 index 00000000..352ea4ea --- /dev/null +++ b/cups/main.c @@ -0,0 +1,188 @@ +/* + * + *  BlueZ - Bluetooth protocol stack for Linux + * + *  Copyright (C) 2003-2004  Marcel Holtmann <marcel@holtmann.org> + * + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License version 2 as + *  published by the Free Software Foundation; + * + *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + *  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + *  CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES  + *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN  + *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF  + *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + *  ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,  + *  COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS  + *  SOFTWARE IS DISCLAIMED. + * + * + *  $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> + +#include <bluetooth/bluetooth.h> +#include <bluetooth/sdp.h> +#include <bluetooth/sdp_lib.h> + +int sdp_search_spp(sdp_session_t *sdp, uint8_t *channel); +int sdp_search_hcrp(sdp_session_t *sdp, unsigned short *ctrl_psm, unsigned short *data_psm); + +int spp_print(bdaddr_t *src, bdaddr_t *dst, uint8_t channel, int fd, int copies); +int hcrp_print(bdaddr_t *src, bdaddr_t *dst, unsigned short ctrl_psm, unsigned short data_psm, int fd, int copies); + +static void list_devices(void) +{ +} + +/* + *  Usage: printer-uri job-id user title copies options [file] + * + */ + +int main(int argc, char *argv[]) +{ +	sdp_session_t *sdp; +	bdaddr_t bdaddr; +	unsigned short ctrl_psm, data_psm; +	uint8_t channel, b[6]; +	char *ptr, str[3], device[18], service[12]; +	int i, err, fd, copies, proto; + +	/* Make sure status messages are not buffered */ +	setbuf(stderr, NULL); + +	/* Ignore SIGPIPE signals */ +#ifdef HAVE_SIGSET +	sigset(SIGPIPE, SIG_IGN); +#elif defined(HAVE_SIGACTION) +	memset(&action, 0, sizeof(action)); +	action.sa_handler = SIG_IGN; +	sigaction(SIGPIPE, &action, NULL); +#else +	signal(SIGPIPE, SIG_IGN); +#endif /* HAVE_SIGSET */ + +	if (argc == 1) { +		list_devices(); +		return 0; +	} + +	if (argc < 6 || argc > 7) { +		fprintf(stderr, "Usage: bluetooth job-id user title copies options [file]\n"); +		return 1; +	} + +	if (argc == 6) { +		fd = 0; +		copies = 1; +	} else { +		if ((fd = open(argv[6], O_RDONLY)) < 0) { +			perror("ERROR: Unable to open print file"); +			return 1; +		} +		copies = atoi(argv[4]); +	} + +	if (strncasecmp(argv[0], "bluetooth://", 12)) { +		fprintf(stderr, "ERROR: No device URI found\n"); +		return 1; +	} + +	ptr = argv[0] + 12; +	for (i = 0; i < 6; i++) { +		strncpy(str, ptr, 2); +		b[i] = (uint8_t) strtol(str, NULL, 16); +		ptr += 2; +	} +	sprintf(device, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X", +		b[0], b[1], b[2], b[3], b[4], b[5]); + +	str2ba(device, &bdaddr); + +	ptr = strchr(ptr, '/'); +	if (ptr) { +		strncpy(service, ptr + 1, 12); + +		if (!strncasecmp(ptr + 1, "spp", 3)) +			proto = 1; +		else if (!strncasecmp(ptr + 1, "hcrp", 4)) +			proto = 2; +		else +			proto = 0; +	} else { +		strcpy(service, "auto"); +		proto = 0; +	} + +	fprintf(stderr, "DEBUG: %s device %s service %s fd %d copies %d\n", +			argv[0], device, service, fd, copies); + +	sdp = sdp_connect(BDADDR_ANY, &bdaddr, 0 /*SDP_RETRY_IF_BUSY*/); +	if (!sdp) { +		fprintf(stderr, "ERROR: Can't open Bluetooth connection\n"); +		return 1; +	} + +	switch (proto) { +	case 1: +		err = sdp_search_spp(sdp, &channel); +		break; +	case 2: +		err = sdp_search_hcrp(sdp, &ctrl_psm, &data_psm); +		break; +	default: +		proto = 2; +		err = sdp_search_hcrp(sdp, &ctrl_psm, &data_psm); +		if (err) { +			proto = 1; +			err = sdp_search_spp(sdp, &channel); +		} +		break; +	} + +	sdp_close(sdp); + +	if (err) { +		fprintf(stderr, "ERROR: Can't get service information\n"); +		return 1; +	} + +	switch (proto) { +	case 1: +		err = spp_print(BDADDR_ANY, &bdaddr, channel, fd, copies); +		break; +	case 2: +		err = hcrp_print(BDADDR_ANY, &bdaddr, ctrl_psm, data_psm, fd, copies); +		break; +	default: +		err = 1; +		fprintf(stderr, "ERROR: Unsupported protocol\n"); +		break; +	} + +	if (fd != 0) +		close(fd); + +	if (!err) +		fprintf(stderr, "INFO: Ready to print\n"); + +	return err; +} diff --git a/cups/sdp.c b/cups/sdp.c new file mode 100644 index 00000000..7491ab1f --- /dev/null +++ b/cups/sdp.c @@ -0,0 +1,155 @@ +/* + * + *  BlueZ - Bluetooth protocol stack for Linux + * + *  Copyright (C) 2003-2004  Marcel Holtmann <marcel@holtmann.org> + * + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License version 2 as + *  published by the Free Software Foundation; + * + *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + *  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + *  CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES  + *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN  + *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF  + *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + *  ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,  + *  COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS  + *  SOFTWARE IS DISCLAIMED. + * + * + *  $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <signal.h> +#include <sys/socket.h> + +#include <bluetooth/bluetooth.h> +#include <bluetooth/sdp.h> +#include <bluetooth/sdp_lib.h> + +#define HCRP_CTRL_UUID		0x0012 +#define HCRP_DATA_UUID		0x0014 + +#define HCR_PROFILE_ID		0x1125 +#define HCR_PRINT_SVCLASS_ID	0x1126 + +#define SDP_ATTR_ADD_PROTO_DESC_LIST	0x000d + +static int sdp_get_add_access_protos(const sdp_record_t *rec, sdp_list_t **pap) +{ +	sdp_data_t *pdlist, *curr; +	sdp_list_t *ap = 0; + +	pdlist = sdp_data_get(rec, SDP_ATTR_ADD_PROTO_DESC_LIST); +	if (pdlist == NULL) { +		errno = ENODATA; +		return -1; +	} + +	pdlist = pdlist->val.dataseq; + +	for (; pdlist; pdlist = pdlist->next) { +		sdp_list_t *pds = 0; +		for (curr = pdlist->val.dataseq; curr; curr = curr->next) +			pds = sdp_list_append(pds, curr->val.dataseq); +		ap = sdp_list_append(ap, pds); +	} + +	*pap = ap; + +	return 0; +} + +int sdp_search_hcrp(sdp_session_t *sdp, unsigned short *ctrl_psm, unsigned short *data_psm) +{ +	sdp_list_t *srch, *attrs, *rsp; +	uuid_t svclass; +	uint16_t attr1, attr2; +	int err; + +	if (!sdp) +		return -1; + +	sdp_uuid16_create(&svclass, HCR_PRINT_SVCLASS_ID); +	srch = sdp_list_append(NULL, &svclass); + +	attr1 = SDP_ATTR_PROTO_DESC_LIST; +	attrs = sdp_list_append(NULL, &attr1); +	attr2 = SDP_ATTR_ADD_PROTO_DESC_LIST; +	attrs = sdp_list_append(attrs, &attr2); + +	err = sdp_service_search_attr_req(sdp, srch, SDP_ATTR_REQ_INDIVIDUAL, attrs, &rsp); +	if (err) +		return -1; + +	for (; rsp; rsp = rsp->next) { +		sdp_record_t *rec = (sdp_record_t *) rsp->data; +		sdp_list_t *protos; + +		if (!sdp_get_access_protos(rec, &protos)) { +			unsigned short psm = sdp_get_proto_port(protos, L2CAP_UUID); +			if (psm > 0) { +				*ctrl_psm = psm; +			} +		} + +		if (!sdp_get_add_access_protos(rec, &protos)) { +			unsigned short psm = sdp_get_proto_port(protos, L2CAP_UUID); +			if (psm > 0 && *ctrl_psm > 0) { +				*data_psm = psm; +				return 0; +			} +		} +	} + +	return -1; +} + +int sdp_search_spp(sdp_session_t *sdp, uint8_t *channel) +{ +	sdp_list_t *srch, *attrs, *rsp; +	uuid_t svclass; +	uint16_t attr; +	int err; + +	if (!sdp) +		return -1; + +	sdp_uuid16_create(&svclass, SERIAL_PORT_SVCLASS_ID); +	srch = sdp_list_append(NULL, &svclass); + +	attr = SDP_ATTR_PROTO_DESC_LIST; +	attrs = sdp_list_append(NULL, &attr); + +	err = sdp_service_search_attr_req(sdp, srch, SDP_ATTR_REQ_INDIVIDUAL, attrs, &rsp); +	if (err) +		return -1; + +	for (; rsp; rsp = rsp->next) { +		sdp_record_t *rec = (sdp_record_t *) rsp->data; +		sdp_list_t *protos; + +		if (!sdp_get_access_protos(rec, &protos)) { +			uint8_t ch = sdp_get_proto_port(protos, RFCOMM_UUID); +			if (ch > 0) { +				*channel = ch; +				return 0; +			} +		} +	} + +	return -1; +} diff --git a/cups/spp.c b/cups/spp.c new file mode 100644 index 00000000..ec8fcdd5 --- /dev/null +++ b/cups/spp.c @@ -0,0 +1,103 @@ +/* + * + *  BlueZ - Bluetooth protocol stack for Linux + * + *  Copyright (C) 2003-2004  Marcel Holtmann <marcel@holtmann.org> + * + * + *  This program is free software; you can redistribute it and/or modify + *  it under the terms of the GNU General Public License version 2 as + *  published by the Free Software Foundation; + * + *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + *  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + *  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. + *  IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) AND AUTHOR(S) BE LIABLE FOR ANY + *  CLAIM, OR ANY SPECIAL INDIRECT OR CONSEQUENTIAL DAMAGES, OR ANY DAMAGES  + *  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN  + *  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF  + *  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + *  ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,  + *  COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS  + *  SOFTWARE IS DISCLAIMED. + * + * + *  $Id$ + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <errno.h> +#include <unistd.h> +#include <signal.h> +#include <sys/socket.h> + +#include <bluetooth/bluetooth.h> +#include <bluetooth/rfcomm.h> + +int spp_print(bdaddr_t *src, bdaddr_t *dst, uint8_t channel, int fd, int copies) +{ +	struct sockaddr_rc addr; +	unsigned char buf[2048]; +	int i, sk, len; + +	if ((sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0) { +		perror("ERROR: Can't create socket"); +		return 1; +	} + +	addr.rc_family = AF_BLUETOOTH; +	bacpy(&addr.rc_bdaddr, src); +	addr.rc_channel = 0; + +	if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { +		perror("ERROR: Can't bind socket"); +		close(sk); +		return 1; +	} + +	addr.rc_family = AF_BLUETOOTH; +	bacpy(&addr.rc_bdaddr, dst); +	addr.rc_channel = channel; + +	if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) { +		perror("ERROR: Can't connect to device"); +		close(sk); +		return 1; +	} + +	/* Ignore SIGTERM signals if printing from stdin */ +	if (fd == 0) { +#ifdef HAVE_SIGSET +		sigset(SIGTERM, SIG_IGN); +#elif defined(HAVE_SIGACTION) +		memset(&action, 0, sizeof(action)); +		sigemptyset(&action.sa_mask); +		action.sa_handler = SIG_IGN; +		sigaction(SIGTERM, &action, NULL); +#else +		signal(SIGTERM, SIG_IGN); +#endif /* HAVE_SIGSET */ +	} + +	for (i = 0; i < copies; i++) { + +		if (fd != 0) { +			fprintf(stderr, "PAGE: 1 1\n"); +			lseek(fd, 0, SEEK_SET); +		} + +		while ((len = read(fd, buf, sizeof(buf))) > 0) { +			write(sk, buf, len); +		} + +	} + +	close(sk); + +	return 0; +} | 
