* [Bluez-devel] CUPS plugin discovery bits
@ 2007-05-23 15:24 Bastien Nocera
2007-05-23 15:51 ` Marcel Holtmann
0 siblings, 1 reply; 21+ messages in thread
From: Bastien Nocera @ 2007-05-23 15:24 UTC (permalink / raw)
To: bluez-devel; +Cc: twaugh
[-- Attachment #1: Type: text/plain, Size: 1048 bytes --]
Heya,
Here's a patch against CVS bluez-utils to add discovery to the CUPS
backend. With this, it means that most CUPS front-end will be able to
list visible printers when adding a new one, be it through the web
interface or other front-ends (like Fedora' system-config-printer).
It adds D-Bus and glib as dependencies for the backend (not that it
matters that much...).
There are 2 things left:
- First, printer model/make detection. Does anyone know how this works
over HCRP or SPP? I would think that it would be something accessible
over HCRP as some other OSes are able to autodetect the necessary
printer driver (IEEE1284?).
Links to the specs appreciated.
- Secondly, does this detection require the devices to be paired? If it
does, then I'd want to add something like "--identify" to the bluetooth
backend so that front-ends can get make/model _after_ the printer has
been added to the queues and paired (if we did this during discovery we
might get flooded in auths).
Comments welcome.
Cheers
--
Bastien Nocera <hadess@hadess.net>
[-- Attachment #2: bluez-utils-cups-printer-listing.patch --]
[-- Type: text/x-patch, Size: 9296 bytes --]
Index: acinclude.m4
===================================================================
RCS file: /cvsroot/bluez/utils/acinclude.m4,v
retrieving revision 1.107
diff -u -p -r1.107 acinclude.m4
--- acinclude.m4 8 Apr 2007 19:56:52 -0000 1.107
+++ acinclude.m4 23 May 2007 15:11:31 -0000
@@ -78,6 +78,8 @@ AC_DEFUN([AC_PATH_GLIB], [
PKG_CHECK_MODULES(GLIB, glib-2.0, glib_found=yes, glib_found=no)
AC_SUBST(GLIB_CFLAGS)
AC_SUBST(GLIB_LIBS)
+ GLIB_GENMARSHAL=`$PKG_CONFIG --variable=glib_genmarshal glib-2.0`
+ AC_SUBST(GLIB_GENMARSHAL)
])
AC_DEFUN([AC_PATH_DBUS], [
Index: cups/Makefile.am
===================================================================
RCS file: /cvsroot/bluez/utils/cups/Makefile.am,v
retrieving revision 1.9
diff -u -p -r1.9 Makefile.am
--- cups/Makefile.am 20 Aug 2006 02:21:03 -0000 1.9
+++ cups/Makefile.am 23 May 2007 15:11:31 -0000
@@ -7,9 +7,19 @@ else
noinst_PROGRAMS = bluetooth
endif
-bluetooth_SOURCES = main.c sdp.c spp.c hcrp.c
-bluetooth_LDADD = @BLUEZ_LIBS@
+MARSHAL_FILES = bluez-cups-marshal.h bluez-cups-marshal.c
-AM_CFLAGS = @BLUEZ_CFLAGS@
+bluetooth_SOURCES = main.c sdp.c spp.c hcrp.c $(MARSHAL_FILES)
+bluetooth_LDADD = @DBUS_GLIB_LIBS@ @BLUEZ_LIBS@
-MAINTAINERCLEANFILES = Makefile.in
+bluez-cups-marshal.h: bluez-cups-marshal.list
+ $(GLIB_GENMARSHAL) --prefix=bluez_cups_marshal $< --header > $@
+bluez-cups-marshal.c: bluez-cups-marshal.list
+ $(GLIB_GENMARSHAL) --prefix=bluez_cups_marshal $< --body > $@
+main.c: $(MARSHAL_FILES)
+
+AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_GLIB_CFLAGS@
+
+MAINTAINERCLEANFILES = Makefile.in $(MARSHAL_FILES)
+CLEANFILES = $(MARSHAL_FILES)
+EXTRA_DIST = bluez-cups-marshal.list
Index: cups/main.c
===================================================================
RCS file: /cvsroot/bluez/utils/cups/main.c,v
retrieving revision 1.6
diff -u -p -r1.6 main.c
--- cups/main.c 3 Jan 2006 13:28:57 -0000 1.6
+++ cups/main.c 23 May 2007 15:11:31 -0000
@@ -38,12 +38,257 @@
#include <bluetooth/sdp.h>
#include <bluetooth/sdp_lib.h>
+#include <dbus/dbus-glib.h>
+#include <glib/gi18n.h>
+#include "bluez-cups-marshal.h"
+
extern int sdp_search_spp(sdp_session_t *sdp, uint8_t *channel);
extern int sdp_search_hcrp(sdp_session_t *sdp, unsigned short *ctrl_psm, unsigned short *data_psm);
extern int spp_print(bdaddr_t *src, bdaddr_t *dst, uint8_t channel, int fd, int copies);
extern int hcrp_print(bdaddr_t *src, bdaddr_t *dst, unsigned short ctrl_psm, unsigned short data_psm, int fd, int copies);
+#define PRINTER_SERVICE_CLASS_NAME "printer"
+
+typedef struct {
+ char *bdaddr;
+ char *name;
+} BluezCupsDevice;
+
+static GList *device_list = NULL;
+static GMainLoop *loop = NULL;
+
+static void
+add_device_to_list(const char *name, const char *bdaddr)
+{
+ BluezCupsDevice *device;
+ GList *l;
+
+ /* Look for the device in the list */
+ for (l = device_list; l != NULL; l = l->next) {
+ device = (BluezCupsDevice *) l->data;
+
+ if (strcmp(device->bdaddr, bdaddr) == 0) {
+ g_free(device->name);
+ device->name = g_strdup(name);
+ return;
+ }
+ }
+
+ /* Or add it to the list if it's not there */
+ device = g_new0(BluezCupsDevice, 1);
+ device->bdaddr = g_strdup(bdaddr);
+ device->name = g_strdup(name);
+
+ device_list = g_list_prepend(device_list, device);
+}
+
+static void
+print_printer_details(const char *name, const char *bdaddr)
+{
+ char *uri, *escaped;
+
+ escaped = g_strdelimit(g_strdup(name), "\"", '\'');
+
+ uri = g_strdup_printf("bluetooth://%c%c%c%c%c%c%c%c%c%c%c%c",
+ bdaddr[0], bdaddr[1],
+ bdaddr[3], bdaddr[4],
+ bdaddr[6], bdaddr[7],
+ bdaddr[9], bdaddr[10],
+ bdaddr[12], bdaddr[13],
+ bdaddr[15], bdaddr[16]);
+ g_print("network %s \"Unknown\" \"%s (Bluetooth)\"\n", uri, escaped);
+ g_free(escaped);
+}
+
+static void
+discovery_started(DBusGProxy *object, gpointer user_data)
+{
+ /* Discovery started! */
+}
+
+static void
+remote_device_found(DBusGProxy *object,
+ const char *bdaddr, guint class, int rssi,
+ gpointer user_data)
+{
+ GError *e = NULL;
+ const char *name;
+
+ dbus_g_proxy_call(object, "GetRemoteName", &e,
+ G_TYPE_STRING, bdaddr, G_TYPE_INVALID,
+ G_TYPE_STRING, &name, G_TYPE_INVALID);
+ if(e != NULL) {
+ const char *name;
+
+ name = dbus_g_error_get_name(e);
+ if (g_str_equal(name, "org.bluez.Error.RequestDeferred") != FALSE) {
+ add_device_to_list(NULL, bdaddr);
+ }
+ g_error_free(e);
+ } else {
+ add_device_to_list(name, bdaddr);
+ }
+}
+
+static void
+remote_name_updated(DBusGProxy *object,
+ const char *bdaddr, const char *name,
+ gpointer user_data)
+{
+ add_device_to_list(name, bdaddr);
+}
+
+static gboolean
+device_is_printer(DBusGProxy *object, const char *bdaddr)
+{
+ GError *e = NULL;
+ char *class;
+
+ dbus_g_proxy_call(object, "GetRemoteMinorClass", &e,
+ G_TYPE_STRING, bdaddr, G_TYPE_INVALID,
+ G_TYPE_STRING, &class, G_TYPE_INVALID);
+
+ if (e == NULL && g_str_equal(class, PRINTER_SERVICE_CLASS_NAME)) {
+ return TRUE;
+ } else if(e != NULL) {
+ g_error_free(e);
+ }
+
+ return FALSE;
+}
+
+static void
+discovery_completed(DBusGProxy *object, gpointer user_data)
+{
+ GList *l;
+
+ for (l = device_list; l != NULL; l = l->next) {
+ BluezCupsDevice *device = (BluezCupsDevice *) l->data;
+
+ if (device_is_printer(object, device->bdaddr))
+ print_printer_details(device->name, device->bdaddr);
+ g_free(device->name);
+ g_free(device->bdaddr);
+ g_free(device);
+ }
+
+ g_list_free(device_list);
+ device_list = NULL;
+
+ g_main_loop_quit(loop);
+}
+
+static void
+remote_device_disappeared(DBusGProxy *object,
+ const char *bdaddr,
+ gpointer user_data)
+{
+ GList *l;
+
+ for (l = device_list; l != NULL; l = l->next) {
+ BluezCupsDevice *device = (BluezCupsDevice *) l->data;
+
+ if (strcmp(device->bdaddr, bdaddr) == 0) {
+ g_free(device->name);
+ g_free(device->bdaddr);
+ g_free(device);
+ device_list = g_list_delete_link(device_list, l);
+ return;
+ }
+ }
+}
+
+static void
+list_printers(void)
+{
+ /* 1. Connect to the bus
+ * 2. Get the manager
+ * 3. Get the default adapter
+ * 4. Get a list of devices
+ * 5. Get the class of each device
+ * 6. Print the details from each printer device
+ */
+ GError *e = NULL;
+ DBusGConnection *conn;
+ DBusGProxy *object;
+ const char *adapter;
+
+ g_type_init();
+
+ conn = dbus_g_bus_get(DBUS_BUS_SYSTEM, &e);
+ if (e != NULL) {
+ g_warning("Couldn't connect to bus: %s", e->message);
+ g_error_free(e);
+ return;
+ }
+
+ object = dbus_g_proxy_new_for_name(conn, "org.bluez",
+ "/org/bluez", "org.bluez.Manager");
+ dbus_g_proxy_call(object, "DefaultAdapter", &e,
+ G_TYPE_INVALID, G_TYPE_STRING, &adapter, G_TYPE_INVALID);
+ if (e != NULL) {
+ const char *name;
+
+ name = dbus_g_error_get_name(e);
+
+ /* No adapter */
+ if (g_str_equal(name, "org.bluez.Error.NoSuchAdapter") != FALSE) {
+ g_error_free(e);
+ return;
+ }
+
+ g_warning("Couldn't get default bluetooth adapter: %s",
+ e->message);
+ g_error_free(e);
+ return;
+ }
+
+ object = dbus_g_proxy_new_for_name(conn, "org.bluez",
+ adapter, "org.bluez.Adapter");
+
+ dbus_g_proxy_add_signal(object, "DiscoveryStarted", G_TYPE_INVALID);
+ dbus_g_proxy_connect_signal(object, "DiscoveryStarted",
+ G_CALLBACK(discovery_started), NULL, NULL);
+
+ dbus_g_object_register_marshaller(bluez_cups_marshal_VOID__STRING_UINT_INT,
+ G_TYPE_NONE, G_TYPE_STRING, G_TYPE_UINT,
+ G_TYPE_INT, G_TYPE_INVALID);
+ dbus_g_proxy_add_signal(object, "RemoteDeviceFound",
+ G_TYPE_STRING, G_TYPE_UINT, G_TYPE_INT, G_TYPE_INVALID);
+ dbus_g_proxy_connect_signal(object, "RemoteDeviceFound",
+ G_CALLBACK(remote_device_found), NULL, NULL);
+
+ dbus_g_object_register_marshaller(bluez_cups_marshal_VOID__STRING_STRING,
+ G_TYPE_NONE, G_TYPE_STRING,
+ G_TYPE_STRING, G_TYPE_INVALID);
+ dbus_g_proxy_add_signal(object, "RemoteNameUpdated",
+ G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID);
+ dbus_g_proxy_connect_signal(object, "RemoteNameUpdated",
+ G_CALLBACK(remote_name_updated), NULL, NULL);
+
+ dbus_g_proxy_add_signal(object, "RemoteDeviceDisappeared",
+ G_TYPE_STRING, G_TYPE_INVALID);
+ dbus_g_proxy_connect_signal(object, "RemoteDeviceDisappeared",
+ G_CALLBACK(remote_device_disappeared), NULL, NULL);
+
+ dbus_g_proxy_add_signal(object, "DiscoveryCompleted", G_TYPE_INVALID);
+ dbus_g_proxy_connect_signal(object, "DiscoveryCompleted",
+ G_CALLBACK(discovery_completed), NULL, NULL);
+
+ dbus_g_proxy_call(object, "DiscoverDevices", &e,
+ G_TYPE_INVALID, G_TYPE_INVALID);
+ if (e != NULL) {
+ g_warning("Couldn't start discovery: %s: %s",
+ dbus_g_error_get_name(e), e->message);
+ g_error_free(e);
+ return;
+ }
+
+ loop = g_main_loop_new(NULL, TRUE);
+ g_main_loop_run(loop);
+}
+
/*
* Usage: printer-uri job-id user title copies options [file]
*
@@ -73,7 +318,7 @@ int main(int argc, char *argv[])
#endif /* HAVE_SIGSET */
if (argc == 1) {
- puts("network bluetooth \"Unknown\" \"Bluetooth printer\"");
+ list_printers();
return 0;
}
--- /dev/null 2007-05-22 10:58:00.668244955 +0100
+++ cups/bluez-cups-marshal.list 2007-05-23 11:51:07.000000000 +0100
@@ -0,0 +1,2 @@
+VOID:STRING,UINT,INT
+VOID:STRING,STRING
[-- Attachment #3: Type: text/plain, Size: 286 bytes --]
-------------------------------------------------------------------------
This SF.net email is sponsored by DB2 Express
Download DB2 Express C - the FREE version of DB2 express and take
control of your XML. No limits. Just data. Click to get it now.
http://sourceforge.net/powerbar/db2/
[-- Attachment #4: Type: text/plain, Size: 164 bytes --]
_______________________________________________
Bluez-devel mailing list
Bluez-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-devel
^ permalink raw reply [flat|nested] 21+ messages in thread* Re: [Bluez-devel] CUPS plugin discovery bits 2007-05-23 15:24 [Bluez-devel] CUPS plugin discovery bits Bastien Nocera @ 2007-05-23 15:51 ` Marcel Holtmann 2007-05-23 15:57 ` Tim Waugh ` (2 more replies) 0 siblings, 3 replies; 21+ messages in thread From: Marcel Holtmann @ 2007-05-23 15:51 UTC (permalink / raw) To: BlueZ development; +Cc: twaugh Hi Bastien, > Here's a patch against CVS bluez-utils to add discovery to the CUPS > backend. With this, it means that most CUPS front-end will be able to > list visible printers when adding a new one, be it through the web > interface or other front-ends (like Fedora' system-config-printer). > > It adds D-Bus and glib as dependencies for the backend (not that it > matters that much...). it actually does. We provide an eGlib for embedded systems and so when compiled with GLib, we only use that function subset. And second you use the GLib D-Bus bindings. I am not willing to create these dependencies for a "daemon" package. Another small thing is that DisocverDevices() will automatically take care of the name resolving for you. So no need to call GetRemoteName(). You will get the RemoteNameUpdated() signal. The thing that worries me is when you start CUPS it will list through all backends and make them list. So on every boot the system will scan for devices in range and that can slow down the system boot. So this might not be a good idea. Actually that is the reason why we wanna go for a printing service in the future. Regards Marcel ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ _______________________________________________ Bluez-devel mailing list Bluez-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/bluez-devel ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [Bluez-devel] CUPS plugin discovery bits 2007-05-23 15:51 ` Marcel Holtmann @ 2007-05-23 15:57 ` Tim Waugh 2007-05-23 16:15 ` Bastien Nocera 2007-05-24 15:03 ` Bastien Nocera 2 siblings, 0 replies; 21+ messages in thread From: Tim Waugh @ 2007-05-23 15:57 UTC (permalink / raw) To: Marcel Holtmann; +Cc: BlueZ development [-- Attachment #1: Type: text/plain, Size: 506 bytes --] On Wed, 2007-05-23 at 17:51 +0200, Marcel Holtmann wrote: > The thing that worries me is when you start CUPS it will list through > all backends and make them list. So on every boot the system will scan > for devices in range and that can slow down the system boot. So this > might not be a good idea. Actually that is the reason why we wanna go > for a printing service in the future. This hasn't been true since CUPS 1.1.x. In CUPS 1.2.x device discovery is performed on demand. Tim. */ [-- Attachment #2: This is a digitally signed message part --] [-- Type: application/pgp-signature, Size: 189 bytes --] ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [Bluez-devel] CUPS plugin discovery bits 2007-05-23 15:51 ` Marcel Holtmann 2007-05-23 15:57 ` Tim Waugh @ 2007-05-23 16:15 ` Bastien Nocera 2007-05-23 16:26 ` Bastien Nocera 2007-05-24 15:03 ` Bastien Nocera 2 siblings, 1 reply; 21+ messages in thread From: Bastien Nocera @ 2007-05-23 16:15 UTC (permalink / raw) To: BlueZ development; +Cc: twaugh On Wed, 2007-05-23 at 17:51 +0200, Marcel Holtmann wrote: > Hi Bastien, > > > Here's a patch against CVS bluez-utils to add discovery to the CUPS > > backend. With this, it means that most CUPS front-end will be able to > > list visible printers when adding a new one, be it through the web > > interface or other front-ends (like Fedora' system-config-printer). > > > > It adds D-Bus and glib as dependencies for the backend (not that it > > matters that much...). > > it actually does. We provide an eGlib for embedded systems and so when > compiled with GLib, we only use that function subset. > > And second you use the GLib D-Bus bindings. I am not willing to create > these dependencies for a "daemon" package. It's not a "daemon", as in, it won't be running all the time. It's only a small short-lived program. Should I make it compile-time dependency? > Another small thing is that DisocverDevices() will automatically take > care of the name resolving for you. So no need to call GetRemoteName(). > You will get the RemoteNameUpdated() signal. Cool, I'll clean up the code. > The thing that worries me is when you start CUPS it will list through > all backends and make them list. So on every boot the system will scan > for devices in range and that can slow down the system boot. So this > might not be a good idea. Actually that is the reason why we wanna go > for a printing service in the future. As Tim mentioned, CUPS won't do the requests on startup, but on demand. As for the printing service, what would it actually buy us, ie. which feature would you have in it that aren't possible in the backend? -- Bastien Nocera <hadess@hadess.net> ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ _______________________________________________ Bluez-devel mailing list Bluez-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/bluez-devel ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [Bluez-devel] CUPS plugin discovery bits 2007-05-23 16:15 ` Bastien Nocera @ 2007-05-23 16:26 ` Bastien Nocera 2007-05-23 16:56 ` Johan Hedberg 0 siblings, 1 reply; 21+ messages in thread From: Bastien Nocera @ 2007-05-23 16:26 UTC (permalink / raw) To: BlueZ development; +Cc: twaugh [-- Attachment #1: Type: text/plain, Size: 424 bytes --] On Wed, 2007-05-23 at 17:15 +0100, Bastien Nocera wrote: > On Wed, 2007-05-23 at 17:51 +0200, Marcel Holtmann wrote: <snip> > > Another small thing is that DisocverDevices() will automatically take > > care of the name resolving for you. So no need to call GetRemoteName(). > > You will get the RemoteNameUpdated() signal. > > Cool, I'll clean up the code. Updated patch attached. -- Bastien Nocera <hadess@hadess.net> [-- Attachment #2: bluez-utils-cups-printer-listing-2.patch --] [-- Type: text/x-patch, Size: 9087 bytes --] Index: acinclude.m4 =================================================================== RCS file: /cvsroot/bluez/utils/acinclude.m4,v retrieving revision 1.107 diff -u -p -r1.107 acinclude.m4 --- acinclude.m4 8 Apr 2007 19:56:52 -0000 1.107 +++ acinclude.m4 23 May 2007 16:27:49 -0000 @@ -78,6 +78,8 @@ AC_DEFUN([AC_PATH_GLIB], [ PKG_CHECK_MODULES(GLIB, glib-2.0, glib_found=yes, glib_found=no) AC_SUBST(GLIB_CFLAGS) AC_SUBST(GLIB_LIBS) + GLIB_GENMARSHAL=`$PKG_CONFIG --variable=glib_genmarshal glib-2.0` + AC_SUBST(GLIB_GENMARSHAL) ]) AC_DEFUN([AC_PATH_DBUS], [ Index: cups/Makefile.am =================================================================== RCS file: /cvsroot/bluez/utils/cups/Makefile.am,v retrieving revision 1.9 diff -u -p -r1.9 Makefile.am --- cups/Makefile.am 20 Aug 2006 02:21:03 -0000 1.9 +++ cups/Makefile.am 23 May 2007 16:27:50 -0000 @@ -7,9 +7,19 @@ else noinst_PROGRAMS = bluetooth endif -bluetooth_SOURCES = main.c sdp.c spp.c hcrp.c -bluetooth_LDADD = @BLUEZ_LIBS@ +MARSHAL_FILES = bluez-cups-marshal.h bluez-cups-marshal.c -AM_CFLAGS = @BLUEZ_CFLAGS@ +bluetooth_SOURCES = main.c sdp.c spp.c hcrp.c $(MARSHAL_FILES) +bluetooth_LDADD = @DBUS_GLIB_LIBS@ @BLUEZ_LIBS@ -MAINTAINERCLEANFILES = Makefile.in +bluez-cups-marshal.h: bluez-cups-marshal.list + $(GLIB_GENMARSHAL) --prefix=bluez_cups_marshal $< --header > $@ +bluez-cups-marshal.c: bluez-cups-marshal.list + $(GLIB_GENMARSHAL) --prefix=bluez_cups_marshal $< --body > $@ +main.c: $(MARSHAL_FILES) + +AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_GLIB_CFLAGS@ + +MAINTAINERCLEANFILES = Makefile.in $(MARSHAL_FILES) +CLEANFILES = $(MARSHAL_FILES) +EXTRA_DIST = bluez-cups-marshal.list Index: cups/main.c =================================================================== RCS file: /cvsroot/bluez/utils/cups/main.c,v retrieving revision 1.6 diff -u -p -r1.6 main.c --- cups/main.c 3 Jan 2006 13:28:57 -0000 1.6 +++ cups/main.c 23 May 2007 16:27:50 -0000 @@ -38,12 +38,249 @@ #include <bluetooth/sdp.h> #include <bluetooth/sdp_lib.h> +#include <dbus/dbus-glib.h> +#include <glib/gi18n.h> +#include "bluez-cups-marshal.h" + extern int sdp_search_spp(sdp_session_t *sdp, uint8_t *channel); extern int sdp_search_hcrp(sdp_session_t *sdp, unsigned short *ctrl_psm, unsigned short *data_psm); extern int spp_print(bdaddr_t *src, bdaddr_t *dst, uint8_t channel, int fd, int copies); extern int hcrp_print(bdaddr_t *src, bdaddr_t *dst, unsigned short ctrl_psm, unsigned short data_psm, int fd, int copies); +#define PRINTER_SERVICE_CLASS_NAME "printer" + +typedef struct { + char *bdaddr; + char *name; +} BluezCupsDevice; + +static GList *device_list = NULL; +static GMainLoop *loop = NULL; + +static void +add_device_to_list(const char *name, const char *bdaddr) +{ + BluezCupsDevice *device; + GList *l; + + /* Look for the device in the list */ + for (l = device_list; l != NULL; l = l->next) { + device = (BluezCupsDevice *) l->data; + + if (strcmp(device->bdaddr, bdaddr) == 0) { + g_free(device->name); + device->name = g_strdup(name); + return; + } + } + + /* Or add it to the list if it's not there */ + device = g_new0(BluezCupsDevice, 1); + device->bdaddr = g_strdup(bdaddr); + if (device->name != NULL) + device->name = g_strdup(name); + + device_list = g_list_prepend(device_list, device); +} + +static void +print_printer_details(const char *name, const char *bdaddr) +{ + char *uri, *escaped; + + escaped = g_strdelimit(g_strdup(name), "\"", '\''); + + uri = g_strdup_printf("bluetooth://%c%c%c%c%c%c%c%c%c%c%c%c", + bdaddr[0], bdaddr[1], + bdaddr[3], bdaddr[4], + bdaddr[6], bdaddr[7], + bdaddr[9], bdaddr[10], + bdaddr[12], bdaddr[13], + bdaddr[15], bdaddr[16]); + g_print("network %s \"Unknown\" \"%s (Bluetooth)\"\n", uri, escaped); + g_free(escaped); +} + +static void +discovery_started(DBusGProxy *object, gpointer user_data) +{ + /* Discovery started! */ +} + +static void +remote_device_found(DBusGProxy *object, + const char *bdaddr, guint class, int rssi, + gpointer user_data) +{ + add_device_to_list(NULL, bdaddr); +} + +static void +remote_name_updated(DBusGProxy *object, + const char *bdaddr, const char *name, + gpointer user_data) +{ + add_device_to_list(name, bdaddr); +} + +static gboolean +device_is_printer(DBusGProxy *object, const char *bdaddr) +{ + GError *e = NULL; + char *class; + + dbus_g_proxy_call(object, "GetRemoteMinorClass", &e, + G_TYPE_STRING, bdaddr, G_TYPE_INVALID, + G_TYPE_STRING, &class, G_TYPE_INVALID); + + if (e == NULL && g_str_equal(class, PRINTER_SERVICE_CLASS_NAME)) { + return TRUE; + } else if(e != NULL) { + g_error_free(e); + } + + return FALSE; +} + +static void +discovery_completed(DBusGProxy *object, gpointer user_data) +{ + GList *l; + guint num_unnamed = 1; + + for (l = device_list; l != NULL; l = l->next) { + BluezCupsDevice *device = (BluezCupsDevice *) l->data; + + if (device_is_printer(object, device->bdaddr)) { + if (device->name == NULL) { + device->name = g_strdup_printf ("Unnamed printer #%d", + num_unnamed); + num_unnamed++; + } + print_printer_details(device->name, device->bdaddr); + } + g_free(device->name); + g_free(device->bdaddr); + g_free(device); + } + + g_list_free(device_list); + device_list = NULL; + + g_main_loop_quit(loop); +} + +static void +remote_device_disappeared(DBusGProxy *object, + const char *bdaddr, + gpointer user_data) +{ + GList *l; + + for (l = device_list; l != NULL; l = l->next) { + BluezCupsDevice *device = (BluezCupsDevice *) l->data; + + if (strcmp(device->bdaddr, bdaddr) == 0) { + g_free(device->name); + g_free(device->bdaddr); + g_free(device); + device_list = g_list_delete_link(device_list, l); + return; + } + } +} + +static void +list_printers(void) +{ + /* 1. Connect to the bus + * 2. Get the manager + * 3. Get the default adapter + * 4. Get a list of devices + * 5. Get the class of each device + * 6. Print the details from each printer device + */ + GError *e = NULL; + DBusGConnection *conn; + DBusGProxy *object; + const char *adapter; + + g_type_init(); + + conn = dbus_g_bus_get(DBUS_BUS_SYSTEM, &e); + if (e != NULL) { + g_warning("Couldn't connect to bus: %s", e->message); + g_error_free(e); + return; + } + + object = dbus_g_proxy_new_for_name(conn, "org.bluez", + "/org/bluez", "org.bluez.Manager"); + dbus_g_proxy_call(object, "DefaultAdapter", &e, + G_TYPE_INVALID, G_TYPE_STRING, &adapter, G_TYPE_INVALID); + if (e != NULL) { + const char *name; + + name = dbus_g_error_get_name(e); + + /* No adapter */ + if (g_str_equal(name, "org.bluez.Error.NoSuchAdapter") != FALSE) { + g_error_free(e); + return; + } + + g_warning("Couldn't get default bluetooth adapter: %s", + e->message); + g_error_free(e); + return; + } + + object = dbus_g_proxy_new_for_name(conn, "org.bluez", + adapter, "org.bluez.Adapter"); + + dbus_g_proxy_add_signal(object, "DiscoveryStarted", G_TYPE_INVALID); + dbus_g_proxy_connect_signal(object, "DiscoveryStarted", + G_CALLBACK(discovery_started), NULL, NULL); + + dbus_g_object_register_marshaller(bluez_cups_marshal_VOID__STRING_UINT_INT, + G_TYPE_NONE, G_TYPE_STRING, G_TYPE_UINT, + G_TYPE_INT, G_TYPE_INVALID); + dbus_g_proxy_add_signal(object, "RemoteDeviceFound", + G_TYPE_STRING, G_TYPE_UINT, G_TYPE_INT, G_TYPE_INVALID); + dbus_g_proxy_connect_signal(object, "RemoteDeviceFound", + G_CALLBACK(remote_device_found), NULL, NULL); + + dbus_g_object_register_marshaller(bluez_cups_marshal_VOID__STRING_STRING, + G_TYPE_NONE, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_INVALID); + dbus_g_proxy_add_signal(object, "RemoteNameUpdated", + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID); + dbus_g_proxy_connect_signal(object, "RemoteNameUpdated", + G_CALLBACK(remote_name_updated), NULL, NULL); + + dbus_g_proxy_add_signal(object, "RemoteDeviceDisappeared", + G_TYPE_STRING, G_TYPE_INVALID); + dbus_g_proxy_connect_signal(object, "RemoteDeviceDisappeared", + G_CALLBACK(remote_device_disappeared), NULL, NULL); + + dbus_g_proxy_add_signal(object, "DiscoveryCompleted", G_TYPE_INVALID); + dbus_g_proxy_connect_signal(object, "DiscoveryCompleted", + G_CALLBACK(discovery_completed), NULL, NULL); + + dbus_g_proxy_call(object, "DiscoverDevices", &e, + G_TYPE_INVALID, G_TYPE_INVALID); + if (e != NULL) { + g_warning("Couldn't start discovery: %s: %s", + dbus_g_error_get_name(e), e->message); + g_error_free(e); + return; + } + + loop = g_main_loop_new(NULL, TRUE); + g_main_loop_run(loop); +} + /* * Usage: printer-uri job-id user title copies options [file] * @@ -73,7 +310,7 @@ int main(int argc, char *argv[]) #endif /* HAVE_SIGSET */ if (argc == 1) { - puts("network bluetooth \"Unknown\" \"Bluetooth printer\""); + list_printers(); return 0; } --- /dev/null 2007-05-22 10:58:00.668244955 +0100 +++ cups/bluez-cups-marshal.list 2007-05-23 11:51:07.000000000 +0100 @@ -0,0 +1,2 @@ +VOID:STRING,UINT,INT +VOID:STRING,STRING [-- Attachment #3: Type: text/plain, Size: 286 bytes --] ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ [-- Attachment #4: Type: text/plain, Size: 164 bytes --] _______________________________________________ Bluez-devel mailing list Bluez-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/bluez-devel ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [Bluez-devel] CUPS plugin discovery bits 2007-05-23 16:26 ` Bastien Nocera @ 2007-05-23 16:56 ` Johan Hedberg 2007-05-23 17:07 ` Bastien Nocera 2007-05-24 13:39 ` Bastien Nocera 0 siblings, 2 replies; 21+ messages in thread From: Johan Hedberg @ 2007-05-23 16:56 UTC (permalink / raw) To: BlueZ development Hi Bastien, On May 23, 2007, at 18:26, Bastien Nocera wrote: > Updated patch attached. A little about optimizing the device discovery. It seems you are filtering out all non-printer devices by checking the minor device class but still requesting names for all found devices (actually hcid is doing the requesting because you use the normal DiscoverDevices method). The name requests are the most time wasting operations of the device discovery process (if a device happens to go out of range you'll have to wait usually between 10 and 20 seconds for a page timeout to occur, and even if it is within range we're talking about several seconds usually for the name request to succeed). To allow overcoming this issue have the DiscoverDevicesWithoutNameResolving method which can be used when you can deduce from the device class information whether you want to ignore the device or get further information about it (e.g. its name, provided services through SDP, etc). So, for the CUPS case, the optimal solution would be to use this alternate discovery method and for each RemoteDeviceFound signal check the class of device value and if it matches request the name for the device (as you were doing in your first patch). This way time will not go wasted to requesting names for devices we will not do anything with anyway. Johan ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ _______________________________________________ Bluez-devel mailing list Bluez-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/bluez-devel ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [Bluez-devel] CUPS plugin discovery bits 2007-05-23 16:56 ` Johan Hedberg @ 2007-05-23 17:07 ` Bastien Nocera 2007-05-24 13:39 ` Bastien Nocera 1 sibling, 0 replies; 21+ messages in thread From: Bastien Nocera @ 2007-05-23 17:07 UTC (permalink / raw) To: BlueZ development On Wed, 2007-05-23 at 18:56 +0200, Johan Hedberg wrote: > Hi Bastien, > > On May 23, 2007, at 18:26, Bastien Nocera wrote: > > Updated patch attached. > > A little about optimizing the device discovery. <snip> > This way time > will not go wasted to requesting names for devices we will not do > anything with anyway. Good call. I'll fix it up tomorrow. -- Bastien Nocera <hadess@hadess.net> ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ _______________________________________________ Bluez-devel mailing list Bluez-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/bluez-devel ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [Bluez-devel] CUPS plugin discovery bits 2007-05-23 16:56 ` Johan Hedberg 2007-05-23 17:07 ` Bastien Nocera @ 2007-05-24 13:39 ` Bastien Nocera 2007-05-24 15:31 ` Johan Hedberg 1 sibling, 1 reply; 21+ messages in thread From: Bastien Nocera @ 2007-05-24 13:39 UTC (permalink / raw) To: BlueZ development [-- Attachment #1: Type: text/plain, Size: 461 bytes --] On Wed, 2007-05-23 at 18:56 +0200, Johan Hedberg wrote: > Hi Bastien, > > On May 23, 2007, at 18:26, Bastien Nocera wrote: > > Updated patch attached. > > A little about optimizing the device discovery. Fixed in this version, and also added recent devices (through ListRemoteDevices and ListBondings). Marcel told me this would be mergeable if I removed the dbus-glib dependency, which I'm going to do now. Cheers -- Bastien Nocera <hadess@hadess.net> [-- Attachment #2: bluez-utils-cups-printer-listing-4.patch --] [-- Type: text/x-patch, Size: 10629 bytes --] Index: acinclude.m4 =================================================================== RCS file: /cvsroot/bluez/utils/acinclude.m4,v retrieving revision 1.107 diff -u -p -r1.107 acinclude.m4 --- acinclude.m4 8 Apr 2007 19:56:52 -0000 1.107 +++ acinclude.m4 24 May 2007 13:37:36 -0000 @@ -78,6 +78,8 @@ AC_DEFUN([AC_PATH_GLIB], [ PKG_CHECK_MODULES(GLIB, glib-2.0, glib_found=yes, glib_found=no) AC_SUBST(GLIB_CFLAGS) AC_SUBST(GLIB_LIBS) + GLIB_GENMARSHAL=`$PKG_CONFIG --variable=glib_genmarshal glib-2.0` + AC_SUBST(GLIB_GENMARSHAL) ]) AC_DEFUN([AC_PATH_DBUS], [ Index: cups/Makefile.am =================================================================== RCS file: /cvsroot/bluez/utils/cups/Makefile.am,v retrieving revision 1.9 diff -u -p -r1.9 Makefile.am --- cups/Makefile.am 20 Aug 2006 02:21:03 -0000 1.9 +++ cups/Makefile.am 24 May 2007 13:37:36 -0000 @@ -7,9 +7,19 @@ else noinst_PROGRAMS = bluetooth endif -bluetooth_SOURCES = main.c sdp.c spp.c hcrp.c -bluetooth_LDADD = @BLUEZ_LIBS@ +MARSHAL_FILES = bluez-cups-marshal.h bluez-cups-marshal.c -AM_CFLAGS = @BLUEZ_CFLAGS@ +bluetooth_SOURCES = main.c sdp.c spp.c hcrp.c $(MARSHAL_FILES) +bluetooth_LDADD = @DBUS_GLIB_LIBS@ @BLUEZ_LIBS@ -MAINTAINERCLEANFILES = Makefile.in +bluez-cups-marshal.h: bluez-cups-marshal.list + $(GLIB_GENMARSHAL) --prefix=bluez_cups_marshal $< --header > $@ +bluez-cups-marshal.c: bluez-cups-marshal.list + $(GLIB_GENMARSHAL) --prefix=bluez_cups_marshal $< --body > $@ +main.c: $(MARSHAL_FILES) + +AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_GLIB_CFLAGS@ + +MAINTAINERCLEANFILES = Makefile.in $(MARSHAL_FILES) +CLEANFILES = $(MARSHAL_FILES) +EXTRA_DIST = bluez-cups-marshal.list Index: cups/main.c =================================================================== RCS file: /cvsroot/bluez/utils/cups/main.c,v retrieving revision 1.6 diff -u -p -r1.6 main.c --- cups/main.c 3 Jan 2006 13:28:57 -0000 1.6 +++ cups/main.c 24 May 2007 13:37:36 -0000 @@ -38,12 +38,317 @@ #include <bluetooth/sdp.h> #include <bluetooth/sdp_lib.h> +#include <dbus/dbus-glib.h> +#include <glib/gi18n.h> +#include "bluez-cups-marshal.h" + extern int sdp_search_spp(sdp_session_t *sdp, uint8_t *channel); extern int sdp_search_hcrp(sdp_session_t *sdp, unsigned short *ctrl_psm, unsigned short *data_psm); extern int spp_print(bdaddr_t *src, bdaddr_t *dst, uint8_t channel, int fd, int copies); extern int hcrp_print(bdaddr_t *src, bdaddr_t *dst, unsigned short ctrl_psm, unsigned short data_psm, int fd, int copies); +#define PRINTER_SERVICE_CLASS_NAME "printer" + +typedef struct { + char *bdaddr; + char *name; +} BluezCupsDevice; + +static GList *device_list = NULL; +static GMainLoop *loop = NULL; + +static void +add_device_to_list(const char *name, const char *bdaddr) +{ + BluezCupsDevice *device; + GList *l; + + /* Look for the device in the list */ + for (l = device_list; l != NULL; l = l->next) { + device = (BluezCupsDevice *) l->data; + + if (strcmp(device->bdaddr, bdaddr) == 0) { + g_free(device->name); + device->name = g_strdup(name); + return; + } + } + + /* Or add it to the list if it's not there */ + device = g_new0(BluezCupsDevice, 1); + device->bdaddr = g_strdup(bdaddr); + device->name = g_strdup(name); + + device_list = g_list_prepend(device_list, device); +} + +static void +print_printer_details(const char *name, const char *bdaddr) +{ + char *uri, *escaped; + + escaped = g_strdelimit(g_strdup(name), "\"", '\''); + + uri = g_strdup_printf("bluetooth://%c%c%c%c%c%c%c%c%c%c%c%c", + bdaddr[0], bdaddr[1], + bdaddr[3], bdaddr[4], + bdaddr[6], bdaddr[7], + bdaddr[9], bdaddr[10], + bdaddr[12], bdaddr[13], + bdaddr[15], bdaddr[16]); + g_print("network %s \"Unknown\" \"%s (Bluetooth)\"\n", uri, escaped); + g_free(escaped); +} + +static gboolean +device_is_printer(DBusGProxy *object, const char *bdaddr) +{ + GError *e = NULL; + char *class; + + dbus_g_proxy_call(object, "GetRemoteMinorClass", &e, + G_TYPE_STRING, bdaddr, G_TYPE_INVALID, + G_TYPE_STRING, &class, G_TYPE_INVALID); + + if (e == NULL && g_str_equal(class, PRINTER_SERVICE_CLASS_NAME)) { + return TRUE; + } else if(e != NULL) { + g_error_free(e); + } + + return FALSE; +} + +static void +add_devices_to_list(DBusGProxy *object, const char **array) +{ + GError *e = NULL; + while (*array) { + const char *name; + + if (!device_is_printer(object, *array)) { + array++; + continue; + } + dbus_g_proxy_call (object, "GetRemoteName", &e, + G_TYPE_STRING, *array, G_TYPE_INVALID, + G_TYPE_STRING, &name, G_TYPE_INVALID); + if (e == NULL) { + add_device_to_list (name, *array); + } else { + g_error_free (e); + e = NULL; + } + array++; + } +} + +static void +remote_device_found(DBusGProxy *object, + const char *bdaddr, guint class, int rssi, + gpointer user_data) +{ + GError *e = NULL; + const char *name; + + /* Don't add non-printer devices */ + if (!device_is_printer(object, bdaddr)) + return; + + dbus_g_proxy_call(object, "GetRemoteName", &e, + G_TYPE_STRING, bdaddr, G_TYPE_INVALID, + G_TYPE_STRING, &name, G_TYPE_INVALID); + + if(e != NULL) { + const char *name; + + name = dbus_g_error_get_name(e); + if (g_str_equal(name, "org.bluez.Error.RequestDeferred") != FALSE) { + add_device_to_list(NULL, bdaddr); + } + g_error_free(e); + } else { + add_device_to_list(name, bdaddr); + } +} + +static void +remote_name_updated(DBusGProxy *object, + const char *bdaddr, const char *name, + gpointer user_data) +{ + add_device_to_list(name, bdaddr); +} + +static void +discovery_completed(DBusGProxy *object, gpointer user_data) +{ + GList *l; + guint num_unnamed = 1; + + for (l = device_list; l != NULL; l = l->next) { + BluezCupsDevice *device = (BluezCupsDevice *) l->data; + + if (device->name == NULL) { + device->name = g_strdup_printf ("Unnamed printer #%d", + num_unnamed); + num_unnamed++; + } + print_printer_details(device->name, device->bdaddr); + g_free(device->name); + g_free(device->bdaddr); + g_free(device); + } + + g_list_free(device_list); + device_list = NULL; + + g_main_loop_quit(loop); +} + +static void +remote_device_disappeared(DBusGProxy *object, + const char *bdaddr, + gpointer user_data) +{ + GList *l; + + for (l = device_list; l != NULL; l = l->next) { + BluezCupsDevice *device = (BluezCupsDevice *) l->data; + + if (strcmp(device->bdaddr, bdaddr) == 0) { + g_free(device->name); + g_free(device->bdaddr); + g_free(device); + device_list = g_list_delete_link(device_list, l); + return; + } + } +} + +static gboolean +list_known_printers(DBusGProxy *object) +{ + GError *e = NULL; + const char **array; + + dbus_g_proxy_call (object, "ListRemoteDevices", &e, + G_TYPE_INVALID, G_TYPE_STRV, &array, G_TYPE_INVALID); + if (e == NULL) { + add_devices_to_list (object, array); + } else { + /* Most likely bluez-utils < 3.8, so no ListRemoteDevices */ + const char *name; + + name = dbus_g_error_get_name (e); + if (g_str_equal (name, "org.bluez.Error.UnknownMethod") != FALSE) { + g_error_free (e); + e = NULL; + dbus_g_proxy_call (object, "ListBondings", &e, + G_TYPE_INVALID, G_TYPE_STRV, &array, G_TYPE_INVALID); + if (e == NULL) { + add_devices_to_list (object, array); + } else { + g_error_free (e); + } + } else { + g_error_free (e); + } + } + + return FALSE; +} + +static void +list_printers(void) +{ + /* 1. Connect to the bus + * 2. Get the manager + * 3. Get the default adapter + * 4. Get a list of devices + * 5. Get the class of each device + * 6. Print the details from each printer device + */ + GError *e = NULL; + DBusGConnection *conn; + DBusGProxy *object; + const char *adapter; + + g_type_init(); + + conn = dbus_g_bus_get(DBUS_BUS_SYSTEM, &e); + if (e != NULL) { + g_warning("Couldn't connect to bus: %s", e->message); + g_error_free(e); + return; + } + + object = dbus_g_proxy_new_for_name(conn, "org.bluez", + "/org/bluez", "org.bluez.Manager"); + dbus_g_proxy_call(object, "DefaultAdapter", &e, + G_TYPE_INVALID, G_TYPE_STRING, &adapter, G_TYPE_INVALID); + if (e != NULL) { + const char *name; + + name = dbus_g_error_get_name(e); + + /* No adapter */ + if (g_str_equal(name, "org.bluez.Error.NoSuchAdapter") != FALSE) { + g_error_free(e); + return; + } + + g_warning("Couldn't get default bluetooth adapter: %s", + e->message); + g_error_free(e); + return; + } + + object = dbus_g_proxy_new_for_name(conn, "org.bluez", + adapter, "org.bluez.Adapter"); + + dbus_g_object_register_marshaller(bluez_cups_marshal_VOID__STRING_UINT_INT, + G_TYPE_NONE, G_TYPE_STRING, G_TYPE_UINT, + G_TYPE_INT, G_TYPE_INVALID); + dbus_g_proxy_add_signal(object, "RemoteDeviceFound", + G_TYPE_STRING, G_TYPE_UINT, G_TYPE_INT, G_TYPE_INVALID); + dbus_g_proxy_connect_signal(object, "RemoteDeviceFound", + G_CALLBACK(remote_device_found), NULL, NULL); + + dbus_g_object_register_marshaller(bluez_cups_marshal_VOID__STRING_STRING, + G_TYPE_NONE, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_INVALID); + dbus_g_proxy_add_signal(object, "RemoteNameUpdated", + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID); + dbus_g_proxy_connect_signal(object, "RemoteNameUpdated", + G_CALLBACK(remote_name_updated), NULL, NULL); + + dbus_g_proxy_add_signal(object, "RemoteDeviceDisappeared", + G_TYPE_STRING, G_TYPE_INVALID); + dbus_g_proxy_connect_signal(object, "RemoteDeviceDisappeared", + G_CALLBACK(remote_device_disappeared), NULL, NULL); + + dbus_g_proxy_add_signal(object, "DiscoveryCompleted", G_TYPE_INVALID); + dbus_g_proxy_connect_signal(object, "DiscoveryCompleted", + G_CALLBACK(discovery_completed), NULL, NULL); + + dbus_g_proxy_call(object, "DiscoverDevicesWithoutNameResolving", &e, + G_TYPE_INVALID, G_TYPE_INVALID); + if (e != NULL) { + g_warning("Couldn't start discovery: %s: %s", + dbus_g_error_get_name(e), e->message); + g_error_free(e); + return; + } + + /* Also add the the recent devices */ + g_idle_add ((GSourceFunc) list_known_printers, object); + + loop = g_main_loop_new(NULL, TRUE); + g_main_loop_run(loop); +} + /* * Usage: printer-uri job-id user title copies options [file] * @@ -73,7 +378,7 @@ int main(int argc, char *argv[]) #endif /* HAVE_SIGSET */ if (argc == 1) { - puts("network bluetooth \"Unknown\" \"Bluetooth printer\""); + list_printers(); return 0; } --- /dev/null 2007-05-24 12:42:54.675807888 +0100 +++ cups/bluez-cups-marshal.list 2007-05-23 11:51:07.000000000 +0100 @@ -0,0 +1,2 @@ +VOID:STRING,UINT,INT +VOID:STRING,STRING [-- Attachment #3: Type: text/plain, Size: 286 bytes --] ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ [-- Attachment #4: Type: text/plain, Size: 164 bytes --] _______________________________________________ Bluez-devel mailing list Bluez-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/bluez-devel ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [Bluez-devel] CUPS plugin discovery bits 2007-05-24 13:39 ` Bastien Nocera @ 2007-05-24 15:31 ` Johan Hedberg 2007-05-24 18:49 ` Bastien Nocera 0 siblings, 1 reply; 21+ messages in thread From: Johan Hedberg @ 2007-05-24 15:31 UTC (permalink / raw) To: BlueZ development Hi Bastien, On May 24, 2007, at 15:39, Bastien Nocera wrote: > On Wed, 2007-05-23 at 18:56 +0200, Johan Hedberg wrote: >> Hi Bastien, >> >> On May 23, 2007, at 18:26, Bastien Nocera wrote: >>> Updated patch attached. >> >> A little about optimizing the device discovery. > > Fixed in this version, and also added recent devices (through > ListRemoteDevices and ListBondings). I see you're now using the manual name resolving discovery and deciding from the device class whether to get the name or not. Great! However, you are causing an unecessary roundtrip back to hcid by calling GetRemoteMinorClass because you in fact already have the necessary information encoded in the class parameter of the RemoteDeviceFound signal. It's not as convenient as a string to do a strcmp on, but you can just take example from hcid code how it converts the 3 byte value to the string. Johan ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ _______________________________________________ Bluez-devel mailing list Bluez-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/bluez-devel ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [Bluez-devel] CUPS plugin discovery bits 2007-05-24 15:31 ` Johan Hedberg @ 2007-05-24 18:49 ` Bastien Nocera 2007-05-25 12:30 ` Bastien Nocera 0 siblings, 1 reply; 21+ messages in thread From: Bastien Nocera @ 2007-05-24 18:49 UTC (permalink / raw) To: BlueZ development [-- Attachment #1: Type: text/plain, Size: 1269 bytes --] On Thu, 2007-05-24 at 17:31 +0200, Johan Hedberg wrote: > Hi Bastien, > > On May 24, 2007, at 15:39, Bastien Nocera wrote: > > On Wed, 2007-05-23 at 18:56 +0200, Johan Hedberg wrote: > >> Hi Bastien, > >> > >> On May 23, 2007, at 18:26, Bastien Nocera wrote: > >>> Updated patch attached. > >> > >> A little about optimizing the device discovery. > > > > Fixed in this version, and also added recent devices (through > > ListRemoteDevices and ListBondings). > > I see you're now using the manual name resolving discovery and > deciding from the device class whether to get the name or not. Great! > However, you are causing an unecessary roundtrip back to hcid by > calling GetRemoteMinorClass because you in fact already have the > necessary information encoded in the class parameter of the > RemoteDeviceFound signal. It's not as convenient as a string to do a > strcmp on, but you can just take example from hcid code how it > converts the 3 byte value to the string. This is most ugly. There should really be a helper function for that, or hcid should pass a decoded argument. Anyway, it's implemented now, along with a port to pure D-Bus, and can use the builtin eglib instead of the system one. Marcel -- Bastien Nocera <hadess@hadess.net> [-- Attachment #2: bluez-utils-cups-printer-listing-8.patch --] [-- Type: text/x-patch, Size: 13112 bytes --] Index: cups/Makefile.am =================================================================== RCS file: /cvsroot/bluez/utils/cups/Makefile.am,v retrieving revision 1.9 diff -u -p -r1.9 Makefile.am --- cups/Makefile.am 20 Aug 2006 02:21:03 -0000 1.9 +++ cups/Makefile.am 24 May 2007 18:50:13 -0000 @@ -8,8 +8,9 @@ noinst_PROGRAMS = bluetooth endif bluetooth_SOURCES = main.c sdp.c spp.c hcrp.c -bluetooth_LDADD = @BLUEZ_LIBS@ +bluetooth_LDADD = @DBUS_LIBS@ @GLIB_LIBS@ @BLUEZ_LIBS@ $(top_builddir)/common/libhelper.a -AM_CFLAGS = @BLUEZ_CFLAGS@ +AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ -I$(top_srcdir)/common MAINTAINERCLEANFILES = Makefile.in + Index: cups/main.c =================================================================== RCS file: /cvsroot/bluez/utils/cups/main.c,v retrieving revision 1.6 diff -u -p -r1.6 main.c --- cups/main.c 3 Jan 2006 13:28:57 -0000 1.6 +++ cups/main.c 24 May 2007 18:50:14 -0000 @@ -38,12 +38,414 @@ #include <bluetooth/sdp.h> #include <bluetooth/sdp_lib.h> +#include <glib.h> +#include <dbus/dbus.h> +#include "dbus.h" + extern int sdp_search_spp(sdp_session_t *sdp, uint8_t *channel); extern int sdp_search_hcrp(sdp_session_t *sdp, unsigned short *ctrl_psm, unsigned short *data_psm); extern int spp_print(bdaddr_t *src, bdaddr_t *dst, uint8_t channel, int fd, int copies); extern int hcrp_print(bdaddr_t *src, bdaddr_t *dst, unsigned short ctrl_psm, unsigned short data_psm, int fd, int copies); +#define PRINTER_SERVICE_CLASS_NAME "printer" + +typedef struct { + char *bdaddr; + char *name; +} BluezCupsDevice; + +static GSList *device_list = NULL; +static GMainLoop *loop = NULL; +static DBusConnection *conn = NULL; + +static void +add_device_to_list(const char *name, const char *bdaddr) +{ + BluezCupsDevice *device; + GSList *l; + + /* Look for the device in the list */ + for (l = device_list; l != NULL; l = l->next) { + device = (BluezCupsDevice *) l->data; + + if (strcmp(device->bdaddr, bdaddr) == 0) { + g_free(device->name); + device->name = g_strdup(name); + return; + } + } + + /* Or add it to the list if it's not there */ + device = g_new0(BluezCupsDevice, 1); + device->bdaddr = g_strdup(bdaddr); + device->name = g_strdup(name); + + device_list = g_slist_prepend(device_list, device); +} + +static char * +escape_name(const char *str, char orig, char dest) +{ + char *ret, *s; + + ret = g_strdup(str); + while ((s = strchr(ret, orig)) != NULL) + s[0] = dest; + return ret; +} + +static void +print_printer_details(const char *name, const char *bdaddr) +{ + char *uri, *escaped; + guint len; + + escaped = escape_name(name, '\"', '\''); + len = strlen("bluetooth://") + 12 + 1; + uri = g_malloc(len); + snprintf(uri, len, "bluetooth://%c%c%c%c%c%c%c%c%c%c%c%c", + bdaddr[0], bdaddr[1], + bdaddr[3], bdaddr[4], + bdaddr[6], bdaddr[7], + bdaddr[9], bdaddr[10], + bdaddr[12], bdaddr[13], + bdaddr[15], bdaddr[16]); + printf("network %s \"Unknown\" \"%s (Bluetooth)\"\n", uri, escaped); + g_free(escaped); + g_free(uri); +} + +static gboolean +device_is_printer(const char *adapter, const char *bdaddr) +{ + char *class; + DBusMessage *message, *reply; + DBusMessageIter iter, reply_iter; + + message = dbus_message_new_method_call("org.bluez", adapter, + "org.bluez.Adapter", + "GetRemoteMinorClass"); + dbus_message_iter_init_append(message, &iter); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr); + + reply = dbus_connection_send_with_reply_and_block(conn, + message, -1, NULL); + if (!reply) { + dbus_message_unref(message); + return FALSE; + } + + dbus_message_iter_init(reply, &reply_iter); + dbus_message_iter_get_basic(&reply_iter, &class); + + if (class != NULL && strcmp(class, PRINTER_SERVICE_CLASS_NAME) == 0) { + dbus_message_unref(reply); + return TRUE; + } + + return FALSE; +} + +static char * +device_get_name(const char *adapter, const char *bdaddr) +{ + char *name; + DBusMessage *message, *reply; + DBusMessageIter iter, reply_iter; + + message = dbus_message_new_method_call("org.bluez", adapter, + "org.bluez.Adapter", + "GetRemoteName"); + dbus_message_iter_init_append(message, &iter); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr); + + reply = dbus_connection_send_with_reply_and_block(conn, + message, -1, NULL); + dbus_message_unref(message); + if (!reply) + return NULL; + + dbus_message_iter_init(reply, &reply_iter); + dbus_message_iter_get_basic(&reply_iter, &name); + + name = g_strdup(name); + dbus_message_unref(reply); + return name; +} + +static void +remote_device_found(const char *adapter, const char *bdaddr, guint class, int rssi) +{ + uint8_t major_index = (class >> 8) & 0x1F; + uint8_t minor_index; + uint8_t shift_minor = 0; + gboolean found = FALSE; + char *name; + + /* Check if we have a printer + * From hcid/dbus-adapter.c minor_class_str() */ + if (major_index != 6) + return; + + minor_index = (class >> 4) & 0x0F; + while (shift_minor < 4) { + if (((minor_index >> shift_minor) & 0x01) == 0x01) { + if (shift_minor == 3) { + found = TRUE; + break; + } + } + shift_minor++; + } + + if (!found) + return; + + name = device_get_name(adapter, bdaddr); + add_device_to_list(name, bdaddr); + g_free(name); +} + +static void +remote_name_updated(const char *bdaddr, const char *name) +{ + add_device_to_list(name, bdaddr); +} + +static void +discovery_completed(void) +{ + GSList *l; + + for (l = device_list; l != NULL; l = l->next) { + BluezCupsDevice *device = (BluezCupsDevice *) l->data; + + if (device->name == NULL) { + device->name = escape_name(device->bdaddr, + ':', '-'); + } + print_printer_details(device->name, device->bdaddr); + g_free(device->name); + g_free(device->bdaddr); + g_free(device); + } + + g_slist_free(device_list); + device_list = NULL; + + g_main_loop_quit(loop); +} + +static void +remote_device_disappeared(const char *bdaddr) +{ + GSList *l; + + for (l = device_list; l != NULL; l = l->next) { + BluezCupsDevice *device = (BluezCupsDevice *) l->data; + + if (strcmp(device->bdaddr, bdaddr) == 0) { + g_free(device->name); + g_free(device->bdaddr); + g_free(device); + device_list = g_slist_delete_link(device_list, l); + return; + } + } +} + +static gboolean +list_known_printers(const char *adapter) +{ + DBusMessageIter reply_iter, iter_array; + DBusError error; + DBusMessage *message, *reply; + + message = dbus_message_new_method_call ("org.bluez", adapter, + "org.bluez.Adapter", + "ListRemoteDevices"); + if (message == NULL) + return FALSE; + + dbus_error_init(&error); + reply = dbus_connection_send_with_reply_and_block(conn, + message, -1, + &error); + dbus_message_unref(message); + if (&error != NULL && dbus_error_is_set(&error)) + return FALSE; + + dbus_message_iter_init(reply, &reply_iter); + if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_ARRAY) { + dbus_message_unref(reply); + return FALSE; + } + + dbus_message_iter_recurse(&reply_iter, &iter_array); + while (dbus_message_iter_get_arg_type(&iter_array) == DBUS_TYPE_STRING) { + char *bdaddr; + + dbus_message_iter_get_basic(&iter_array, &bdaddr); + if (device_is_printer(adapter, bdaddr)) { + char *name; + name = device_get_name(adapter, bdaddr); + add_device_to_list(name, bdaddr); + g_free(name); + } + dbus_message_iter_next(&iter_array); + } + + dbus_message_unref(reply); + + return FALSE; +} + +static DBusHandlerResult +filter_func(DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + const char *adapter; + + if (dbus_message_is_signal(message, "org.bluez.Adapter", + "RemoteDeviceFound")) { + char *bdaddr; + guint class; + int rssi; + + dbus_message_get_args(message, NULL, + DBUS_TYPE_STRING, &bdaddr, + DBUS_TYPE_UINT32, &class, + DBUS_TYPE_INT32, &rssi, + DBUS_TYPE_INVALID); + adapter = dbus_message_get_path(message); + remote_device_found(adapter, bdaddr, class, rssi); + } else if (dbus_message_is_signal(message, "org.bluez.Adapter", + "RemoteNameUpdated")) { + char *bdaddr, *name; + + dbus_message_get_args(message, NULL, + DBUS_TYPE_STRING, &bdaddr, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_INVALID); + remote_name_updated(bdaddr, name); + } else if (dbus_message_is_signal(message, "org.bluez.Adapter", + "RemoteDeviceDisappeared")) { + char *bdaddr; + + dbus_message_get_args(message, NULL, + DBUS_TYPE_STRING, &bdaddr, + DBUS_TYPE_INVALID); + remote_device_disappeared(bdaddr); + } else if (dbus_message_is_signal(message, "org.bluez.Adapter", + "DiscoveryCompleted")) { + discovery_completed(); + } + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static void +list_printers(void) +{ + /* 1. Connect to the bus + * 2. Get the manager + * 3. Get the default adapter + * 4. Get a list of devices + * 5. Get the class of each device + * 6. Print the details from each printer device + */ + DBusError error; + dbus_bool_t hcid_exists; + DBusMessage *reply, *message; + DBusMessageIter reply_iter; + char *adapter, *match; + guint len; + + conn = init_dbus(NULL, NULL, NULL); + if (conn == NULL) + return; + + dbus_error_init(&error); + hcid_exists = dbus_bus_name_has_owner(conn, "org.bluez", &error); + if (&error != NULL && dbus_error_is_set(&error)) + return; + + if (!hcid_exists) + return; + + /* Get the default adapter */ + message = dbus_message_new_method_call("org.bluez", "/org/bluez", + "org.bluez.Manager", + "DefaultAdapter"); + if (message == NULL) { + dbus_connection_unref(conn); + return; + } + reply = dbus_connection_send_with_reply_and_block(conn, + message, -1, + &error); + dbus_message_unref(message); + if (&error != NULL && dbus_error_is_set(&error)) { + dbus_connection_unref(conn); + return; + } + + dbus_message_iter_init(reply, &reply_iter); + if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_STRING) { + dbus_message_unref(reply); + dbus_connection_unref(conn); + return; + } + dbus_message_iter_get_basic(&reply_iter, &adapter); + adapter = g_strdup(adapter); + dbus_message_unref(reply); + + if (!dbus_connection_add_filter(conn, filter_func, adapter, g_free)) { + g_free(adapter); + dbus_connection_unref(conn); + return; + } + +#define MATCH_FORMAT \ + "type='signal'," \ + "interface='org.bluez.Adapter'," \ + "sender='org.bluez'," \ + "path='%s'" + + len = strlen(MATCH_FORMAT) - 2 + strlen(adapter) + 1; + match = g_malloc(len); + snprintf(match, len, "type='signal'," + "interface='org.bluez.Adapter'," + "sender='org.bluez'," + "path='%s'", + adapter); + dbus_bus_add_match(conn, match, &error); + g_free(match); + + message = dbus_message_new_method_call("org.bluez", adapter, + "org.bluez.Adapter", + "DiscoverDevicesWithoutNameResolving"); + + if (!dbus_connection_send_with_reply(conn, + message, NULL, -1)) { + dbus_message_unref(message); + dbus_connection_unref(conn); + g_free(adapter); + return; + } + dbus_message_unref(message); + + /* Also add the the recent devices */ + g_timeout_add(0, (GSourceFunc) list_known_printers, adapter); + + loop = g_main_loop_new(NULL, TRUE); + g_main_loop_run(loop); + + dbus_connection_unref(conn); +} + /* * Usage: printer-uri job-id user title copies options [file] * @@ -73,7 +475,7 @@ int main(int argc, char *argv[]) #endif /* HAVE_SIGSET */ if (argc == 1) { - puts("network bluetooth \"Unknown\" \"Bluetooth printer\""); + list_printers(); return 0; } Index: eglib/gmain.c =================================================================== RCS file: /cvsroot/bluez/utils/eglib/gmain.c,v retrieving revision 1.27 diff -u -p -r1.27 gmain.c --- eglib/gmain.c 3 May 2007 15:41:42 -0000 1.27 +++ eglib/gmain.c 24 May 2007 18:50:17 -0000 @@ -1127,6 +1127,48 @@ void g_slist_free(GSList *list) } } +static inline GSList* +_g_slist_remove_link (GSList *list, + GSList *link) +{ + GSList *tmp; + GSList *prev; + + prev = NULL; + tmp = list; + + while (tmp) + { + if (tmp == link) + { + if (prev) + prev->next = tmp->next; + if (list == tmp) + list = list->next; + + tmp->next = NULL; + break; + } + + prev = tmp; + tmp = tmp->next; + } + + return list; +} + + +GSList* +g_slist_delete_link (GSList *list, + GSList *link) +{ + list = _g_slist_remove_link(list, link); + g_free(link); + + return list; +} + + /* Memory allocation functions */ gpointer g_malloc(gulong n_bytes) Index: eglib/gmain.h =================================================================== RCS file: /cvsroot/bluez/utils/eglib/gmain.h,v retrieving revision 1.12 diff -u -p -r1.12 gmain.h --- eglib/gmain.h 3 May 2007 15:41:43 -0000 1.12 +++ eglib/gmain.h 24 May 2007 18:50:17 -0000 @@ -191,6 +191,7 @@ int g_slist_length(GSList *list); void g_slist_foreach(GSList *list, GFunc func, void *user_data); void g_slist_free(GSList *list); +GSList *g_slist_delete_link (GSList *list, GSList *link); /* End GSList declarations */ [-- Attachment #3: Type: text/plain, Size: 286 bytes --] ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ [-- Attachment #4: Type: text/plain, Size: 164 bytes --] _______________________________________________ Bluez-devel mailing list Bluez-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/bluez-devel ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [Bluez-devel] CUPS plugin discovery bits 2007-05-24 18:49 ` Bastien Nocera @ 2007-05-25 12:30 ` Bastien Nocera 2007-05-25 12:58 ` Bastien Nocera 0 siblings, 1 reply; 21+ messages in thread From: Bastien Nocera @ 2007-05-25 12:30 UTC (permalink / raw) To: BlueZ development [-- Attachment #1: Type: text/plain, Size: 835 bytes --] On Thu, 2007-05-24 at 19:50 +0100, Bastien Nocera wrote: <snip> > This is most ugly. There should really be a helper function for that, or > hcid should pass a decoded argument. > > Anyway, it's implemented now, along with a port to pure D-Bus, and can > use the builtin eglib instead of the system one. And an updated version which pulls the IEEE1284 ID from the attributes of the SDP record. This means that it takes 2 clicks in most config tools to add the printer (add printer, and select the bluetooth printer). If you're using the system hcid instead of the patched in bluez-utils, you'll need to replace the line: const char *svc_id = "hcrp"; /* aka 0x1126 */ with: const char *svc_id = "00001126-0000-1000-8000-00805F9B34FB"; in cups/main.c device_get_ieee1284_id() Patch attached. -- Bastien Nocera <hadess@hadess.net> [-- Attachment #2: bluez-utils-cups-printer-listing-9.patch --] [-- Type: text/x-patch, Size: 16747 bytes --] Index: cups/Makefile.am =================================================================== RCS file: /cvsroot/bluez/utils/cups/Makefile.am,v retrieving revision 1.9 diff -u -p -r1.9 Makefile.am --- cups/Makefile.am 20 Aug 2006 02:21:03 -0000 1.9 +++ cups/Makefile.am 25 May 2007 12:28:37 -0000 @@ -8,8 +8,13 @@ noinst_PROGRAMS = bluetooth endif bluetooth_SOURCES = main.c sdp.c spp.c hcrp.c -bluetooth_LDADD = @BLUEZ_LIBS@ +if EXPAT +bluetooth_LDADD = @DBUS_LIBS@ @GLIB_LIBS@ @BLUEZ_LIBS@ -lexpat $(top_builddir)/common/libhelper.a +else +bluetooth_LDADD = @DBUS_LIBS@ @GLIB_LIBS@ @BLUEZ_LIBS@ $(top_builddir)/common/libhelper.a +endif -AM_CFLAGS = @BLUEZ_CFLAGS@ +AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ MAINTAINERCLEANFILES = Makefile.in + Index: cups/main.c =================================================================== RCS file: /cvsroot/bluez/utils/cups/main.c,v retrieving revision 1.6 diff -u -p -r1.6 main.c --- cups/main.c 3 Jan 2006 13:28:57 -0000 1.6 +++ cups/main.c 25 May 2007 12:28:37 -0000 @@ -38,12 +38,517 @@ #include <bluetooth/sdp.h> #include <bluetooth/sdp_lib.h> +#include <glib.h> +#include <dbus/dbus.h> +#include "../common/dbus.h" +#include "../common/sdp-xml.h" + extern int sdp_search_spp(sdp_session_t *sdp, uint8_t *channel); extern int sdp_search_hcrp(sdp_session_t *sdp, unsigned short *ctrl_psm, unsigned short *data_psm); extern int spp_print(bdaddr_t *src, bdaddr_t *dst, uint8_t channel, int fd, int copies); extern int hcrp_print(bdaddr_t *src, bdaddr_t *dst, unsigned short ctrl_psm, unsigned short data_psm, int fd, int copies); +#define PRINTER_SERVICE_CLASS_NAME "printer" + +typedef struct { + char *bdaddr; + char *name; + char *id; +} BluezCupsDevice; + +static GSList *device_list = NULL; +static GMainLoop *loop = NULL; +static DBusConnection *conn = NULL; + +#define ATTRID_1284ID 0x0300 + +static char * +parse_xml_sdp(const char *xml) +{ + sdp_record_t *sdp_record; + sdp_list_t *l; + char *str = NULL; + + sdp_record = sdp_xml_parse_record(xml, strlen(xml)); + if (sdp_record == NULL) + return NULL; + for (l = sdp_record->attrlist; l != NULL; l = l->next) { + sdp_data_t *data; + + data = (sdp_data_t *) l->data; + if (data->attrId != ATTRID_1284ID) + continue; + /* Ignore the length, it's null terminated */ + str = g_strdup(data->val.str + 2); + break; + } + sdp_record_free(sdp_record); + + return str; +} + +static char * +device_get_ieee1284_id(const char *adapter, const char *bdaddr) +{ + guint service_handle; + DBusMessage *message, *reply; + DBusMessageIter iter, reply_iter, iter_array; + const char *svc_id = "hcrp"; /* aka 0x1126 */ + char *xml, *id; + + /* Look for the service handle of the HCRP service */ + message = dbus_message_new_method_call("org.bluez", adapter, + "org.bluez.Adapter", + "GetRemoteServiceHandles"); + dbus_message_iter_init_append(message, &iter); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &svc_id); + + reply = dbus_connection_send_with_reply_and_block(conn, + message, -1, NULL); + if (!reply) { + dbus_message_unref(message); + return NULL; + } + + dbus_message_iter_init(reply, &reply_iter); + if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_ARRAY) { + dbus_message_unref(reply); + return NULL; + } + + /* Hopefully we only get one handle, or take a punt */ + dbus_message_iter_recurse(&reply_iter, &iter_array); + while (dbus_message_iter_get_arg_type(&iter_array) == DBUS_TYPE_UINT32) { + dbus_message_iter_get_basic(&iter_array, &service_handle); + dbus_message_iter_next(&iter_array); + } + + dbus_message_unref(reply); + + /* Now get the XML for the HCRP service record */ + message = dbus_message_new_method_call("org.bluez", adapter, + "org.bluez.Adapter", + "GetRemoteServiceRecordAsXML"); + dbus_message_iter_init_append(message, &iter); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT32, &service_handle); + + reply = dbus_connection_send_with_reply_and_block(conn, + message, -1, NULL); + dbus_message_unref(message); + if (!reply) { + return NULL; + } + + dbus_message_iter_init(reply, &reply_iter); + dbus_message_iter_get_basic(&reply_iter, &xml); + + id = parse_xml_sdp(xml); + + dbus_message_unref(reply); + + return id; +} + +static void +add_device_to_list(const char *name, const char *bdaddr, const char *id) +{ + BluezCupsDevice *device; + GSList *l; + + /* Look for the device in the list */ + for (l = device_list; l != NULL; l = l->next) { + device = (BluezCupsDevice *) l->data; + + if (strcmp(device->bdaddr, bdaddr) == 0) { + g_free(device->name); + device->name = g_strdup(name); + return; + } + } + + /* Or add it to the list if it's not there */ + device = g_new0(BluezCupsDevice, 1); + device->bdaddr = g_strdup(bdaddr); + device->name = g_strdup(name); + device->id = g_strdup(id); + + device_list = g_slist_prepend(device_list, device); +} + +static char * +escape_name(const char *str, char orig, char dest) +{ + char *ret, *s; + + ret = g_strdup(str); + while ((s = strchr(ret, orig)) != NULL) + s[0] = dest; + return ret; +} + +static void +print_printer_details(const char *name, const char *bdaddr, const char *id) +{ + char *uri, *escaped; + guint len; + + escaped = escape_name(name, '\"', '\''); + len = strlen("bluetooth://") + 12 + 1; + uri = g_malloc(len); + snprintf(uri, len, "bluetooth://%c%c%c%c%c%c%c%c%c%c%c%c", + bdaddr[0], bdaddr[1], + bdaddr[3], bdaddr[4], + bdaddr[6], bdaddr[7], + bdaddr[9], bdaddr[10], + bdaddr[12], bdaddr[13], + bdaddr[15], bdaddr[16]); + printf("network %s \"Unknown\" \"%s (Bluetooth)\"", uri, escaped); + if (id != NULL) + printf(" \"%s\"\n", id); + else + printf ("\n"); + g_free(escaped); + g_free(uri); +} + +static gboolean +device_is_printer(const char *adapter, const char *bdaddr) +{ + char *class; + DBusMessage *message, *reply; + DBusMessageIter iter, reply_iter; + + message = dbus_message_new_method_call("org.bluez", adapter, + "org.bluez.Adapter", + "GetRemoteMinorClass"); + dbus_message_iter_init_append(message, &iter); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr); + + reply = dbus_connection_send_with_reply_and_block(conn, + message, -1, NULL); + dbus_message_unref(message); + if (!reply) { + return FALSE; + } + + dbus_message_iter_init(reply, &reply_iter); + dbus_message_iter_get_basic(&reply_iter, &class); + + if (class != NULL && strcmp(class, PRINTER_SERVICE_CLASS_NAME) == 0) { + dbus_message_unref(reply); + return TRUE; + } + + return FALSE; +} + +static char * +device_get_name(const char *adapter, const char *bdaddr) +{ + char *name; + DBusMessage *message, *reply; + DBusMessageIter iter, reply_iter; + + message = dbus_message_new_method_call("org.bluez", adapter, + "org.bluez.Adapter", + "GetRemoteName"); + dbus_message_iter_init_append(message, &iter); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr); + + reply = dbus_connection_send_with_reply_and_block(conn, + message, -1, NULL); + dbus_message_unref(message); + if (!reply) + return NULL; + + dbus_message_iter_init(reply, &reply_iter); + dbus_message_iter_get_basic(&reply_iter, &name); + + name = g_strdup(name); + dbus_message_unref(reply); + return name; +} + +static void +remote_device_found(const char *adapter, const char *bdaddr, guint class, int rssi) +{ + uint8_t major_index = (class >> 8) & 0x1F; + uint8_t minor_index; + uint8_t shift_minor = 0; + gboolean found = FALSE; + char *name, *id; + + /* Check if we have a printer + * From hcid/dbus-adapter.c minor_class_str() */ + if (major_index != 6) + return; + + minor_index = (class >> 4) & 0x0F; + while (shift_minor < 4) { + if (((minor_index >> shift_minor) & 0x01) == 0x01) { + if (shift_minor == 3) { + found = TRUE; + break; + } + } + shift_minor++; + } + + if (!found) + return; + + name = device_get_name(adapter, bdaddr); + id = device_get_ieee1284_id(adapter, bdaddr); + add_device_to_list(name, bdaddr, id); + g_free(name); + g_free(id); +} + +static void +remote_name_updated(const char *bdaddr, const char *name) +{ + add_device_to_list(name, bdaddr, NULL); +} + +static void +discovery_completed(void) +{ + GSList *l; + + for (l = device_list; l != NULL; l = l->next) { + BluezCupsDevice *device = (BluezCupsDevice *) l->data; + + if (device->name == NULL) { + device->name = escape_name(device->bdaddr, + ':', '-'); + } + print_printer_details(device->name, device->bdaddr, device->id); + g_free(device->name); + g_free(device->bdaddr); + g_free(device->id); + g_free(device); + } + + g_slist_free(device_list); + device_list = NULL; + + g_main_loop_quit(loop); +} + +static void +remote_device_disappeared(const char *bdaddr) +{ + GSList *l; + + for (l = device_list; l != NULL; l = l->next) { + BluezCupsDevice *device = (BluezCupsDevice *) l->data; + + if (strcmp(device->bdaddr, bdaddr) == 0) { + g_free(device->name); + g_free(device->bdaddr); + g_free(device); + device_list = g_slist_delete_link(device_list, l); + return; + } + } +} + +static gboolean +list_known_printers(const char *adapter) +{ + DBusMessageIter reply_iter, iter_array; + DBusError error; + DBusMessage *message, *reply; + + message = dbus_message_new_method_call ("org.bluez", adapter, + "org.bluez.Adapter", + "ListRemoteDevices"); + if (message == NULL) + return FALSE; + + dbus_error_init(&error); + reply = dbus_connection_send_with_reply_and_block(conn, + message, -1, + &error); + dbus_message_unref(message); + if (&error != NULL && dbus_error_is_set(&error)) + return FALSE; + + dbus_message_iter_init(reply, &reply_iter); + if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_ARRAY) { + dbus_message_unref(reply); + return FALSE; + } + + dbus_message_iter_recurse(&reply_iter, &iter_array); + while (dbus_message_iter_get_arg_type(&iter_array) == DBUS_TYPE_STRING) { + char *bdaddr; + + dbus_message_iter_get_basic(&iter_array, &bdaddr); + if (device_is_printer(adapter, bdaddr)) { + char *name, *id; + name = device_get_name(adapter, bdaddr); + id = device_get_ieee1284_id(adapter, bdaddr); + add_device_to_list(name, bdaddr, id); + g_free(name); + g_free(id); + } + dbus_message_iter_next(&iter_array); + } + + dbus_message_unref(reply); + + return FALSE; +} + +static DBusHandlerResult +filter_func(DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + const char *adapter; + + if (dbus_message_is_signal(message, "org.bluez.Adapter", + "RemoteDeviceFound")) { + char *bdaddr; + guint class; + int rssi; + + dbus_message_get_args(message, NULL, + DBUS_TYPE_STRING, &bdaddr, + DBUS_TYPE_UINT32, &class, + DBUS_TYPE_INT32, &rssi, + DBUS_TYPE_INVALID); + adapter = dbus_message_get_path(message); + remote_device_found(adapter, bdaddr, class, rssi); + } else if (dbus_message_is_signal(message, "org.bluez.Adapter", + "RemoteNameUpdated")) { + char *bdaddr, *name; + + dbus_message_get_args(message, NULL, + DBUS_TYPE_STRING, &bdaddr, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_INVALID); + remote_name_updated(bdaddr, name); + } else if (dbus_message_is_signal(message, "org.bluez.Adapter", + "RemoteDeviceDisappeared")) { + char *bdaddr; + + dbus_message_get_args(message, NULL, + DBUS_TYPE_STRING, &bdaddr, + DBUS_TYPE_INVALID); + remote_device_disappeared(bdaddr); + } else if (dbus_message_is_signal(message, "org.bluez.Adapter", + "DiscoveryCompleted")) { + discovery_completed(); + } + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static void +list_printers(void) +{ + /* 1. Connect to the bus + * 2. Get the manager + * 3. Get the default adapter + * 4. Get a list of devices + * 5. Get the class of each device + * 6. Print the details from each printer device + */ + DBusError error; + dbus_bool_t hcid_exists; + DBusMessage *reply, *message; + DBusMessageIter reply_iter; + char *adapter, *match; + guint len; + + conn = init_dbus(NULL, NULL, NULL); + if (conn == NULL) + return; + + dbus_error_init(&error); + hcid_exists = dbus_bus_name_has_owner(conn, "org.bluez", &error); + if (&error != NULL && dbus_error_is_set(&error)) + return; + + if (!hcid_exists) + return; + + /* Get the default adapter */ + message = dbus_message_new_method_call("org.bluez", "/org/bluez", + "org.bluez.Manager", + "DefaultAdapter"); + if (message == NULL) { + dbus_connection_unref(conn); + return; + } + reply = dbus_connection_send_with_reply_and_block(conn, + message, -1, + &error); + dbus_message_unref(message); + if (&error != NULL && dbus_error_is_set(&error)) { + dbus_connection_unref(conn); + return; + } + + dbus_message_iter_init(reply, &reply_iter); + if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_STRING) { + dbus_message_unref(reply); + dbus_connection_unref(conn); + return; + } + dbus_message_iter_get_basic(&reply_iter, &adapter); + adapter = g_strdup(adapter); + dbus_message_unref(reply); + + if (!dbus_connection_add_filter(conn, filter_func, adapter, g_free)) { + g_free(adapter); + dbus_connection_unref(conn); + return; + } + +#define MATCH_FORMAT \ + "type='signal'," \ + "interface='org.bluez.Adapter'," \ + "sender='org.bluez'," \ + "path='%s'" + + len = strlen(MATCH_FORMAT) - 2 + strlen(adapter) + 1; + match = g_malloc(len); + snprintf(match, len, "type='signal'," + "interface='org.bluez.Adapter'," + "sender='org.bluez'," + "path='%s'", + adapter); + dbus_bus_add_match(conn, match, &error); + g_free(match); + + message = dbus_message_new_method_call("org.bluez", adapter, + "org.bluez.Adapter", + "DiscoverDevicesWithoutNameResolving"); + + if (!dbus_connection_send_with_reply(conn, + message, NULL, -1)) { + dbus_message_unref(message); + dbus_connection_unref(conn); + g_free(adapter); + return; + } + dbus_message_unref(message); + + /* Also add the the recent devices */ + g_timeout_add(0, (GSourceFunc) list_known_printers, adapter); + + loop = g_main_loop_new(NULL, TRUE); + g_main_loop_run(loop); + + dbus_connection_unref(conn); +} + /* * Usage: printer-uri job-id user title copies options [file] * @@ -73,7 +578,7 @@ int main(int argc, char *argv[]) #endif /* HAVE_SIGSET */ if (argc == 1) { - puts("network bluetooth \"Unknown\" \"Bluetooth printer\""); + list_printers(); return 0; } Index: eglib/gmain.c =================================================================== RCS file: /cvsroot/bluez/utils/eglib/gmain.c,v retrieving revision 1.27 diff -u -p -r1.27 gmain.c --- eglib/gmain.c 3 May 2007 15:41:42 -0000 1.27 +++ eglib/gmain.c 25 May 2007 12:28:38 -0000 @@ -1127,6 +1127,48 @@ void g_slist_free(GSList *list) } } +static inline GSList* +_g_slist_remove_link (GSList *list, + GSList *link) +{ + GSList *tmp; + GSList *prev; + + prev = NULL; + tmp = list; + + while (tmp) + { + if (tmp == link) + { + if (prev) + prev->next = tmp->next; + if (list == tmp) + list = list->next; + + tmp->next = NULL; + break; + } + + prev = tmp; + tmp = tmp->next; + } + + return list; +} + + +GSList* +g_slist_delete_link (GSList *list, + GSList *link) +{ + list = _g_slist_remove_link(list, link); + g_free(link); + + return list; +} + + /* Memory allocation functions */ gpointer g_malloc(gulong n_bytes) Index: eglib/gmain.h =================================================================== RCS file: /cvsroot/bluez/utils/eglib/gmain.h,v retrieving revision 1.12 diff -u -p -r1.12 gmain.h --- eglib/gmain.h 3 May 2007 15:41:43 -0000 1.12 +++ eglib/gmain.h 25 May 2007 12:28:38 -0000 @@ -191,6 +191,7 @@ int g_slist_length(GSList *list); void g_slist_foreach(GSList *list, GFunc func, void *user_data); void g_slist_free(GSList *list); +GSList *g_slist_delete_link (GSList *list, GSList *link); /* End GSList declarations */ Index: hcid/dbus-sdp.c =================================================================== RCS file: /cvsroot/bluez/utils/hcid/dbus-sdp.c,v retrieving revision 1.71 diff -u -p -r1.71 dbus-sdp.c --- hcid/dbus-sdp.c 3 May 2007 11:49:43 -0000 1.71 +++ hcid/dbus-sdp.c 25 May 2007 12:28:38 -0000 @@ -270,6 +270,7 @@ sdp_service_t sdp_service[] = { { "fax", FAX_SVCLASS_ID, "Fax" }, { "spp", SERIAL_PORT_SVCLASS_ID, "Serial Port" }, { "hsp", HEADSET_SVCLASS_ID, "Headset" }, + { "hcrp", HCR_PRINT_SVCLASS_ID, "Hardcopy Cable Replacement (Printer)" }, { NULL } }; [-- Attachment #3: Type: text/plain, Size: 286 bytes --] ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ [-- Attachment #4: Type: text/plain, Size: 164 bytes --] _______________________________________________ Bluez-devel mailing list Bluez-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/bluez-devel ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [Bluez-devel] CUPS plugin discovery bits 2007-05-25 12:30 ` Bastien Nocera @ 2007-05-25 12:58 ` Bastien Nocera 2007-05-25 15:08 ` Bastien Nocera 0 siblings, 1 reply; 21+ messages in thread From: Bastien Nocera @ 2007-05-25 12:58 UTC (permalink / raw) To: BlueZ development [-- Attachment #1: Type: text/plain, Size: 987 bytes --] On Fri, 2007-05-25 at 13:30 +0100, Bastien Nocera wrote: > On Thu, 2007-05-24 at 19:50 +0100, Bastien Nocera wrote: > <snip> > > This is most ugly. There should really be a helper function for that, or > > hcid should pass a decoded argument. > > > > Anyway, it's implemented now, along with a port to pure D-Bus, and can > > use the builtin eglib instead of the system one. > > And an updated version which pulls the IEEE1284 ID from the attributes > of the SDP record. This means that it takes 2 clicks in most config > tools to add the printer (add printer, and select the bluetooth > printer). > > If you're using the system hcid instead of the patched in bluez-utils, > you'll need to replace the line: > const char *svc_id = "hcrp"; /* aka 0x1126 */ > with: > const char *svc_id = "00001126-0000-1000-8000-00805F9B34FB"; > in cups/main.c device_get_ieee1284_id() > > Patch attached. With some indentation changes, at Marcel's request. -- Bastien Nocera <hadess@hadess.net> [-- Attachment #2: bluez-utils-cups-printer-listing-10.patch --] [-- Type: text/x-patch, Size: 16717 bytes --] Index: cups/Makefile.am =================================================================== RCS file: /cvsroot/bluez/utils/cups/Makefile.am,v retrieving revision 1.9 diff -u -p -r1.9 Makefile.am --- cups/Makefile.am 20 Aug 2006 02:21:03 -0000 1.9 +++ cups/Makefile.am 25 May 2007 12:59:53 -0000 @@ -8,8 +8,13 @@ noinst_PROGRAMS = bluetooth endif bluetooth_SOURCES = main.c sdp.c spp.c hcrp.c -bluetooth_LDADD = @BLUEZ_LIBS@ +if EXPAT +bluetooth_LDADD = @DBUS_LIBS@ @GLIB_LIBS@ @BLUEZ_LIBS@ -lexpat $(top_builddir)/common/libhelper.a +else +bluetooth_LDADD = @DBUS_LIBS@ @GLIB_LIBS@ @BLUEZ_LIBS@ $(top_builddir)/common/libhelper.a +endif -AM_CFLAGS = @BLUEZ_CFLAGS@ +AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ MAINTAINERCLEANFILES = Makefile.in + Index: cups/main.c =================================================================== RCS file: /cvsroot/bluez/utils/cups/main.c,v retrieving revision 1.6 diff -u -p -r1.6 main.c --- cups/main.c 3 Jan 2006 13:28:57 -0000 1.6 +++ cups/main.c 25 May 2007 12:59:53 -0000 @@ -38,12 +38,501 @@ #include <bluetooth/sdp.h> #include <bluetooth/sdp_lib.h> +#include <glib.h> +#include <dbus/dbus.h> +#include "../common/dbus.h" +#include "../common/sdp-xml.h" + extern int sdp_search_spp(sdp_session_t *sdp, uint8_t *channel); extern int sdp_search_hcrp(sdp_session_t *sdp, unsigned short *ctrl_psm, unsigned short *data_psm); extern int spp_print(bdaddr_t *src, bdaddr_t *dst, uint8_t channel, int fd, int copies); extern int hcrp_print(bdaddr_t *src, bdaddr_t *dst, unsigned short ctrl_psm, unsigned short data_psm, int fd, int copies); +#define PRINTER_SERVICE_CLASS_NAME "printer" + +typedef struct { + char *bdaddr; + char *name; + char *id; +} BluezCupsDevice; + +static GSList *device_list = NULL; +static GMainLoop *loop = NULL; +static DBusConnection *conn = NULL; + +#define ATTRID_1284ID 0x0300 + +static char *parse_xml_sdp(const char *xml) +{ + sdp_record_t *sdp_record; + sdp_list_t *l; + char *str = NULL; + + sdp_record = sdp_xml_parse_record(xml, strlen(xml)); + if (sdp_record == NULL) + return NULL; + for (l = sdp_record->attrlist; l != NULL; l = l->next) { + sdp_data_t *data; + + data = (sdp_data_t *) l->data; + if (data->attrId != ATTRID_1284ID) + continue; + /* Ignore the length, it's null terminated */ + str = g_strdup(data->val.str + 2); + break; + } + sdp_record_free(sdp_record); + + return str; +} + +static char *device_get_ieee1284_id(const char *adapter, const char *bdaddr) +{ + guint service_handle; + DBusMessage *message, *reply; + DBusMessageIter iter, reply_iter, iter_array; + const char *svc_id = "hcrp"; /* aka 0x1126 */ + char *xml, *id; + + /* Look for the service handle of the HCRP service */ + message = dbus_message_new_method_call("org.bluez", adapter, + "org.bluez.Adapter", + "GetRemoteServiceHandles"); + dbus_message_iter_init_append(message, &iter); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &svc_id); + + reply = dbus_connection_send_with_reply_and_block(conn, + message, -1, NULL); + if (!reply) { + dbus_message_unref(message); + return NULL; + } + + dbus_message_iter_init(reply, &reply_iter); + if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_ARRAY) { + dbus_message_unref(reply); + return NULL; + } + + /* Hopefully we only get one handle, or take a punt */ + dbus_message_iter_recurse(&reply_iter, &iter_array); + while (dbus_message_iter_get_arg_type(&iter_array) == DBUS_TYPE_UINT32) { + dbus_message_iter_get_basic(&iter_array, &service_handle); + dbus_message_iter_next(&iter_array); + } + + dbus_message_unref(reply); + + /* Now get the XML for the HCRP service record */ + message = dbus_message_new_method_call("org.bluez", adapter, + "org.bluez.Adapter", + "GetRemoteServiceRecordAsXML"); + dbus_message_iter_init_append(message, &iter); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT32, &service_handle); + + reply = dbus_connection_send_with_reply_and_block(conn, + message, -1, NULL); + dbus_message_unref(message); + if (!reply) { + return NULL; + } + + dbus_message_iter_init(reply, &reply_iter); + dbus_message_iter_get_basic(&reply_iter, &xml); + + id = parse_xml_sdp(xml); + + dbus_message_unref(reply); + + return id; +} + +static void add_device_to_list(const char *name, const char *bdaddr, const char *id) +{ + BluezCupsDevice *device; + GSList *l; + + /* Look for the device in the list */ + for (l = device_list; l != NULL; l = l->next) { + device = (BluezCupsDevice *) l->data; + + if (strcmp(device->bdaddr, bdaddr) == 0) { + g_free(device->name); + device->name = g_strdup(name); + return; + } + } + + /* Or add it to the list if it's not there */ + device = g_new0(BluezCupsDevice, 1); + device->bdaddr = g_strdup(bdaddr); + device->name = g_strdup(name); + device->id = g_strdup(id); + + device_list = g_slist_prepend(device_list, device); +} + +static char *escape_name(const char *str, char orig, char dest) +{ + char *ret, *s; + + ret = g_strdup(str); + while ((s = strchr(ret, orig)) != NULL) + s[0] = dest; + return ret; +} + +static void print_printer_details(const char *name, const char *bdaddr, const char *id) +{ + char *uri, *escaped; + guint len; + + escaped = escape_name(name, '\"', '\''); + len = strlen("bluetooth://") + 12 + 1; + uri = g_malloc(len); + snprintf(uri, len, "bluetooth://%c%c%c%c%c%c%c%c%c%c%c%c", + bdaddr[0], bdaddr[1], + bdaddr[3], bdaddr[4], + bdaddr[6], bdaddr[7], + bdaddr[9], bdaddr[10], + bdaddr[12], bdaddr[13], + bdaddr[15], bdaddr[16]); + printf("network %s \"Unknown\" \"%s (Bluetooth)\"", uri, escaped); + if (id != NULL) + printf(" \"%s\"\n", id); + else + printf ("\n"); + g_free(escaped); + g_free(uri); +} + +static gboolean device_is_printer(const char *adapter, const char *bdaddr) +{ + char *class; + DBusMessage *message, *reply; + DBusMessageIter iter, reply_iter; + + message = dbus_message_new_method_call("org.bluez", adapter, + "org.bluez.Adapter", + "GetRemoteMinorClass"); + dbus_message_iter_init_append(message, &iter); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr); + + reply = dbus_connection_send_with_reply_and_block(conn, + message, -1, NULL); + dbus_message_unref(message); + if (!reply) { + return FALSE; + } + + dbus_message_iter_init(reply, &reply_iter); + dbus_message_iter_get_basic(&reply_iter, &class); + + if (class != NULL && strcmp(class, PRINTER_SERVICE_CLASS_NAME) == 0) { + dbus_message_unref(reply); + return TRUE; + } + + return FALSE; +} + +static char *device_get_name(const char *adapter, const char *bdaddr) +{ + char *name; + DBusMessage *message, *reply; + DBusMessageIter iter, reply_iter; + + message = dbus_message_new_method_call("org.bluez", adapter, + "org.bluez.Adapter", + "GetRemoteName"); + dbus_message_iter_init_append(message, &iter); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr); + + reply = dbus_connection_send_with_reply_and_block(conn, + message, -1, NULL); + dbus_message_unref(message); + if (!reply) + return NULL; + + dbus_message_iter_init(reply, &reply_iter); + dbus_message_iter_get_basic(&reply_iter, &name); + + name = g_strdup(name); + dbus_message_unref(reply); + return name; +} + +static void remote_device_found(const char *adapter, const char *bdaddr, guint class, int rssi) +{ + uint8_t major_index = (class >> 8) & 0x1F; + uint8_t minor_index; + uint8_t shift_minor = 0; + gboolean found = FALSE; + char *name, *id; + + /* Check if we have a printer + * From hcid/dbus-adapter.c minor_class_str() */ + if (major_index != 6) + return; + + minor_index = (class >> 4) & 0x0F; + while (shift_minor < 4) { + if (((minor_index >> shift_minor) & 0x01) == 0x01) { + if (shift_minor == 3) { + found = TRUE; + break; + } + } + shift_minor++; + } + + if (!found) + return; + + name = device_get_name(adapter, bdaddr); + id = device_get_ieee1284_id(adapter, bdaddr); + add_device_to_list(name, bdaddr, id); + g_free(name); + g_free(id); +} + +static void remote_name_updated(const char *bdaddr, const char *name) +{ + add_device_to_list(name, bdaddr, NULL); +} + +static void discovery_completed(void) +{ + GSList *l; + + for (l = device_list; l != NULL; l = l->next) { + BluezCupsDevice *device = (BluezCupsDevice *) l->data; + + if (device->name == NULL) { + device->name = escape_name(device->bdaddr, + ':', '-'); + } + print_printer_details(device->name, device->bdaddr, device->id); + g_free(device->name); + g_free(device->bdaddr); + g_free(device->id); + g_free(device); + } + + g_slist_free(device_list); + device_list = NULL; + + g_main_loop_quit(loop); +} + +static void remote_device_disappeared(const char *bdaddr) +{ + GSList *l; + + for (l = device_list; l != NULL; l = l->next) { + BluezCupsDevice *device = (BluezCupsDevice *) l->data; + + if (strcmp(device->bdaddr, bdaddr) == 0) { + g_free(device->name); + g_free(device->bdaddr); + g_free(device); + device_list = g_slist_delete_link(device_list, l); + return; + } + } +} + +static gboolean list_known_printers(const char *adapter) +{ + DBusMessageIter reply_iter, iter_array; + DBusError error; + DBusMessage *message, *reply; + + message = dbus_message_new_method_call ("org.bluez", adapter, + "org.bluez.Adapter", + "ListRemoteDevices"); + if (message == NULL) + return FALSE; + + dbus_error_init(&error); + reply = dbus_connection_send_with_reply_and_block(conn, + message, -1, + &error); + dbus_message_unref(message); + if (&error != NULL && dbus_error_is_set(&error)) + return FALSE; + + dbus_message_iter_init(reply, &reply_iter); + if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_ARRAY) { + dbus_message_unref(reply); + return FALSE; + } + + dbus_message_iter_recurse(&reply_iter, &iter_array); + while (dbus_message_iter_get_arg_type(&iter_array) == DBUS_TYPE_STRING) { + char *bdaddr; + + dbus_message_iter_get_basic(&iter_array, &bdaddr); + if (device_is_printer(adapter, bdaddr)) { + char *name, *id; + name = device_get_name(adapter, bdaddr); + id = device_get_ieee1284_id(adapter, bdaddr); + add_device_to_list(name, bdaddr, id); + g_free(name); + g_free(id); + } + dbus_message_iter_next(&iter_array); + } + + dbus_message_unref(reply); + + return FALSE; +} + +static DBusHandlerResult filter_func(DBusConnection *connection, DBusMessage *message, void *user_data) +{ + const char *adapter; + + if (dbus_message_is_signal(message, "org.bluez.Adapter", + "RemoteDeviceFound")) { + char *bdaddr; + guint class; + int rssi; + + dbus_message_get_args(message, NULL, + DBUS_TYPE_STRING, &bdaddr, + DBUS_TYPE_UINT32, &class, + DBUS_TYPE_INT32, &rssi, + DBUS_TYPE_INVALID); + adapter = dbus_message_get_path(message); + remote_device_found(adapter, bdaddr, class, rssi); + } else if (dbus_message_is_signal(message, "org.bluez.Adapter", + "RemoteNameUpdated")) { + char *bdaddr, *name; + + dbus_message_get_args(message, NULL, + DBUS_TYPE_STRING, &bdaddr, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_INVALID); + remote_name_updated(bdaddr, name); + } else if (dbus_message_is_signal(message, "org.bluez.Adapter", + "RemoteDeviceDisappeared")) { + char *bdaddr; + + dbus_message_get_args(message, NULL, + DBUS_TYPE_STRING, &bdaddr, + DBUS_TYPE_INVALID); + remote_device_disappeared(bdaddr); + } else if (dbus_message_is_signal(message, "org.bluez.Adapter", + "DiscoveryCompleted")) { + discovery_completed(); + } + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static void list_printers(void) +{ + /* 1. Connect to the bus + * 2. Get the manager + * 3. Get the default adapter + * 4. Get a list of devices + * 5. Get the class of each device + * 6. Print the details from each printer device + */ + DBusError error; + dbus_bool_t hcid_exists; + DBusMessage *reply, *message; + DBusMessageIter reply_iter; + char *adapter, *match; + guint len; + + conn = init_dbus(NULL, NULL, NULL); + if (conn == NULL) + return; + + dbus_error_init(&error); + hcid_exists = dbus_bus_name_has_owner(conn, "org.bluez", &error); + if (&error != NULL && dbus_error_is_set(&error)) + return; + + if (!hcid_exists) + return; + + /* Get the default adapter */ + message = dbus_message_new_method_call("org.bluez", "/org/bluez", + "org.bluez.Manager", + "DefaultAdapter"); + if (message == NULL) { + dbus_connection_unref(conn); + return; + } + reply = dbus_connection_send_with_reply_and_block(conn, + message, -1, + &error); + dbus_message_unref(message); + if (&error != NULL && dbus_error_is_set(&error)) { + dbus_connection_unref(conn); + return; + } + + dbus_message_iter_init(reply, &reply_iter); + if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_STRING) { + dbus_message_unref(reply); + dbus_connection_unref(conn); + return; + } + dbus_message_iter_get_basic(&reply_iter, &adapter); + adapter = g_strdup(adapter); + dbus_message_unref(reply); + + if (!dbus_connection_add_filter(conn, filter_func, adapter, g_free)) { + g_free(adapter); + dbus_connection_unref(conn); + return; + } + +#define MATCH_FORMAT \ + "type='signal'," \ + "interface='org.bluez.Adapter'," \ + "sender='org.bluez'," \ + "path='%s'" + + len = strlen(MATCH_FORMAT) - 2 + strlen(adapter) + 1; + match = g_malloc(len); + snprintf(match, len, "type='signal'," + "interface='org.bluez.Adapter'," + "sender='org.bluez'," + "path='%s'", + adapter); + dbus_bus_add_match(conn, match, &error); + g_free(match); + + message = dbus_message_new_method_call("org.bluez", adapter, + "org.bluez.Adapter", + "DiscoverDevicesWithoutNameResolving"); + + if (!dbus_connection_send_with_reply(conn, + message, NULL, -1)) { + dbus_message_unref(message); + dbus_connection_unref(conn); + g_free(adapter); + return; + } + dbus_message_unref(message); + + /* Also add the the recent devices */ + g_timeout_add(0, (GSourceFunc) list_known_printers, adapter); + + loop = g_main_loop_new(NULL, TRUE); + g_main_loop_run(loop); + + dbus_connection_unref(conn); +} + /* * Usage: printer-uri job-id user title copies options [file] * @@ -73,7 +562,7 @@ int main(int argc, char *argv[]) #endif /* HAVE_SIGSET */ if (argc == 1) { - puts("network bluetooth \"Unknown\" \"Bluetooth printer\""); + list_printers(); return 0; } Index: eglib/gmain.c =================================================================== RCS file: /cvsroot/bluez/utils/eglib/gmain.c,v retrieving revision 1.27 diff -u -p -r1.27 gmain.c --- eglib/gmain.c 3 May 2007 15:41:42 -0000 1.27 +++ eglib/gmain.c 25 May 2007 12:59:54 -0000 @@ -1127,6 +1127,48 @@ void g_slist_free(GSList *list) } } +static inline GSList* +_g_slist_remove_link (GSList *list, + GSList *link) +{ + GSList *tmp; + GSList *prev; + + prev = NULL; + tmp = list; + + while (tmp) + { + if (tmp == link) + { + if (prev) + prev->next = tmp->next; + if (list == tmp) + list = list->next; + + tmp->next = NULL; + break; + } + + prev = tmp; + tmp = tmp->next; + } + + return list; +} + + +GSList* +g_slist_delete_link (GSList *list, + GSList *link) +{ + list = _g_slist_remove_link(list, link); + g_free(link); + + return list; +} + + /* Memory allocation functions */ gpointer g_malloc(gulong n_bytes) Index: eglib/gmain.h =================================================================== RCS file: /cvsroot/bluez/utils/eglib/gmain.h,v retrieving revision 1.12 diff -u -p -r1.12 gmain.h --- eglib/gmain.h 3 May 2007 15:41:43 -0000 1.12 +++ eglib/gmain.h 25 May 2007 12:59:54 -0000 @@ -191,6 +191,7 @@ int g_slist_length(GSList *list); void g_slist_foreach(GSList *list, GFunc func, void *user_data); void g_slist_free(GSList *list); +GSList *g_slist_delete_link (GSList *list, GSList *link); /* End GSList declarations */ Index: hcid/dbus-sdp.c =================================================================== RCS file: /cvsroot/bluez/utils/hcid/dbus-sdp.c,v retrieving revision 1.71 diff -u -p -r1.71 dbus-sdp.c --- hcid/dbus-sdp.c 3 May 2007 11:49:43 -0000 1.71 +++ hcid/dbus-sdp.c 25 May 2007 12:59:54 -0000 @@ -270,6 +270,7 @@ sdp_service_t sdp_service[] = { { "fax", FAX_SVCLASS_ID, "Fax" }, { "spp", SERIAL_PORT_SVCLASS_ID, "Serial Port" }, { "hsp", HEADSET_SVCLASS_ID, "Headset" }, + { "hcrp", HCR_PRINT_SVCLASS_ID, "Hardcopy Cable Replacement (Printer)" }, { NULL } }; [-- Attachment #3: Type: text/plain, Size: 286 bytes --] ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ [-- Attachment #4: Type: text/plain, Size: 164 bytes --] _______________________________________________ Bluez-devel mailing list Bluez-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/bluez-devel ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [Bluez-devel] CUPS plugin discovery bits 2007-05-25 12:58 ` Bastien Nocera @ 2007-05-25 15:08 ` Bastien Nocera 2007-05-29 3:58 ` Luiz Augusto von Dentz 2007-06-07 10:21 ` Marcel Holtmann 0 siblings, 2 replies; 21+ messages in thread From: Bastien Nocera @ 2007-05-25 15:08 UTC (permalink / raw) To: BlueZ development [-- Attachment #1: Type: text/plain, Size: 1226 bytes --] On Fri, 2007-05-25 at 13:58 +0100, Bastien Nocera wrote: > On Fri, 2007-05-25 at 13:30 +0100, Bastien Nocera wrote: > > On Thu, 2007-05-24 at 19:50 +0100, Bastien Nocera wrote: > > <snip> > > > This is most ugly. There should really be a helper function for that, or > > > hcid should pass a decoded argument. > > > > > > Anyway, it's implemented now, along with a port to pure D-Bus, and can > > > use the builtin eglib instead of the system one. > > > > And an updated version which pulls the IEEE1284 ID from the attributes > > of the SDP record. This means that it takes 2 clicks in most config > > tools to add the printer (add printer, and select the bluetooth > > printer). > > > > If you're using the system hcid instead of the patched in bluez-utils, > > you'll need to replace the line: > > const char *svc_id = "hcrp"; /* aka 0x1126 */ > > with: > > const char *svc_id = "00001126-0000-1000-8000-00805F9B34FB"; > > in cups/main.c device_get_ieee1284_id() > > > > Patch attached. > > With some indentation changes, at Marcel's request. - Don't typedef BluezCupsDevice - Fix includes from common/ - Simplify Makefile.am slightly - Remove already committed eglib changes -- Bastien Nocera <hadess@hadess.net> [-- Attachment #2: bluez-utils-cups-printer-listing-11.patch --] [-- Type: text/x-patch, Size: 15178 bytes --] Index: cups/Makefile.am =================================================================== RCS file: /cvsroot/bluez/utils/cups/Makefile.am,v retrieving revision 1.9 diff -u -p -r1.9 Makefile.am --- cups/Makefile.am 20 Aug 2006 02:21:03 -0000 1.9 +++ cups/Makefile.am 25 May 2007 15:08:15 -0000 @@ -8,8 +8,13 @@ noinst_PROGRAMS = bluetooth endif bluetooth_SOURCES = main.c sdp.c spp.c hcrp.c -bluetooth_LDADD = @BLUEZ_LIBS@ +bluetooth_LDADD = @DBUS_LIBS@ @GLIB_LIBS@ @BLUEZ_LIBS@ $(top_builddir)/common/libhelper.a -AM_CFLAGS = @BLUEZ_CFLAGS@ +if EXPAT +bluetooth_LDADD += -lexpat +endif + +AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_CFLAGS@ @GLIB_CFLAGS@ -I$(top_srcdir)/common/ MAINTAINERCLEANFILES = Makefile.in + Index: cups/main.c =================================================================== RCS file: /cvsroot/bluez/utils/cups/main.c,v retrieving revision 1.6 diff -u -p -r1.6 main.c --- cups/main.c 3 Jan 2006 13:28:57 -0000 1.6 +++ cups/main.c 25 May 2007 15:08:16 -0000 @@ -38,12 +38,502 @@ #include <bluetooth/sdp.h> #include <bluetooth/sdp_lib.h> +#include <glib.h> +#include <dbus/dbus.h> + +#include "dbus.h" +#include "sdp-xml.h" + extern int sdp_search_spp(sdp_session_t *sdp, uint8_t *channel); extern int sdp_search_hcrp(sdp_session_t *sdp, unsigned short *ctrl_psm, unsigned short *data_psm); extern int spp_print(bdaddr_t *src, bdaddr_t *dst, uint8_t channel, int fd, int copies); extern int hcrp_print(bdaddr_t *src, bdaddr_t *dst, unsigned short ctrl_psm, unsigned short data_psm, int fd, int copies); +#define PRINTER_SERVICE_CLASS_NAME "printer" + +typedef struct cups_device { + char *bdaddr; + char *name; + char *id; +}; + +static GSList *device_list = NULL; +static GMainLoop *loop = NULL; +static DBusConnection *conn = NULL; + +#define ATTRID_1284ID 0x0300 + +static char *parse_xml_sdp(const char *xml) +{ + sdp_record_t *sdp_record; + sdp_list_t *l; + char *str = NULL; + + sdp_record = sdp_xml_parse_record(xml, strlen(xml)); + if (sdp_record == NULL) + return NULL; + for (l = sdp_record->attrlist; l != NULL; l = l->next) { + sdp_data_t *data; + + data = (sdp_data_t *) l->data; + if (data->attrId != ATTRID_1284ID) + continue; + /* Ignore the length, it's null terminated */ + str = g_strdup(data->val.str + 2); + break; + } + sdp_record_free(sdp_record); + + return str; +} + +static char *device_get_ieee1284_id(const char *adapter, const char *bdaddr) +{ + guint service_handle; + DBusMessage *message, *reply; + DBusMessageIter iter, reply_iter, iter_array; + const char *svc_id = "hcrp"; /* aka 0x1126 */ + char *xml, *id; + + /* Look for the service handle of the HCRP service */ + message = dbus_message_new_method_call("org.bluez", adapter, + "org.bluez.Adapter", + "GetRemoteServiceHandles"); + dbus_message_iter_init_append(message, &iter); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &svc_id); + + reply = dbus_connection_send_with_reply_and_block(conn, + message, -1, NULL); + if (!reply) { + dbus_message_unref(message); + return NULL; + } + + dbus_message_iter_init(reply, &reply_iter); + if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_ARRAY) { + dbus_message_unref(reply); + return NULL; + } + + /* Hopefully we only get one handle, or take a punt */ + dbus_message_iter_recurse(&reply_iter, &iter_array); + while (dbus_message_iter_get_arg_type(&iter_array) == DBUS_TYPE_UINT32) { + dbus_message_iter_get_basic(&iter_array, &service_handle); + dbus_message_iter_next(&iter_array); + } + + dbus_message_unref(reply); + + /* Now get the XML for the HCRP service record */ + message = dbus_message_new_method_call("org.bluez", adapter, + "org.bluez.Adapter", + "GetRemoteServiceRecordAsXML"); + dbus_message_iter_init_append(message, &iter); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_UINT32, &service_handle); + + reply = dbus_connection_send_with_reply_and_block(conn, + message, -1, NULL); + dbus_message_unref(message); + if (!reply) { + return NULL; + } + + dbus_message_iter_init(reply, &reply_iter); + dbus_message_iter_get_basic(&reply_iter, &xml); + + id = parse_xml_sdp(xml); + + dbus_message_unref(reply); + + return id; +} + +static void add_device_to_list(const char *name, const char *bdaddr, const char *id) +{ + struct cups_device *device; + GSList *l; + + /* Look for the device in the list */ + for (l = device_list; l != NULL; l = l->next) { + device = (struct cups_device *) l->data; + + if (strcmp(device->bdaddr, bdaddr) == 0) { + g_free(device->name); + device->name = g_strdup(name); + return; + } + } + + /* Or add it to the list if it's not there */ + device = g_new0(struct cups_device, 1); + device->bdaddr = g_strdup(bdaddr); + device->name = g_strdup(name); + device->id = g_strdup(id); + + device_list = g_slist_prepend(device_list, device); +} + +static char *escape_name(const char *str, char orig, char dest) +{ + char *ret, *s; + + ret = g_strdup(str); + while ((s = strchr(ret, orig)) != NULL) + s[0] = dest; + return ret; +} + +static void print_printer_details(const char *name, const char *bdaddr, const char *id) +{ + char *uri, *escaped; + guint len; + + escaped = escape_name(name, '\"', '\''); + len = strlen("bluetooth://") + 12 + 1; + uri = g_malloc(len); + snprintf(uri, len, "bluetooth://%c%c%c%c%c%c%c%c%c%c%c%c", + bdaddr[0], bdaddr[1], + bdaddr[3], bdaddr[4], + bdaddr[6], bdaddr[7], + bdaddr[9], bdaddr[10], + bdaddr[12], bdaddr[13], + bdaddr[15], bdaddr[16]); + printf("network %s \"Unknown\" \"%s (Bluetooth)\"", uri, escaped); + if (id != NULL) + printf(" \"%s\"\n", id); + else + printf ("\n"); + g_free(escaped); + g_free(uri); +} + +static gboolean device_is_printer(const char *adapter, const char *bdaddr) +{ + char *class; + DBusMessage *message, *reply; + DBusMessageIter iter, reply_iter; + + message = dbus_message_new_method_call("org.bluez", adapter, + "org.bluez.Adapter", + "GetRemoteMinorClass"); + dbus_message_iter_init_append(message, &iter); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr); + + reply = dbus_connection_send_with_reply_and_block(conn, + message, -1, NULL); + dbus_message_unref(message); + if (!reply) { + return FALSE; + } + + dbus_message_iter_init(reply, &reply_iter); + dbus_message_iter_get_basic(&reply_iter, &class); + + if (class != NULL && strcmp(class, PRINTER_SERVICE_CLASS_NAME) == 0) { + dbus_message_unref(reply); + return TRUE; + } + + return FALSE; +} + +static char *device_get_name(const char *adapter, const char *bdaddr) +{ + char *name; + DBusMessage *message, *reply; + DBusMessageIter iter, reply_iter; + + message = dbus_message_new_method_call("org.bluez", adapter, + "org.bluez.Adapter", + "GetRemoteName"); + dbus_message_iter_init_append(message, &iter); + dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr); + + reply = dbus_connection_send_with_reply_and_block(conn, + message, -1, NULL); + dbus_message_unref(message); + if (!reply) + return NULL; + + dbus_message_iter_init(reply, &reply_iter); + dbus_message_iter_get_basic(&reply_iter, &name); + + name = g_strdup(name); + dbus_message_unref(reply); + return name; +} + +static void remote_device_found(const char *adapter, const char *bdaddr, guint class, int rssi) +{ + uint8_t major_index = (class >> 8) & 0x1F; + uint8_t minor_index; + uint8_t shift_minor = 0; + gboolean found = FALSE; + char *name, *id; + + /* Check if we have a printer + * From hcid/dbus-adapter.c minor_class_str() */ + if (major_index != 6) + return; + + minor_index = (class >> 4) & 0x0F; + while (shift_minor < 4) { + if (((minor_index >> shift_minor) & 0x01) == 0x01) { + if (shift_minor == 3) { + found = TRUE; + break; + } + } + shift_minor++; + } + + if (!found) + return; + + name = device_get_name(adapter, bdaddr); + id = device_get_ieee1284_id(adapter, bdaddr); + add_device_to_list(name, bdaddr, id); + g_free(name); + g_free(id); +} + +static void remote_name_updated(const char *bdaddr, const char *name) +{ + add_device_to_list(name, bdaddr, NULL); +} + +static void discovery_completed(void) +{ + GSList *l; + + for (l = device_list; l != NULL; l = l->next) { + struct cups_device *device = (struct cups_device *) l->data; + + if (device->name == NULL) { + device->name = escape_name(device->bdaddr, + ':', '-'); + } + print_printer_details(device->name, device->bdaddr, device->id); + g_free(device->name); + g_free(device->bdaddr); + g_free(device->id); + g_free(device); + } + + g_slist_free(device_list); + device_list = NULL; + + g_main_loop_quit(loop); +} + +static void remote_device_disappeared(const char *bdaddr) +{ + GSList *l; + + for (l = device_list; l != NULL; l = l->next) { + struct cups_device *device = (struct cups_device *) l->data; + + if (strcmp(device->bdaddr, bdaddr) == 0) { + g_free(device->name); + g_free(device->bdaddr); + g_free(device); + device_list = g_slist_delete_link(device_list, l); + return; + } + } +} + +static gboolean list_known_printers(const char *adapter) +{ + DBusMessageIter reply_iter, iter_array; + DBusError error; + DBusMessage *message, *reply; + + message = dbus_message_new_method_call ("org.bluez", adapter, + "org.bluez.Adapter", + "ListRemoteDevices"); + if (message == NULL) + return FALSE; + + dbus_error_init(&error); + reply = dbus_connection_send_with_reply_and_block(conn, + message, -1, + &error); + dbus_message_unref(message); + if (&error != NULL && dbus_error_is_set(&error)) + return FALSE; + + dbus_message_iter_init(reply, &reply_iter); + if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_ARRAY) { + dbus_message_unref(reply); + return FALSE; + } + + dbus_message_iter_recurse(&reply_iter, &iter_array); + while (dbus_message_iter_get_arg_type(&iter_array) == DBUS_TYPE_STRING) { + char *bdaddr; + + dbus_message_iter_get_basic(&iter_array, &bdaddr); + if (device_is_printer(adapter, bdaddr)) { + char *name, *id; + name = device_get_name(adapter, bdaddr); + id = device_get_ieee1284_id(adapter, bdaddr); + add_device_to_list(name, bdaddr, id); + g_free(name); + g_free(id); + } + dbus_message_iter_next(&iter_array); + } + + dbus_message_unref(reply); + + return FALSE; +} + +static DBusHandlerResult filter_func(DBusConnection *connection, DBusMessage *message, void *user_data) +{ + const char *adapter; + + if (dbus_message_is_signal(message, "org.bluez.Adapter", + "RemoteDeviceFound")) { + char *bdaddr; + guint class; + int rssi; + + dbus_message_get_args(message, NULL, + DBUS_TYPE_STRING, &bdaddr, + DBUS_TYPE_UINT32, &class, + DBUS_TYPE_INT32, &rssi, + DBUS_TYPE_INVALID); + adapter = dbus_message_get_path(message); + remote_device_found(adapter, bdaddr, class, rssi); + } else if (dbus_message_is_signal(message, "org.bluez.Adapter", + "RemoteNameUpdated")) { + char *bdaddr, *name; + + dbus_message_get_args(message, NULL, + DBUS_TYPE_STRING, &bdaddr, + DBUS_TYPE_STRING, &name, + DBUS_TYPE_INVALID); + remote_name_updated(bdaddr, name); + } else if (dbus_message_is_signal(message, "org.bluez.Adapter", + "RemoteDeviceDisappeared")) { + char *bdaddr; + + dbus_message_get_args(message, NULL, + DBUS_TYPE_STRING, &bdaddr, + DBUS_TYPE_INVALID); + remote_device_disappeared(bdaddr); + } else if (dbus_message_is_signal(message, "org.bluez.Adapter", + "DiscoveryCompleted")) { + discovery_completed(); + } + + return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; +} + +static void list_printers(void) +{ + /* 1. Connect to the bus + * 2. Get the manager + * 3. Get the default adapter + * 4. Get a list of devices + * 5. Get the class of each device + * 6. Print the details from each printer device + */ + DBusError error; + dbus_bool_t hcid_exists; + DBusMessage *reply, *message; + DBusMessageIter reply_iter; + char *adapter, *match; + guint len; + + conn = init_dbus(NULL, NULL, NULL); + if (conn == NULL) + return; + + dbus_error_init(&error); + hcid_exists = dbus_bus_name_has_owner(conn, "org.bluez", &error); + if (&error != NULL && dbus_error_is_set(&error)) + return; + + if (!hcid_exists) + return; + + /* Get the default adapter */ + message = dbus_message_new_method_call("org.bluez", "/org/bluez", + "org.bluez.Manager", + "DefaultAdapter"); + if (message == NULL) { + dbus_connection_unref(conn); + return; + } + reply = dbus_connection_send_with_reply_and_block(conn, + message, -1, + &error); + dbus_message_unref(message); + if (&error != NULL && dbus_error_is_set(&error)) { + dbus_connection_unref(conn); + return; + } + + dbus_message_iter_init(reply, &reply_iter); + if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_STRING) { + dbus_message_unref(reply); + dbus_connection_unref(conn); + return; + } + dbus_message_iter_get_basic(&reply_iter, &adapter); + adapter = g_strdup(adapter); + dbus_message_unref(reply); + + if (!dbus_connection_add_filter(conn, filter_func, adapter, g_free)) { + g_free(adapter); + dbus_connection_unref(conn); + return; + } + +#define MATCH_FORMAT \ + "type='signal'," \ + "interface='org.bluez.Adapter'," \ + "sender='org.bluez'," \ + "path='%s'" + + len = strlen(MATCH_FORMAT) - 2 + strlen(adapter) + 1; + match = g_malloc(len); + snprintf(match, len, "type='signal'," + "interface='org.bluez.Adapter'," + "sender='org.bluez'," + "path='%s'", + adapter); + dbus_bus_add_match(conn, match, &error); + g_free(match); + + message = dbus_message_new_method_call("org.bluez", adapter, + "org.bluez.Adapter", + "DiscoverDevicesWithoutNameResolving"); + + if (!dbus_connection_send_with_reply(conn, + message, NULL, -1)) { + dbus_message_unref(message); + dbus_connection_unref(conn); + g_free(adapter); + return; + } + dbus_message_unref(message); + + /* Also add the the recent devices */ + g_timeout_add(0, (GSourceFunc) list_known_printers, adapter); + + loop = g_main_loop_new(NULL, TRUE); + g_main_loop_run(loop); + + dbus_connection_unref(conn); +} + /* * Usage: printer-uri job-id user title copies options [file] * @@ -73,7 +563,7 @@ int main(int argc, char *argv[]) #endif /* HAVE_SIGSET */ if (argc == 1) { - puts("network bluetooth \"Unknown\" \"Bluetooth printer\""); + list_printers(); return 0; } Index: hcid/dbus-sdp.c =================================================================== RCS file: /cvsroot/bluez/utils/hcid/dbus-sdp.c,v retrieving revision 1.74 diff -u -p -r1.74 dbus-sdp.c --- hcid/dbus-sdp.c 9 May 2007 10:12:59 -0000 1.74 +++ hcid/dbus-sdp.c 25 May 2007 15:08:16 -0000 @@ -284,6 +284,7 @@ sdp_service_t sdp_service[] = { { "fax", FAX_SVCLASS_ID, "Fax" }, { "spp", SERIAL_PORT_SVCLASS_ID, "Serial Port" }, { "hsp", HEADSET_SVCLASS_ID, "Headset" }, + { "hcrp", HCR_PRINT_SVCLASS_ID, "Hardcopy Cable Replacement (Printer)" }, { NULL } }; [-- Attachment #3: Type: text/plain, Size: 286 bytes --] ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ [-- Attachment #4: Type: text/plain, Size: 164 bytes --] _______________________________________________ Bluez-devel mailing list Bluez-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/bluez-devel ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [Bluez-devel] CUPS plugin discovery bits 2007-05-25 15:08 ` Bastien Nocera @ 2007-05-29 3:58 ` Luiz Augusto von Dentz 2007-05-29 10:26 ` Bastien Nocera 2007-06-07 10:21 ` Marcel Holtmann 1 sibling, 1 reply; 21+ messages in thread From: Luiz Augusto von Dentz @ 2007-05-29 3:58 UTC (permalink / raw) To: BlueZ development [-- Attachment #1.1: Type: text/plain, Size: 2747 bytes --] I consider this as a wizard for printers, like in NetwokManager the network wizard also does start a discovery and it work like a charm but in my opinion it doesnt belong to bluez utils. Having each wizard to rely in its own discovery is probably a bad design, we can probably integrate all wizard together and then having services configuring them in the background. This way we could leave to the user to use periodic scan and popup specific device wizard dependent on each service when active. Also in my opinion it should exist a printer service for those that want to configure its devices that are not in discoverable mode. Btw, The printer wizard as it is now wont work with periodic discovery, signals DiscoveryStarted and DiscoveryCompleted are not emitted while in periodic discovery. On 5/25/07, Bastien Nocera <hadess@hadess.net> wrote: > > On Fri, 2007-05-25 at 13:58 +0100, Bastien Nocera wrote: > > On Fri, 2007-05-25 at 13:30 +0100, Bastien Nocera wrote: > > > On Thu, 2007-05-24 at 19:50 +0100, Bastien Nocera wrote: > > > <snip> > > > > This is most ugly. There should really be a helper function for > that, or > > > > hcid should pass a decoded argument. > > > > > > > > Anyway, it's implemented now, along with a port to pure D-Bus, and > can > > > > use the builtin eglib instead of the system one. > > > > > > And an updated version which pulls the IEEE1284 ID from the attributes > > > of the SDP record. This means that it takes 2 clicks in most config > > > tools to add the printer (add printer, and select the bluetooth > > > printer). > > > > > > If you're using the system hcid instead of the patched in bluez-utils, > > > you'll need to replace the line: > > > const char *svc_id = "hcrp"; /* aka 0x1126 */ > > > with: > > > const char *svc_id = "00001126-0000-1000-8000-00805F9B34FB"; > > > in cups/main.c device_get_ieee1284_id() > > > > > > Patch attached. > > > > With some indentation changes, at Marcel's request. > > - Don't typedef BluezCupsDevice > - Fix includes from common/ > - Simplify Makefile.am slightly > - Remove already committed eglib changes > > -- > Bastien Nocera <hadess@hadess.net> > > ------------------------------------------------------------------------- > This SF.net email is sponsored by DB2 Express > Download DB2 Express C - the FREE version of DB2 express and take > control of your XML. No limits. Just data. Click to get it now. > http://sourceforge.net/powerbar/db2/ > _______________________________________________ > Bluez-devel mailing list > Bluez-devel@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/bluez-devel > > > -- Luiz Augusto von Dentz Engenheiro de Computação [-- Attachment #1.2: Type: text/html, Size: 3525 bytes --] [-- Attachment #2: Type: text/plain, Size: 286 bytes --] ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ [-- Attachment #3: Type: text/plain, Size: 164 bytes --] _______________________________________________ Bluez-devel mailing list Bluez-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/bluez-devel ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [Bluez-devel] CUPS plugin discovery bits 2007-05-29 3:58 ` Luiz Augusto von Dentz @ 2007-05-29 10:26 ` Bastien Nocera 2007-05-29 13:18 ` Luiz Augusto von Dentz 0 siblings, 1 reply; 21+ messages in thread From: Bastien Nocera @ 2007-05-29 10:26 UTC (permalink / raw) To: BlueZ development On Tue, 2007-05-29 at 00:58 -0300, Luiz Augusto von Dentz wrote: > I consider this as a wizard for printers, like in NetwokManager the > network wizard also > does start a discovery and it work like a charm but in my opinion it > doesnt belong to bluez utils. It's a standard feature of cups backends. If they support it, they should list the accessible/known printers in the vicinity. > Having each wizard to rely in its own discovery is probably a bad > design, we can probably integrate > all wizard together and then having services configuring them in the > background. This way we > could leave to the user to use periodic scan and popup specific device > wizard dependent on > each service when active. Also in my opinion it should exist a printer > service for those that want to > configure its devices that are not in discoverable mode. True, it would be much better. But in the meanwhile, this patch simply implements a CUPS feature and allows us to have some basic integration in the distribution-provided printer tools. Being able to configure the printer via a bluetooth configuration wizard requires a bit more work, but it's also on my plans. There should be a CUPS service that would allow hcid to add/remove bluetooth printers from cups with minimum user interaction. > Btw, The printer wizard as it is now wont work with periodic > discovery, signals DiscoveryStarted and > DiscoveryCompleted are not emitted while in periodic discovery. The cups backend isn't supposed to run forever, so it can't do periodic discovery. -- Bastien Nocera <hadess@hadess.net> ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ _______________________________________________ Bluez-devel mailing list Bluez-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/bluez-devel ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [Bluez-devel] CUPS plugin discovery bits 2007-05-29 10:26 ` Bastien Nocera @ 2007-05-29 13:18 ` Luiz Augusto von Dentz 2007-05-29 13:37 ` Marcel Holtmann 0 siblings, 1 reply; 21+ messages in thread From: Luiz Augusto von Dentz @ 2007-05-29 13:18 UTC (permalink / raw) To: BlueZ development [-- Attachment #1.1: Type: text/plain, Size: 2985 bytes --] Comments in line: On 5/29/07, Bastien Nocera <hadess@hadess.net> wrote: > > On Tue, 2007-05-29 at 00:58 -0300, Luiz Augusto von Dentz wrote: > > I consider this as a wizard for printers, like in NetwokManager the > > network wizard also > > does start a discovery and it work like a charm but in my opinion it > > doesnt belong to bluez utils. > > It's a standard feature of cups backends. If they support it, they > should list the accessible/known printers in the vicinity. > > > Having each wizard to rely in its own discovery is probably a bad > > design, we can probably integrate > > all wizard together and then having services configuring them in the > > background. This way we > > could leave to the user to use periodic scan and popup specific device > > wizard dependent on > > each service when active. Also in my opinion it should exist a printer > > service for those that want to > > configure its devices that are not in discoverable mode. > > True, it would be much better. But in the meanwhile, this patch simply > implements a CUPS feature and allows us to have some basic integration > in the distribution-provided printer tools. So we may mark this as subject to change. Being able to configure the printer via a bluetooth configuration wizard > requires a bit more work, but it's also on my plans. There should be a > CUPS service that would allow hcid to add/remove bluetooth printers from > cups with minimum user interaction. My idea is to have printer service more generic, the bluetooth wizard could do CUPS integration as it would integrate with any other system wide integration. > Btw, The printer wizard as it is now wont work with periodic > > discovery, signals DiscoveryStarted and > > DiscoveryCompleted are not emitted while in periodic discovery. > > The cups backend isn't supposed to run forever, so it can't do periodic > discovery. Well that is not the case of being running forever but you could probably test if the periodic scan is active before you start a blocking discovery. My main concern is about multiple process doing this, the probability of having collisions while doing sdp searches could be very high as it is very common to have more than one functionality in a device, this leaves wizard processes very complicated and may force them to reschedule on each collision . -- > Bastien Nocera <hadess@hadess.net> > > > ------------------------------------------------------------------------- > This SF.net email is sponsored by DB2 Express > Download DB2 Express C - the FREE version of DB2 express and take > control of your XML. No limits. Just data. Click to get it now. > http://sourceforge.net/powerbar/db2/ > _______________________________________________ > Bluez-devel mailing list > Bluez-devel@lists.sourceforge.net > https://lists.sourceforge.net/lists/listinfo/bluez-devel > -- Luiz Augusto von Dentz Engenheiro de Computação [-- Attachment #1.2: Type: text/html, Size: 4072 bytes --] [-- Attachment #2: Type: text/plain, Size: 286 bytes --] ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ [-- Attachment #3: Type: text/plain, Size: 164 bytes --] _______________________________________________ Bluez-devel mailing list Bluez-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/bluez-devel ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [Bluez-devel] CUPS plugin discovery bits 2007-05-29 13:18 ` Luiz Augusto von Dentz @ 2007-05-29 13:37 ` Marcel Holtmann 0 siblings, 0 replies; 21+ messages in thread From: Marcel Holtmann @ 2007-05-29 13:37 UTC (permalink / raw) To: BlueZ development Hi Luiz, > > Btw, The printer wizard as it is now wont work with periodic > > discovery, signals DiscoveryStarted and > > DiscoveryCompleted are not emitted while in > periodic discovery. > > The cups backend isn't supposed to run forever, so it can't do > periodic > discovery. > > Well that is not the case of being running forever but you could > probably > test if the periodic scan is active before you start a blocking > discovery. > My main concern is about multiple process doing this, the probability > of > having collisions while doing sdp searches could be very high as it is > very > common to have more than one functionality in a device, this leaves > wizard > processes very complicated and may force them to reschedule on each > collision . it is fine to start an inquiry while you are in periodic inquiry. With the exception that some chips don't allow that. It is also fine to create an ACL link while in periodic inquiry since the device then will stop its inquiry train automatically and switch to page for the ACL link. After it it will continue with the periodic inquiry as before. The kernel now takes care of serializing the ACL link creation. This works perfectly fine. There is one small glitch with remote name resolve that doesn't trigger the ACL queue. However real name request have been always a problem. However over D-Bus you only get cached names or an error anyway. The only exception is if you in inquiry or periodic inquiry. While the inquiry is no problem, we have to check with the periodic inquiry if we create a deadlock. Regards Marcel ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ _______________________________________________ Bluez-devel mailing list Bluez-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/bluez-devel ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [Bluez-devel] CUPS plugin discovery bits 2007-05-25 15:08 ` Bastien Nocera 2007-05-29 3:58 ` Luiz Augusto von Dentz @ 2007-06-07 10:21 ` Marcel Holtmann 2007-06-07 12:59 ` Bastien Nocera 1 sibling, 1 reply; 21+ messages in thread From: Marcel Holtmann @ 2007-06-07 10:21 UTC (permalink / raw) To: BlueZ development Hi Bastien, > > With some indentation changes, at Marcel's request. > > - Don't typedef BluezCupsDevice > - Fix includes from common/ > - Simplify Makefile.am slightly > - Remove already committed eglib changes with some fixes and cleanups, the has now been committed to the CVS. Regards Marcel ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ _______________________________________________ Bluez-devel mailing list Bluez-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/bluez-devel ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [Bluez-devel] CUPS plugin discovery bits 2007-06-07 10:21 ` Marcel Holtmann @ 2007-06-07 12:59 ` Bastien Nocera 0 siblings, 0 replies; 21+ messages in thread From: Bastien Nocera @ 2007-06-07 12:59 UTC (permalink / raw) To: BlueZ development On Thu, 2007-06-07 at 12:21 +0200, Marcel Holtmann wrote: > Hi Bastien, > > > > With some indentation changes, at Marcel's request. > > > > - Don't typedef BluezCupsDevice > > - Fix includes from common/ > > - Simplify Makefile.am slightly > > - Remove already committed eglib changes > > with some fixes and cleanups, the has now been committed to the CVS. Great stuff, thanks! -- Bastien Nocera <hadess@hadess.net> ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ _______________________________________________ Bluez-devel mailing list Bluez-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/bluez-devel ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [Bluez-devel] CUPS plugin discovery bits 2007-05-23 15:51 ` Marcel Holtmann 2007-05-23 15:57 ` Tim Waugh 2007-05-23 16:15 ` Bastien Nocera @ 2007-05-24 15:03 ` Bastien Nocera 2007-05-24 15:20 ` Marcel Holtmann 2 siblings, 1 reply; 21+ messages in thread From: Bastien Nocera @ 2007-05-24 15:03 UTC (permalink / raw) To: BlueZ development; +Cc: twaugh [-- Attachment #1: Type: text/plain, Size: 1603 bytes --] On Wed, 2007-05-23 at 17:51 +0200, Marcel Holtmann wrote: > Hi Bastien, > > > Here's a patch against CVS bluez-utils to add discovery to the CUPS > > backend. With this, it means that most CUPS front-end will be able to > > list visible printers when adding a new one, be it through the web > > interface or other front-ends (like Fedora' system-config-printer). > > > > It adds D-Bus and glib as dependencies for the backend (not that it > > matters that much...). > > it actually does. We provide an eGlib for embedded systems and so when > compiled with GLib, we only use that function subset. > > And second you use the GLib D-Bus bindings. I am not willing to create > these dependencies for a "daemon" package. The dependency is already optional (and if not, I can make it so). I've looked at what using dbus directly would entail, and I'm not sure that's a good use of my (or anyone's) time. The code would be much more complicated than it would need to be, and certainly not any more readable. In the worst case, how about moving the cups plugin to another module? > Actually that is the reason why we wanna go > for a printing service in the future. I still haven't heard the benefits, or features that service would have. Unless you want to pass data from a client, over dbus to this printing service, which I don't think is a good idea given the potential size of the data being passed over. If anyone is involved with that, a draft API would be appreciated. This latest patch avoids untranslated messages getting to the end-user. Cheers -- Bastien Nocera <hadess@hadess.net> [-- Attachment #2: bluez-utils-cups-printer-listing-5.patch --] [-- Type: text/x-patch, Size: 10557 bytes --] Index: acinclude.m4 =================================================================== RCS file: /cvsroot/bluez/utils/acinclude.m4,v retrieving revision 1.107 diff -u -p -r1.107 acinclude.m4 --- acinclude.m4 8 Apr 2007 19:56:52 -0000 1.107 +++ acinclude.m4 24 May 2007 14:54:17 -0000 @@ -78,6 +78,8 @@ AC_DEFUN([AC_PATH_GLIB], [ PKG_CHECK_MODULES(GLIB, glib-2.0, glib_found=yes, glib_found=no) AC_SUBST(GLIB_CFLAGS) AC_SUBST(GLIB_LIBS) + GLIB_GENMARSHAL=`$PKG_CONFIG --variable=glib_genmarshal glib-2.0` + AC_SUBST(GLIB_GENMARSHAL) ]) AC_DEFUN([AC_PATH_DBUS], [ Index: cups/Makefile.am =================================================================== RCS file: /cvsroot/bluez/utils/cups/Makefile.am,v retrieving revision 1.9 diff -u -p -r1.9 Makefile.am --- cups/Makefile.am 20 Aug 2006 02:21:03 -0000 1.9 +++ cups/Makefile.am 24 May 2007 14:54:17 -0000 @@ -7,9 +7,19 @@ else noinst_PROGRAMS = bluetooth endif -bluetooth_SOURCES = main.c sdp.c spp.c hcrp.c -bluetooth_LDADD = @BLUEZ_LIBS@ +MARSHAL_FILES = bluez-cups-marshal.h bluez-cups-marshal.c -AM_CFLAGS = @BLUEZ_CFLAGS@ +bluetooth_SOURCES = main.c sdp.c spp.c hcrp.c $(MARSHAL_FILES) +bluetooth_LDADD = @DBUS_GLIB_LIBS@ @BLUEZ_LIBS@ -MAINTAINERCLEANFILES = Makefile.in +bluez-cups-marshal.h: bluez-cups-marshal.list + $(GLIB_GENMARSHAL) --prefix=bluez_cups_marshal $< --header > $@ +bluez-cups-marshal.c: bluez-cups-marshal.list + $(GLIB_GENMARSHAL) --prefix=bluez_cups_marshal $< --body > $@ +main.c: $(MARSHAL_FILES) + +AM_CFLAGS = @BLUEZ_CFLAGS@ @DBUS_GLIB_CFLAGS@ + +MAINTAINERCLEANFILES = Makefile.in $(MARSHAL_FILES) +CLEANFILES = $(MARSHAL_FILES) +EXTRA_DIST = bluez-cups-marshal.list Index: cups/main.c =================================================================== RCS file: /cvsroot/bluez/utils/cups/main.c,v retrieving revision 1.6 diff -u -p -r1.6 main.c --- cups/main.c 3 Jan 2006 13:28:57 -0000 1.6 +++ cups/main.c 24 May 2007 14:54:17 -0000 @@ -38,12 +38,313 @@ #include <bluetooth/sdp.h> #include <bluetooth/sdp_lib.h> +#include <dbus/dbus-glib.h> +#include "bluez-cups-marshal.h" + extern int sdp_search_spp(sdp_session_t *sdp, uint8_t *channel); extern int sdp_search_hcrp(sdp_session_t *sdp, unsigned short *ctrl_psm, unsigned short *data_psm); extern int spp_print(bdaddr_t *src, bdaddr_t *dst, uint8_t channel, int fd, int copies); extern int hcrp_print(bdaddr_t *src, bdaddr_t *dst, unsigned short ctrl_psm, unsigned short data_psm, int fd, int copies); +#define PRINTER_SERVICE_CLASS_NAME "printer" + +typedef struct { + char *bdaddr; + char *name; +} BluezCupsDevice; + +static GList *device_list = NULL; +static GMainLoop *loop = NULL; + +static void +add_device_to_list(const char *name, const char *bdaddr) +{ + BluezCupsDevice *device; + GList *l; + + /* Look for the device in the list */ + for (l = device_list; l != NULL; l = l->next) { + device = (BluezCupsDevice *) l->data; + + if (strcmp(device->bdaddr, bdaddr) == 0) { + g_free(device->name); + device->name = g_strdup(name); + return; + } + } + + /* Or add it to the list if it's not there */ + device = g_new0(BluezCupsDevice, 1); + device->bdaddr = g_strdup(bdaddr); + device->name = g_strdup(name); + + device_list = g_list_prepend(device_list, device); +} + +static void +print_printer_details(const char *name, const char *bdaddr) +{ + char *uri, *escaped; + + escaped = g_strdelimit(g_strdup(name), "\"", '\''); + uri = g_strdup_printf("bluetooth://%c%c%c%c%c%c%c%c%c%c%c%c", + bdaddr[0], bdaddr[1], + bdaddr[3], bdaddr[4], + bdaddr[6], bdaddr[7], + bdaddr[9], bdaddr[10], + bdaddr[12], bdaddr[13], + bdaddr[15], bdaddr[16]); + g_print("network %s \"Unknown\" \"%s (Bluetooth)\"\n", uri, escaped); + g_free(escaped); +} + +static gboolean +device_is_printer(DBusGProxy *object, const char *bdaddr) +{ + GError *e = NULL; + char *class; + + dbus_g_proxy_call(object, "GetRemoteMinorClass", &e, + G_TYPE_STRING, bdaddr, G_TYPE_INVALID, + G_TYPE_STRING, &class, G_TYPE_INVALID); + + if (e == NULL && g_str_equal(class, PRINTER_SERVICE_CLASS_NAME)) { + return TRUE; + } else if(e != NULL) { + g_error_free(e); + } + + return FALSE; +} + +static void +add_devices_to_list(DBusGProxy *object, const char **array) +{ + GError *e = NULL; + while (*array) { + const char *name; + + if (!device_is_printer(object, *array)) { + array++; + continue; + } + dbus_g_proxy_call (object, "GetRemoteName", &e, + G_TYPE_STRING, *array, G_TYPE_INVALID, + G_TYPE_STRING, &name, G_TYPE_INVALID); + if (e == NULL) { + add_device_to_list (name, *array); + } else { + g_error_free (e); + e = NULL; + } + array++; + } +} + +static void +remote_device_found(DBusGProxy *object, + const char *bdaddr, guint class, int rssi, + gpointer user_data) +{ + GError *e = NULL; + const char *name; + + /* Don't add non-printer devices */ + if (!device_is_printer(object, bdaddr)) + return; + + dbus_g_proxy_call(object, "GetRemoteName", &e, + G_TYPE_STRING, bdaddr, G_TYPE_INVALID, + G_TYPE_STRING, &name, G_TYPE_INVALID); + + if(e != NULL) { + const char *name; + + name = dbus_g_error_get_name(e); + if (g_str_equal(name, "org.bluez.Error.RequestDeferred") != FALSE) { + add_device_to_list(NULL, bdaddr); + } + g_error_free(e); + } else { + add_device_to_list(name, bdaddr); + } +} + +static void +remote_name_updated(DBusGProxy *object, + const char *bdaddr, const char *name, + gpointer user_data) +{ + add_device_to_list(name, bdaddr); +} + +static void +discovery_completed(DBusGProxy *object, gpointer user_data) +{ + GList *l; + + for (l = device_list; l != NULL; l = l->next) { + BluezCupsDevice *device = (BluezCupsDevice *) l->data; + + if (device->name == NULL) { + device->name = g_strdelimit(g_strdup(device->bdaddr), + ":", '-'); + } + print_printer_details(device->name, device->bdaddr); + g_free(device->name); + g_free(device->bdaddr); + g_free(device); + } + + g_list_free(device_list); + device_list = NULL; + + g_main_loop_quit(loop); +} + +static void +remote_device_disappeared(DBusGProxy *object, + const char *bdaddr, + gpointer user_data) +{ + GList *l; + + for (l = device_list; l != NULL; l = l->next) { + BluezCupsDevice *device = (BluezCupsDevice *) l->data; + + if (strcmp(device->bdaddr, bdaddr) == 0) { + g_free(device->name); + g_free(device->bdaddr); + g_free(device); + device_list = g_list_delete_link(device_list, l); + return; + } + } +} + +static gboolean +list_known_printers(DBusGProxy *object) +{ + GError *e = NULL; + const char **array; + + dbus_g_proxy_call (object, "ListRemoteDevices", &e, + G_TYPE_INVALID, G_TYPE_STRV, &array, G_TYPE_INVALID); + if (e == NULL) { + add_devices_to_list (object, array); + } else { + /* Most likely bluez-utils < 3.8, so no ListRemoteDevices */ + const char *name; + + name = dbus_g_error_get_name (e); + if (g_str_equal (name, "org.bluez.Error.UnknownMethod") != FALSE) { + g_error_free (e); + e = NULL; + dbus_g_proxy_call (object, "ListBondings", &e, + G_TYPE_INVALID, G_TYPE_STRV, &array, G_TYPE_INVALID); + if (e == NULL) { + add_devices_to_list (object, array); + } else { + g_error_free (e); + } + } else { + g_error_free (e); + } + } + + return FALSE; +} + +static void +list_printers(void) +{ + /* 1. Connect to the bus + * 2. Get the manager + * 3. Get the default adapter + * 4. Get a list of devices + * 5. Get the class of each device + * 6. Print the details from each printer device + */ + GError *e = NULL; + DBusGConnection *conn; + DBusGProxy *object; + const char *adapter; + + g_type_init(); + + conn = dbus_g_bus_get(DBUS_BUS_SYSTEM, &e); + if (e != NULL) { + g_warning("Couldn't connect to bus: %s", e->message); + g_error_free(e); + return; + } + + object = dbus_g_proxy_new_for_name(conn, "org.bluez", + "/org/bluez", "org.bluez.Manager"); + dbus_g_proxy_call(object, "DefaultAdapter", &e, + G_TYPE_INVALID, G_TYPE_STRING, &adapter, G_TYPE_INVALID); + if (e != NULL) { + const char *name; + + name = dbus_g_error_get_name(e); + + /* No adapter */ + if (g_str_equal(name, "org.bluez.Error.NoSuchAdapter") != FALSE) { + g_error_free(e); + return; + } + + g_warning("Couldn't get default bluetooth adapter: %s", + e->message); + g_error_free(e); + return; + } + + object = dbus_g_proxy_new_for_name(conn, "org.bluez", + adapter, "org.bluez.Adapter"); + + dbus_g_object_register_marshaller(bluez_cups_marshal_VOID__STRING_UINT_INT, + G_TYPE_NONE, G_TYPE_STRING, G_TYPE_UINT, + G_TYPE_INT, G_TYPE_INVALID); + dbus_g_proxy_add_signal(object, "RemoteDeviceFound", + G_TYPE_STRING, G_TYPE_UINT, G_TYPE_INT, G_TYPE_INVALID); + dbus_g_proxy_connect_signal(object, "RemoteDeviceFound", + G_CALLBACK(remote_device_found), NULL, NULL); + + dbus_g_object_register_marshaller(bluez_cups_marshal_VOID__STRING_STRING, + G_TYPE_NONE, G_TYPE_STRING, + G_TYPE_STRING, G_TYPE_INVALID); + dbus_g_proxy_add_signal(object, "RemoteNameUpdated", + G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID); + dbus_g_proxy_connect_signal(object, "RemoteNameUpdated", + G_CALLBACK(remote_name_updated), NULL, NULL); + + dbus_g_proxy_add_signal(object, "RemoteDeviceDisappeared", + G_TYPE_STRING, G_TYPE_INVALID); + dbus_g_proxy_connect_signal(object, "RemoteDeviceDisappeared", + G_CALLBACK(remote_device_disappeared), NULL, NULL); + + dbus_g_proxy_add_signal(object, "DiscoveryCompleted", G_TYPE_INVALID); + dbus_g_proxy_connect_signal(object, "DiscoveryCompleted", + G_CALLBACK(discovery_completed), NULL, NULL); + + dbus_g_proxy_call(object, "DiscoverDevicesWithoutNameResolving", &e, + G_TYPE_INVALID, G_TYPE_INVALID); + if (e != NULL) { + g_warning("Couldn't start discovery: %s: %s", + dbus_g_error_get_name(e), e->message); + g_error_free(e); + return; + } + + /* Also add the the recent devices */ + g_idle_add ((GSourceFunc) list_known_printers, object); + + loop = g_main_loop_new(NULL, TRUE); + g_main_loop_run(loop); +} + /* * Usage: printer-uri job-id user title copies options [file] * @@ -73,7 +374,7 @@ int main(int argc, char *argv[]) #endif /* HAVE_SIGSET */ if (argc == 1) { - puts("network bluetooth \"Unknown\" \"Bluetooth printer\""); + list_printers(); return 0; } --- /dev/null 2007-05-24 12:42:54.675807888 +0100 +++ cups/bluez-cups-marshal.list 2007-05-23 11:51:07.000000000 +0100 @@ -0,0 +1,2 @@ +VOID:STRING,UINT,INT +VOID:STRING,STRING [-- Attachment #3: Type: text/plain, Size: 286 bytes --] ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ [-- Attachment #4: Type: text/plain, Size: 164 bytes --] _______________________________________________ Bluez-devel mailing list Bluez-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/bluez-devel ^ permalink raw reply [flat|nested] 21+ messages in thread
* Re: [Bluez-devel] CUPS plugin discovery bits 2007-05-24 15:03 ` Bastien Nocera @ 2007-05-24 15:20 ` Marcel Holtmann 0 siblings, 0 replies; 21+ messages in thread From: Marcel Holtmann @ 2007-05-24 15:20 UTC (permalink / raw) To: BlueZ development; +Cc: twaugh Hi Bastien, > > > Here's a patch against CVS bluez-utils to add discovery to the CUPS > > > backend. With this, it means that most CUPS front-end will be able to > > > list visible printers when adding a new one, be it through the web > > > interface or other front-ends (like Fedora' system-config-printer). > > > > > > It adds D-Bus and glib as dependencies for the backend (not that it > > > matters that much...). > > > > it actually does. We provide an eGlib for embedded systems and so when > > compiled with GLib, we only use that function subset. > > > > And second you use the GLib D-Bus bindings. I am not willing to create > > these dependencies for a "daemon" package. > > The dependency is already optional (and if not, I can make it so). > > I've looked at what using dbus directly would entail, and I'm not sure > that's a good use of my (or anyone's) time. The code would be much more > complicated than it would need to be, and certainly not any more > readable. you can use a lot of helpers from common/libhelper.a to make the integration with D-Bus really simple. Of course low-level code might is a little bit more complex, but for me it is not less readable actually. > In the worst case, how about moving the cups plugin to another module? I am not maintaining another package. > > Actually that is the reason why we wanna go > > for a printing service in the future. > > I still haven't heard the benefits, or features that service would have. > > Unless you want to pass data from a client, over dbus to this printing > service, which I don't think is a good idea given the potential size of > the data being passed over. > > If anyone is involved with that, a draft API would be appreciated. We are not at that point. It was an idea that came of at the last BlueZ developer meeting. However it might be bogus and we don't do it. I can tell you more once we actually do start working on it. So no real details on it so far. Regards Marcel ------------------------------------------------------------------------- This SF.net email is sponsored by DB2 Express Download DB2 Express C - the FREE version of DB2 express and take control of your XML. No limits. Just data. Click to get it now. http://sourceforge.net/powerbar/db2/ _______________________________________________ Bluez-devel mailing list Bluez-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/bluez-devel ^ permalink raw reply [flat|nested] 21+ messages in thread
end of thread, other threads:[~2007-06-07 12:59 UTC | newest] Thread overview: 21+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2007-05-23 15:24 [Bluez-devel] CUPS plugin discovery bits Bastien Nocera 2007-05-23 15:51 ` Marcel Holtmann 2007-05-23 15:57 ` Tim Waugh 2007-05-23 16:15 ` Bastien Nocera 2007-05-23 16:26 ` Bastien Nocera 2007-05-23 16:56 ` Johan Hedberg 2007-05-23 17:07 ` Bastien Nocera 2007-05-24 13:39 ` Bastien Nocera 2007-05-24 15:31 ` Johan Hedberg 2007-05-24 18:49 ` Bastien Nocera 2007-05-25 12:30 ` Bastien Nocera 2007-05-25 12:58 ` Bastien Nocera 2007-05-25 15:08 ` Bastien Nocera 2007-05-29 3:58 ` Luiz Augusto von Dentz 2007-05-29 10:26 ` Bastien Nocera 2007-05-29 13:18 ` Luiz Augusto von Dentz 2007-05-29 13:37 ` Marcel Holtmann 2007-06-07 10:21 ` Marcel Holtmann 2007-06-07 12:59 ` Bastien Nocera 2007-05-24 15:03 ` Bastien Nocera 2007-05-24 15:20 ` Marcel Holtmann
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox