pax_global_header 0000666 0000000 0000000 00000000064 13601523637 0014520 g ustar 00root root 0000000 0000000 52 comment=0998c40ebad69b3c8e2b3e90f1fd0c0879ce6a57
pybluez-0.23/ 0000775 0000000 0000000 00000000000 13601523637 0013136 5 ustar 00root root 0000000 0000000 pybluez-0.23/.github/ 0000775 0000000 0000000 00000000000 13601523637 0014476 5 ustar 00root root 0000000 0000000 pybluez-0.23/.github/ISSUE_TEMPLATE.md 0000664 0000000 0000000 00000000721 13601523637 0017203 0 ustar 00root root 0000000 0000000 *PyBluez is not under active development but we are seeking new contributors
to investigate bugs and submit patches.*
## System
- **Operating System:**
- **Hardware:** (e.g., Raspberry Pi, external Bluetooth adaptor, etc.)
- **Python Version:**
- **PyBluez Version:**
## Issue
Please provide information necessary to reproduce the issue, including sample
code.
If you have long logs, please post them on https://gist.github.com and link to
the Gist here.
pybluez-0.23/.github/stale.yml 0000664 0000000 0000000 00000001552 13601523637 0016334 0 ustar 00root root 0000000 0000000 # Number of days of inactivity before an issue becomes stale
daysUntilStale: 30
# Number of days of inactivity before a stale issue is closed
daysUntilClose: 7
# Issues with these labels will never be considered stale
exemptLabels:
- pinned
# Label to use when marking an issue as stale
staleLabel: wontfix
# Comment to post when marking an issue as stale. Set to `false` to disable
markComment: >
This issue has been automatically marked as stale because it has not had
recent activity. It will be closed if no further activity occurs.
PyBluez is not under active development, but we still accept pull requests!
If you've resolved your issue, please post your solution and close this
issue. Future users will benefit from the knowledge you share. Thank you.
# Comment to post when closing a stale issue. Set to `false` to disable
closeComment: false
pybluez-0.23/.github/workflows/ 0000775 0000000 0000000 00000000000 13601523637 0016533 5 ustar 00root root 0000000 0000000 pybluez-0.23/.github/workflows/build.yml 0000664 0000000 0000000 00000003722 13601523637 0020361 0 ustar 00root root 0000000 0000000 name: Build
on: [push]
jobs:
build:
strategy:
fail-fast: false
matrix:
python-version: [2.7, 3.5, 3.6, 3.7]
os: [macOS-latest, ubuntu-latest, windows-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v1
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python-version }}
- name: Install Windows Visual C++ for Python 2.7
if: startsWith(matrix.os, 'windows-') && matrix.python-version < 3
run: choco install vcpython27
- name: Install Windows 10 SDK for Python 3.5
if: startsWith(matrix.os, 'windows-') && matrix.python-version == 3.5
run: choco install windows-sdk-10.0
- name: Install Linux dependencies
if: startsWith(matrix.os, 'ubuntu-')
run: sudo apt install bluez libbluetooth-dev
- name: Lint
run: |
pip install flake8
# stop the build if there are Python syntax errors or undefined names
flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics --exclude=./.*,./contrib/bluez/test/sap_client.py
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
- name: Build
run: |
pip install wheel
python setup.py bdist_wheel
- name: Upload wheel
uses: actions/upload-artifact@v1
with:
name: dist
path: dist
package_source:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v1
with:
python-version: ${{ matrix.python-version }}
- name: Make source distribution
run: python setup.py sdist
- name: Upload source distribution
uses: actions/upload-artifact@v1
with:
name: dist
path: dist
pybluez-0.23/.gitignore 0000664 0000000 0000000 00000000222 13601523637 0015122 0 ustar 00root root 0000000 0000000 *.o
*.so
*.pyc
build/
PyBluez.egg-info/
dist/
# Mac detritus
.DS_Store
xcuserdata/
# Visual Studio
/.vs
# Sphinx doc build files
/docs/_build
pybluez-0.23/CHANGELOG 0000664 0000000 0000000 00000023567 13601523637 0014365 0 ustar 00root root 0000000 0000000 PyBluez CHANGELOG file
this file contains a list of changes through the different versions of PyBluez.
changes from 0.22 to 0.23 (December 27, 2019)
---------------------------------------------
Please refer to the commit log. Changes since the previous release are extensive
and were not tracked in this file.
changes from 0.21 to 0.22 (August 05, 2015)
-------------------------------------------
GNU/Linux:
Features:
- experimental support for Bluetooth Low Energy, based on pygattlib
implementation
Bugs:
- l2cap options issue #88
- When cancelling device discovery, DeviceDiscoverer does not call
inquiry_complete() #85
- No way to select device id for device discovery #77
- _get_available_port() should try to bind() with
a supplied address instead of "" #45
Windows:
Bugs:
- No adapter detected - WP8.1 #72
- Non-blocking sockets and blocking sockets with a timeout
do not work correctly when using WinSock backend #40
- Need to setsockopt in Windows #10
changes from 0.20 to 0.21(Apr 05, 2015)
---------------------------------------
GNU/Linux:
Bugs:
- No way to select device id for device discovery #77
- RSSI info not passed on by DeviceDiscoverer #74
- Warnings during compilation on linux #73
- python3 UnicodeDecodeError in DeviceDiscoverer find_devices #67
Windows:
Bugs:
- Problem with iqnuiring unicode names on windows8.1 with python3.4 #76
- warnings during build for windows (ms visual studio 2010 express) #60
changes from 0.19 to 0.20 (Jan 13, 2014)
----------------------------------------
GNU/Linux/Windows:
Python 3 is now supported.
Python 3.3 uses Visual C++ 2010 Express Edition for build on windows.
changes from 0.18 to 0.19
-------------------------
Added option to return the class of device in discover_devices()
(Lukas Hetzenecker)
GNU/Linux:
Added setl2capsecurity() method to BluetoothSocket
Fixed get_l2cap_options(), set_l2cap_options(), set_l2cap_mtu()
Added abovementioned functions as socket methods
Added BT_SECURITY_*, L2CAP_MODE_* constants
Added support for the "Extended Inquiry Response" event in the asynchronous
DeviceDiscoverer (Lukas Hetzenecker)
Fixed problems with kernel 3.x
windows:
Allow threads during the initialization of the inquiry in widcomm
(Lukas Hetzenecker)
changes from 0.17 to 0.18 (Nov 25, 2009)
----------------------------------------
windows:
support Visual C++ 2008 Express Edition for Python 2.6 (this should
add support for Windows Vista and Windows 7) (Lukas Hetzenecker)
include widcomm/util.h in source distribution
changes from 0.16 to 0.17 (Oct 15, 2009)
----------------------------------------
GNU/Linux:
bugfix for linux 2.6.30+ zero out struct sockaddr
DeviceDiscoverer may specify bluetooth device_id (roelhuybrechts)
DeviceDiscoverer do not override duration parameter (roelhuybrechts)
changes from 0.15 to 0.16 (Feb 5, 2009)
---------------------------------------
fix variable naming in example/simple/inquiry.py (M. Harris Bhatti)
windows:
only import msbt if widcomm fails
fix memory error in MSBT stack
widcomm comment out debugging statements
GNU/Linux:
fix examples to import bluetooth._bluetooth
changes from 0.14 to 0.15 (Jan 21, 2008)
----------------------------------------
GNU/Linux:
don't hardcode duration in discover_devices() to 8 (Gustavo Chain)
win32:
search for wbtapi.dll before trying to import widcomm
changes from 0.13 to 0.14 (Nov 12, 2007)
----------------------------------------
GNU/Linux:
fix device class parsing bug in inquiry-with-rssi (Pepe Aracil)
changes from 0.12 to 0.13 (August 30, 2007)
-------------------------------------------
GNU/Linux:
Oops, stupid bug introduced from last bugfix
changes from 0.11 to 0.12 (August 29, 2007)
-------------------------------------------
GNU/Linux:
fixed _checkaddr bug (reported by Giovanni)
changes from 0.10 to 0.11 (August 25, 2007)
-------------------------------------------
win32:
fixed bug preventing MSBT stack from loading when Widcomm not present
changes from 0.9.2 to 0.10 (August 10, 2007)
--------------------------------------------
win32:
better searching for Platform SDK path (Ren� M�ller)
proper Py_{BEGIN,END}_ALLOW_THREADS (Ren� M�ller)
added experimental Broadcom/Widcomm support. All the basics should be
supported:
RFCOMM sockets
L2CAP sockets
Device Discovery, Name Lookup
SDP search on remote devices
SDP advertisement (RFCOMM, L2CAP)
Widcomm stack notes:
1. BluetoothSocket.accept () always returns 0 for the port,
as the RFCOMM channel/L2CAP PSM of the client device is not exposed
by the Widcomm API
2. Not all fields of advertise_service are supported. The following
parameters are currently not supported:
description, protocols
3. The following methods of BluetoothSocket are not supported:
gettimeout, dup, makefile, settimeout
4. The following parameters to discover_devices are not supported:
duration, flush_cache (cache always flushes)
5. The timeout parameter of lookup_name is not supported
6. Once a listening socket has accepted a connection, it is not put
back into listening mode. The original listening socket essentially
becomes useless.
7. SDP search/browse operations on the local host are not yet supported
GNU/Linux:
fix segfault on trying to SDP advertise when sdpd not running
(reported by Eric Butler)
changes from 0.9.1 to 0.9.2 (Dec 29, 2006)
------------------------------------------
GNU/Linux:
fixed endian-ness error in L2CAP psm field. only affects big-endian
machines.
changes from 0.9 to 0.9.1 (Sep 14, 2006)
----------------------------------------
GNU/Linux:
fixed missing #include that prevents PyBluez from compiling with
newer version of BlueZ (reported by Priyank Gosalia)
changes from 0.8 to 0.9 (Sep 9, 2006)
----------------------------------------
added protocols optional parameter to advertise_service (bluez: Bea Lam)
refactor: merged bluez/bluetooth.py and msbt/bluetooth.py
GNU/Linux:
added _bluetooth.hci_devid (Mikael Lindqvist)
added _bluetooth.SCO_OPTIONS constant
added Py_{BEGIN,END}_ALLOW_THREADS guards around sdp_connect
(spotted by Rostislav Belov)
win32:
send() now returns the number of bytes sent (spotted by Keith O'Hara)
sdp search no longer raises an exception when no records are found and no
other error occurred.
changes from 0.7.1 to 0.8 (July 31, 2006)
----------------------------------------
win32:
added settimeout, gettimeout, setblocking methods (David Conolly)
GNU/Linux:
fixed DeviceDiscoverer device class byte swap bug (spotted by Bea Lam)
changes from 0.7 to 0.7.1 (May 13, 2006)
---------------------------------------
win32:
discover_devices() no longer raises an IOError when no devices are detected
lookup_name() sort of works (consistently on some machines,
not at all on others)
advertise_service() fully supported
changes from 0.6.1 to 0.7 (May 5, 2006)
---------------------------------------
- fixed some docstring errors
- added lookup_names parameter to discover_devices() If set to True,
discover_devices() returns a list of (address, name) pairs. If set to False
(default), returns a list of addresses
- added constant PORT_ANY. bind to port PORT_ANY for dynamic port
assignment.
get_available_port() is now deprecated.
- added support for Microsoft Windows Bluetooth API. This comes standard on
Windows XP SP1, and Windows Vista. The following features are supported:
RFCOMM sockets (bind, listen, connect, accept, send, recv, close,
getsockname, fileno)
discover_devices()
find_service()
advertise_service() - with limitations. See code for details
The following features are not yet supported in Windows XP:
DeviceDiscoverer class
lookup_name()
changes from 0.6 to 0.6.1 (Feb 24, 2006)
----------------------------------------
fixed UUID parsing again (byte swap error)
added parsing of 32-bit reserved UUIDs
fixed rfcomm-client and rfcomm-server examples to use the same UUID
addded service-id to find_service result
changes from 0.5 to 0.6 (Feb 18, 2006)
--------------------------------------
fixed examples/basic/l2-mtu.py [sock -> client_sock]
fixed hci_send_req [keywords bug]
fixed UUID parsing (Cezar S Espinola)
changes from 0.4 to 0.5 (Dec 16, 2005)
--------------------------------------
added service-classes and profiles keys to find_service result
added service class list and profile list support to
advertise_service (Elvis Pf zenreuter)
fixed do_search response_list (Richard Moore)
BluetoothError now inherits from IOError (Elvis Pf�tzenreuter)
added CHANGELOG
added COPYING
changes from 0.3 to 0.4 (Nov 9, 2005)
-------------------------------------
fixed DeviceDiscoverer name request parsing (Alastair Tre)
fixed set_l2cap_mtu bluetooth module error (simo salminen)
changes from 0.2 to 0.3 (Sep 20, 2005)
--------------------------------------
fixed invalid free() in bt_hci_inquiry (ted wright)
fixed endian error for RFCOMM sockets (Ted Wright)
no longer using SDP_RECORD_PERSIST
changes from 0.1 to 0.2 (Apr 4, 2005)
-------------------------------------
Support for SDP service advertisement and searching added.
Support for easy asynchronous device discovery added (DeviceDiscoverer).
fixed hci_send_req. added a bunch of constants for ioctl on hci sockets
renamed most things from bluez* to bt* or bluetooth*
changed module name from bluez to _bluetooth
changed bluezsocket to btsocket
New API is incompatible with 0.1.
version 0.1 (Dec 16, 2004)
--------------------------
Support for HCI, L2CAP, and RFCOMM sockets.
No support for OBEX or SDP.
pybluez-0.23/COPYING 0000664 0000000 0000000 00000043105 13601523637 0014174 0 ustar 00root root 0000000 0000000 GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
Copyright (C)
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Library General
Public License instead of this License.
pybluez-0.23/MANIFEST.in 0000664 0000000 0000000 00000000730 13601523637 0014674 0 ustar 00root root 0000000 0000000 include CHANGELOG
include COPYING
include README
include setup.py
recursive-include bluetooth *.py
recursive-include bluez *.c
recursive-include bluez *.h
recursive-include msbt *.c
recursive-include widcomm *.cpp
recursive-include widcomm *.hpp
recursive-include widcomm *.h
recursive-include macos *.c
recursive-include macos *.h
recursive-include port3 *.h
recursive-include examples *.py
recursive-exclude * *.pyc
recursive-exclude * *.o
recursive-exclude * *.opp
pybluez-0.23/README.md 0000664 0000000 0000000 00000010503 13601523637 0014414 0 ustar 00root root 0000000 0000000 PyBluez
=======
[](https://github.com/pybluez/pybluez/actions?query=workflow%3ABuild)
The PyBluez module allows Python code to access the host machine's Bluetooth
resources.
| Linux | Raspberry Pi | macOS | Windows |
| ------ | ------------ | ----- | ------- |
| | | | |
Contributors Wanted
-------------------
**This project is not under active development.** Contributions are strongly
desired to resolve compatibility problems on newer systems, address bugs, and
improve platform support for various features.
Examples
--------
```python
# simple inquiry example
import bluetooth
nearby_devices = bluetooth.discover_devices(lookup_names=True)
print("Found {} devices.".format(len(nearby_devices)))
for addr, name in nearby_devices:
print(" {} - {}".format(addr, name))
```
```python
# bluetooth low energy scan
from bluetooth.ble import DiscoveryService
service = DiscoveryService()
devices = service.discover(2)
for address, name in devices.items():
print("name: {}, address: {}".format(name, address))
```
### GNU/Linux and Windows XP examples:
- [examples/simple/inquiry.py](https://github.com/pybluez/pybluez/blob/master/examples/simple/inquiry.py) -
Detecting nearby Bluetooth devices
- [examples/simple/sdp-browse.py](https://github.com/pybluez/pybluez/blob/master/examples/simple/sdp-browse.py) -
Browsing SDP services on a Bluetooth device.
- [examples/simple/rfcomm-server.py](https://github.com/pybluez/pybluez/blob/master/examples/simple/rfcomm-server.py) -
establishing an RFCOMM connection.
- [examples/simple/rfcomm-client.py](https://github.com/pybluez/pybluez/blob/master/examples/simple/rfcomm-client.py) -
establishing an RFCOMM connection.
- [examples/advanced/read-local-bdaddr.py](https://github.com/pybluez/pybluez/blob/master/examples/advanced/read-local-bdaddr.py) -
provides the local Bluetooth device address.
### GNU/Linux only examples:
- [examples/simple/l2capserver.py](https://github.com/pybluez/pybluez/blob/master/examples/simple/l2capserver.py)
- [examples/simple/l2capclient.py](https://github.com/pybluez/pybluez/blob/master/examples/simple/l2capclient.py)
- [examples/simple/asynchronous-inquiry.py](https://github.com/pybluez/pybluez/blob/master/examples/simple/asynchronous-inquiry.py)
- [examples/bluezchat](https://github.com/pybluez/pybluez/blob/master/examples/bluezchat)
- [examples/advanced/inquiry-with-rssi.py](https://github.com/pybluez/pybluez/blob/master/examples/advanced/inquiry-with-rssi.py)
- [examples/advanced/l2-unreliable-server.py](https://github.com/pybluez/pybluez/blob/master/examples/advanced/l2-unreliable-server.py)
- [examples/advanced/l2-unreliable-client.py](https://github.com/pybluez/pybluez/blob/master/examples/advanced/l2-unreliable-client.py)
### GNU/Linux experimental BLE support:
- [examples/ble/scan.py](https://github.com/pybluez/pybluez/blob/master/examples/ble/scan.py)
- [examples/ble/beacon.py](https://github.com/pybluez/pybluez/blob/master/examples/ble/beacon.py)
- [examples/ble/beacon\_scan.py](https://github.com/pybluez/pybluez/blob/master/examples/ble/beacon_scan.py)
- [examples/ble/read\_name.py](https://github.com/pybluez/pybluez/blob/master/examples/ble/read_name.py)
Contact
-------
Please file bugs to the [issue tracker][bugs]. Questions can be asked on the
[mailing list][ml] hosted on Google Groups, but unfortunately it is not very
active.
[bugs]: https://github.com/pybluez/pybluez/issues
[ml]: http://groups.google.com/group/pybluez/
Installation
------------
Please refer to the [installation instructions](/docs/install.rst).
License
-------
> PyBluez is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
> PyBluez is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.
> You should have received a copy of the GNU General Public License along with
PyBluez; if not, write to the Free Software Foundation, Inc., 51 Franklin St,
Fifth Floor, Boston, MA 02110-1301 USA
pybluez-0.23/bluetooth/ 0000775 0000000 0000000 00000000000 13601523637 0015143 5 ustar 00root root 0000000 0000000 pybluez-0.23/bluetooth/__init__.py 0000664 0000000 0000000 00000025005 13601523637 0017256 0 ustar 00root root 0000000 0000000 import sys
import os
if sys.version < '3':
from .btcommon import *
else:
from bluetooth.btcommon import *
__version__ = 0.23
def _dbg(*args):
return
sys.stderr.write(*args)
sys.stderr.write("\n")
if sys.platform == "win32":
_dbg("trying widcomm")
have_widcomm = False
dll = "wbtapi.dll"
sysroot = os.getenv ("SystemRoot")
if os.path.exists (dll) or \
os.path.exists (os.path.join (sysroot, "system32", dll)) or \
os.path.exists (os.path.join (sysroot, dll)):
try:
from . import widcomm
if widcomm.inquirer.is_device_ready ():
# if the Widcomm stack is active and a Bluetooth device on that
# stack is detected, then use the Widcomm stack
from .widcomm import *
have_widcomm = True
except ImportError:
pass
if not have_widcomm:
# otherwise, fall back to the Microsoft stack
_dbg("Widcomm not ready. falling back to MS stack")
if sys.version < '3':
from .msbt import *
else:
from bluetooth.msbt import *
elif sys.platform.startswith("linux"):
if sys.version < '3':
from .bluez import *
else:
from bluetooth.bluez import *
elif sys.platform == "darwin":
from .macos import *
else:
raise Exception("This platform (%s) is currently not supported by pybluez." % sys.platform)
discover_devices.__doc__ = \
"""Perform a Bluetooth device discovery.
This function uses the first available Bluetooth resource to discover Bluetooth devices.
Parameters
----------
lookup_names : bool
When set to True :func:`discover_devices` also attempts to look up the display name of each
detected device. (the default is False).
lookup_class : bool
When set to True :func:`discover_devices` attempts to look up the class of each detected device.
(the default is False).
Returns
-------
list
Returns a list of device addresses as strings or a list of tuples. The content of the
tuples depends on the values of lookup_names and lookup_class as detailed below.
============ ============ =====================================
lookup_class lookup_names Return
============ ============ =====================================
False False list of device addresses
False True list of (address, name) tuples
True False list of (address, class) tuples
True True list of (address, name, class) tuples
============ ============ =====================================
"""
lookup_name.__doc__ = \
"""Look up the friendly name of a Bluetooth device.
This function tries to determine the friendly name (human readable) of the device with
the specified Bluetooth address.
Parameters
----------
address : str
The Bluetooth address of the device.
Returns
-------
str or None
The friendly name of the device on success, and None on failure.
Raises
------
BluetoothError
When the provided address is not a valid Bluetooth address.
"""
advertise_service.__doc__ = \
"""Advertise a service with the local SDP server.
Parameters
----------
sock : BluetoothSocket
The :class:`BluetoothSocket` to use for advertising a service. The socket must be a bound,
listening socket.
name : str
The name of the service and service_id (if specified). This should be a string
of the form "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", where each 'X' is a hexadecimal
digit.
service_classes : list
a list of service classes belonging to the advertised service.
Each service class is represented by a 16-bit or 128-bit UUID.
============ ====================================
UUID Type Format
------------ ------------------------------------
Short 16-bit XXXX
Full 128-bit XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
============ ====================================
where each 'X' is a hexadecimal digit.
There are some constants for standard services, e.g. SERIAL_PORT_CLASS that equals to
"1101". Some class constants provided by PyBluez are:
======================== ========================
SERIAL_PORT_CLASS LAN_ACCESS_CLASS
DIALUP_NET_CLASS HEADSET_CLASS
CORDLESS_TELEPHONY_CLASS AUDIO_SOURCE_CLASS
AUDIO_SINK_CLASS PANU_CLASS
NAP_CLASS GN_CLASS
======================== ========================
profiles : list
A list of service profiles that thie service fulfills. Each profile is a tuple with
(uuid, version). Most standard profiles use standard classes as UUIDs.
PyBluez offers a list of standard profiles, for example SERIAL_PORT_PROFILE. All standard profiles have
the same name as the classes, except that _CLASS suffix is replaced by _PROFILE.
provider : str
A text string specifying the provider of the service
description : str
A text string describing the service
protocols : list
A list of protocols
Note
----
A note on working with Symbian smartphones: bt_discover in Python for Series 60 will only
detect service records with service class SERIAL_PORT_CLASS and profile SERIAL_PORT_PROFILE
"""
stop_advertising.__doc__ = \
"""Try to stop advertising a bluetooth service.
This function instructs the local SDP server to stop advertising the service associated
with socket. You should typically call this right before you close socket.
Parameters
----------
sock : BluetoothSocket
The :class:`BluetoothSocket` to stop advertising the service on.
Raises
------
BluetoothError
When SDP fails to stop advertising for some reason.
""""""
"""
find_service.__doc__ = \
"""Use to find available Bluetooth services.
This function uses the service discovery protocol (SDP) to search for Bluetooth
services matching the specified criteria and returns the search results.
The search criteria are defined by passing one or more parameters to the function.
If no criteria are specified then a list of all nearby services detected is
returned. If more than one criteria is specified, then the search results will
match all the criteria specified.
Parameters
----------
name: str or None
The friendly name of a Bluetooth device.
uuid : str or None
A valid 16-bit or 128-bit UUID.
============ ====================================
UUID Type Format
------------ ------------------------------------
Short 16-bit XXXX
Full 128-bit XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
============ ====================================
where each 'X' is a hexadecimal digit.
address : str or None
The Bluetooth address of a device or "localhost".
If "localhost" is provided the function will search for Bluetooth services on the
local machine.
Returns
-------
list
The search results will be a list of dictionaries. Each dictionary represents a
search match having the following key/value pairs.
=============== ===========================================================
Key Value
=============== ===========================================================
host the bluetooth address of the device advertising the
service.
name the name of the service being advertised.
description a description of the service being advertised.
provider the name of the person/organization providing the service.
protocol either 'RFCOMM', 'L2CAP', None if the protocol was not specified,
or 'UNKNOWN' if the protocol was specified but unrecognized.
port the L2CAP PSM number if the protocol is 'L2CAP',
the RFCOMM channel number if the protocol is 'RFCOMM',
or None if the protocol wasn't specified.
service-classes a list of service class IDs (UUID strings). Possibly
empty
profiles a list of profiles the service claims to support.
a profile takes the form of (UUID, version) pairs.
Possibly empty.
service-id the Service ID of the service. None if it wasn't set
See the Bluetooth spec for the difference between
Service ID and Service Class ID List
=============== ===========================================================
"""
BluetoothSocket.__doc__ = \
""" A Bluetooth Socket representing one endpoint of a Bluetooth connection.
Parameters
----------
proto : int
The protocol the socket will use. The options are HCI, L2CAP, RFCOMM, or SCO.
The default is RFCOMM.
.. note:: RFCOMM is the only protocol available for Windows and macOS systems.
"""
BluetoothSocket.dup.__doc__ =\
"""Duplicate the socket
Returns
-------
BluetoothSocket
A new :class:`BluetoothSocket` connected to the same system resource.
"""
BluetoothSocket.accept.__doc__ = \
"""Accept a connection.
Returns
-------
tuple
A tuple containing a :class:`BluetoothSocket` and a Bluetooth address.
Raises
------
BluetoothError
When an attempt to accept a connection fails.
"""
BluetoothSocket.bind.__doc__ = \
"""Bind the socket to a local address and port.
Parameters
----------
addrport : tuple
A tuple of the form (address str, port int)
Raises
------
BluetoothError
When an attempt to bind the socket fails.
"""
#BluetoothSocket.get_l2cap_options.__doc__ =\
# """Get the L2CAP options for the specified L2CAP socket.
# Options are: omtu, imtu, flush_to, mode, fcs, max_tx, txwin_size.
# Returns
# -------
# list
# A list of L2CAP options available for the socket.
# """
BluetoothError.__doc__ = \
"""Raised when a bluetooth function or method fails for a Bluetooth I/O
related reason.
"""
pybluez-0.23/bluetooth/ble.py 0000664 0000000 0000000 00000000027 13601523637 0016256 0 ustar 00root root 0000000 0000000 from gattlib import *
pybluez-0.23/bluetooth/bluez.py 0000664 0000000 0000000 00000057735 13601523637 0016657 0 ustar 00root root 0000000 0000000 import array
import fcntl
import sys
import struct
from errno import (EADDRINUSE, EBUSY, EINVAL)
from bluetooth.btcommon import *
import bluetooth._bluetooth as _bt
from bluetooth._bluetooth import HCI, RFCOMM, L2CAP, SCO, SOL_L2CAP, \
SOL_RFCOMM, L2CAP_OPTIONS
get_byte = ord if sys.version_info.major < 3 else int
# ============== SDP service registration and unregistration ============
def discover_devices (duration=8, flush_cache=True, lookup_names=False,
lookup_class=False, device_id=-1, iac=IAC_GIAC):
if device_id == -1:
device_id = _bt.hci_get_route()
sock = _gethcisock (device_id)
try:
results = _bt.hci_inquiry (sock, duration=duration, flush_cache=True,
lookup_class=lookup_class, device_id=device_id,
iac=iac)
except _bt.error as e:
sock.close ()
raise BluetoothError (e.args[0], "Error communicating with local "
"bluetooth adapter: " + e.args[1])
if lookup_names:
pairs = []
for item in results:
if lookup_class:
addr, dev_class = item
else:
addr = item
timeoutms = int (10 * 1000)
try:
name = _bt.hci_read_remote_name (sock, addr, timeoutms)
except _bt.error:
# name lookup failed. either a timeout, or I/O error
continue
pairs.append ((addr, name, dev_class) if lookup_class else (addr, name))
sock.close ()
return pairs
else:
sock.close ()
return results
def read_local_bdaddr():
try:
hci_sock = _bt.hci_open_dev(0)
old_filter = hci_sock.getsockopt( _bt.SOL_HCI, _bt.HCI_FILTER, 14)
flt = _bt.hci_filter_new()
opcode = _bt.cmd_opcode_pack(_bt.OGF_INFO_PARAM,
_bt.OCF_READ_BD_ADDR)
_bt.hci_filter_set_ptype(flt, _bt.HCI_EVENT_PKT)
_bt.hci_filter_set_event(flt, _bt.EVT_CMD_COMPLETE)
_bt.hci_filter_set_opcode(flt, opcode)
hci_sock.setsockopt( _bt.SOL_HCI, _bt.HCI_FILTER, flt )
_bt.hci_send_cmd(hci_sock, _bt.OGF_INFO_PARAM, _bt.OCF_READ_BD_ADDR )
pkt = hci_sock.recv(255)
status,raw_bdaddr = struct.unpack("xxxxxxB6s", pkt)
assert status == 0
t = [ "%02X" % get_byte(b) for b in raw_bdaddr ]
t.reverse()
bdaddr = ":".join(t)
# restore old filter
hci_sock.setsockopt( _bt.SOL_HCI, _bt.HCI_FILTER, old_filter )
return [bdaddr]
except _bt.error as e:
raise BluetoothError(*e.args)
def lookup_name (address, timeout=10):
if not is_valid_address (address):
raise BluetoothError (EINVAL, "%s is not a valid Bluetooth address" % address)
sock = _gethcisock ()
timeoutms = int (timeout * 1000)
try:
name = _bt.hci_read_remote_name (sock, address, timeoutms)
except _bt.error:
# name lookup failed. either a timeout, or I/O error
name = None
sock.close ()
return name
def set_packet_timeout (address, timeout):
"""
Adjusts the ACL flush timeout for the ACL connection to the specified
device. This means that all L2CAP and RFCOMM data being sent to that
device will be dropped if not acknowledged in timeout milliseconds (maximum
1280). A timeout of 0 means to never drop packets.
Since this affects all Bluetooth connections to that device, and not just
those initiated by this process or PyBluez, a call to this method requires
superuser privileges.
You must have an active connection to the specified device before invoking
this method.
"""
n = round (timeout / 0.625)
write_flush_timeout (address, n)
def get_l2cap_options (sock):
"""get_l2cap_options (sock, mtu)
Gets L2CAP options for the specified L2CAP socket.
Options are: omtu, imtu, flush_to, mode, fcs, max_tx, txwin_size.
"""
# TODO this should be in the C module, because it depends
# directly on struct l2cap_options layout.
s = sock.getsockopt (SOL_L2CAP, L2CAP_OPTIONS, 12)
options = list( struct.unpack ("HHHBBBH", s))
return options
def set_l2cap_options (sock, options):
"""set_l2cap_options (sock, options)
Sets L2CAP options for the specified L2CAP socket.
The option list must be in the same format supplied by
get_l2cap_options().
"""
# TODO this should be in the C module, because it depends
# directly on struct l2cap_options layout.
s = struct.pack ("HHHBBBH", *options)
sock.setsockopt (SOL_L2CAP, L2CAP_OPTIONS, s)
def set_l2cap_mtu (sock, mtu):
"""set_l2cap_mtu (sock, mtu)
Adjusts the MTU for the specified L2CAP socket. This method needs to be
invoked on both sides of the connection for it to work! The default mtu
that all L2CAP connections start with is 672 bytes.
mtu must be between 48 and 65535, inclusive.
"""
options = get_l2cap_options (sock)
options[0] = options[1] = mtu
set_l2cap_options (sock, options)
def _get_available_ports(protocol):
if protocol == RFCOMM:
return range (1, 31)
elif protocol == L2CAP:
return range (0x1001, 0x8000, 2)
else:
return [0]
class BluetoothSocket:
__doc__ = _bt.btsocket.__doc__
def __init__ (self, proto = RFCOMM, _sock=None):
if _sock is None:
_sock = _bt.btsocket (proto)
self._sock = _sock
self._proto = proto
def dup (self):
"""dup () -> socket object
Return a new socket object connected to the same system resource.
"""
return BluetoothSocket (proto=self._proto, _sock=self._sock)
def accept (self):
try:
client, addr = self._sock.accept ()
except _bt.error as e:
raise BluetoothError (*e.args)
newsock = BluetoothSocket (self._proto, client)
return (newsock, addr)
accept.__doc__ = _bt.btsocket.accept.__doc__
def bind (self, addrport):
if len (addrport) != 2 or addrport[1] != 0:
try:
return self._sock.bind (addrport)
except _bt.error as e:
raise BluetoothError (*e.args)
addr, _ = addrport
for port in _get_available_ports (self._proto):
try:
return self._sock.bind ((addr, port))
except _bt.error as e:
err = BluetoothError (*e.args)
if err.errno != EADDRINUSE:
break
raise err
def get_l2cap_options(self):
"""get_l2cap_options (sock, mtu)
Gets L2CAP options for the specified L2CAP socket.
Options are: omtu, imtu, flush_to, mode, fcs, max_tx, txwin_size.
"""
return get_l2cap_options(self)
def set_l2cap_options(self, options):
"""set_l2cap_options (sock, options)
Sets L2CAP options for the specified L2CAP socket.
The option list must be in the same format supplied by
get_l2cap_options().
"""
return set_l2cap_options(self, options)
def set_l2cap_mtu(self, mtu):
"""set_l2cap_mtu (sock, mtu)
Adjusts the MTU for the specified L2CAP socket. This method needs to be
invoked on both sides of the connection for it to work! The default mtu
that all L2CAP connections start with is 672 bytes.
mtu must be between 48 and 65535, inclusive.
"""
return set_l2cap_mtu(self, mtu)
# import methods from the wraapped socket object
_s = ("""def %s (self, *args, **kwargs):
try:
return self._sock.%s (*args, **kwargs)
except _bt.error as e:
raise BluetoothError (*e.args)
%s.__doc__ = _bt.btsocket.%s.__doc__\n""")
for _m in ( 'connect', 'connect_ex', 'close',
'fileno', 'getpeername', 'getsockname', 'gettimeout',
'getsockopt', 'listen', 'makefile', 'recv', 'recvfrom', 'sendall',
'send', 'sendto', 'setblocking', 'setsockopt', 'settimeout',
'shutdown', 'setl2capsecurity'):
exec( _s % (_m, _m, _m, _m))
del _m, _s
# import readonly attributes from the wrapped socket object
_s = ("@property\ndef %s (self): \
return self._sock.%s")
for _m in ('family', 'type', 'proto', 'timeout'):
exec( _s % (_m, _m))
del _m, _s
def advertise_service (sock, name, service_id = "", service_classes = [], \
profiles = [], provider = "", description = "", protocols = []):
if service_id != "" and not is_valid_uuid (service_id):
raise ValueError ("invalid UUID specified for service_id")
for uuid in service_classes:
if not is_valid_uuid (uuid):
raise ValueError ("invalid UUID specified in service_classes")
for uuid, version in profiles:
if not is_valid_uuid (uuid) or version < 0 or version > 0xFFFF:
raise ValueError ("Invalid Profile Descriptor")
for uuid in protocols:
if not is_valid_uuid (uuid):
raise ValueError ("invalid UUID specified in protocols")
try:
_bt.sdp_advertise_service (sock._sock, name, service_id, \
service_classes, profiles, provider, description, \
protocols)
except _bt.error as e:
raise BluetoothError (*e.args)
def stop_advertising (sock):
try:
_bt.sdp_stop_advertising (sock._sock)
except _bt.error as e:
raise BluetoothError (*e.args)
def find_service (name = None, uuid = None, address = None):
if not address:
devices = discover_devices ()
else:
devices = [ address ]
results = []
if uuid is not None and not is_valid_uuid (uuid):
raise ValueError ("invalid UUID")
try:
for addr in devices:
try:
s = _bt.SDPSession ()
s.connect (addr)
matches = []
if uuid is not None:
matches = s.search (uuid)
else:
matches = s.browse ()
except _bt.error:
continue
if name is not None:
matches = [s for s in matches if s.get ("name", "") == name]
for m in matches:
m["host"] = addr
results.extend (matches)
except _bt.error as e:
raise BluetoothError (*e.args)
return results
# ================ BlueZ internal methods ================
def _gethcisock (device_id = -1):
try:
sock = _bt.hci_open_dev (device_id)
except _bt.error as e:
raise BluetoothError (e.args[0], "error accessing bluetooth device: " +
e.args[1])
return sock
def get_acl_conn_handle (hci_sock, addr):
hci_fd = hci_sock.fileno ()
reqstr = struct.pack ("6sB17s", _bt.str2ba (addr),
_bt.ACL_LINK, b"\0" * 17)
request = array.array ("b", reqstr)
try:
fcntl.ioctl (hci_fd, _bt.HCIGETCONNINFO, request, 1)
except IOError as e:
raise BluetoothError (e.args[0], "There is no ACL connection to %s" % addr)
# XXX should this be "<8xH14x"?
handle = struct.unpack ("8xH14x", request.tostring ())[0]
return handle
def write_flush_timeout (addr, timeout):
hci_sock = _bt.hci_open_dev ()
# get the ACL connection handle to the remote device
handle = get_acl_conn_handle (hci_sock, addr)
# XXX should this be " 127:
return byte_ - 256
else:
return byte_
class DeviceDiscoverer:
"""
Skeleton class for finer control of the device discovery process.
To implement asynchronous device discovery (e.g. if you want to do
something *as soon as* a device is discovered), subclass
DeviceDiscoverer and override device_discovered () and
inquiry_complete ()
"""
def __init__ (self, device_id=-1):
"""
__init__ (device_id=-1)
device_id - The ID of the Bluetooth adapter that will be used
for discovery.
"""
self.sock = None
self.is_inquiring = False
self.lookup_names = False
self.device_id = device_id
self.names_to_find = {}
self.names_found = {}
def find_devices (self, lookup_names=True,
duration=8,
flush_cache=True):
"""
find_devices (lookup_names=True, service_name=None,
duration=8, flush_cache=True)
Call this method to initiate the device discovery process
lookup_names - set to True if you want to lookup the user-friendly
names for each device found.
service_name - set to the name of a service you're looking for.
only devices with a service of this name will be
returned in device_discovered () NOT YET IMPLEMENTED
ADVANCED PARAMETERS: (don't change these unless you know what
you're doing)
duration - the number of 1.2 second units to spend searching for
bluetooth devices. If lookup_names is True, then the
inquiry process can take a lot longer.
flush_cache - return devices discovered in previous inquiries
"""
if self.is_inquiring:
raise BluetoothError (EBUSY, "Already inquiring!")
self.lookup_names = lookup_names
self.sock = _gethcisock (self.device_id)
flt = _bt.hci_filter_new ()
_bt.hci_filter_all_events (flt)
_bt.hci_filter_set_ptype (flt, _bt.HCI_EVENT_PKT)
try:
self.sock.setsockopt (_bt.SOL_HCI, _bt.HCI_FILTER, flt)
except _bt.error as e:
raise BluetoothError (*e.args)
# send the inquiry command
max_responses = 255
cmd_pkt = struct.pack ("BBBBB", 0x33, 0x8b, 0x9e, \
duration, max_responses)
self.pre_inquiry ()
try:
_bt.hci_send_cmd (self.sock, _bt.OGF_LINK_CTL, \
_bt.OCF_INQUIRY, cmd_pkt)
except _bt.error as e:
raise BluetoothError (*e.args)
self.is_inquiring = True
self.names_to_find = {}
self.names_found = {}
def cancel_inquiry (self):
"""
Call this method to cancel an inquiry in process. inquiry_complete
will still be called.
"""
self.names_to_find = {}
if self.is_inquiring:
try:
_bt.hci_send_cmd (self.sock, _bt.OGF_LINK_CTL, \
_bt.OCF_INQUIRY_CANCEL)
except _bt.error as e:
self.sock.close ()
self.sock = None
raise BluetoothError (e.args[0],
"error canceling inquiry: " +
e.args[1])
self.is_inquiring = False
def process_inquiry (self):
"""
Repeatedly calls process_event () until the device inquiry has
completed.
"""
while self.is_inquiring or len (self.names_to_find) > 0:
self.process_event ()
def process_event (self):
"""
Waits for one event to happen, and proceses it. The event will be
either a device discovery, or an inquiry completion.
"""
self._process_hci_event ()
def _process_hci_event (self):
# FIXME may not wrap _bluetooth.error properly
if self.sock is None: return
# voodoo magic!!!
pkt = self.sock.recv (258)
ptype, event, plen = struct.unpack ("BBB", pkt[:3])
pkt = pkt[3:]
if event == _bt.EVT_INQUIRY_RESULT:
nrsp = get_byte(pkt[0])
for i in range (nrsp):
addr = _bt.ba2str (pkt[1+6*i:1+6*i+6])
psrm = pkt[ 1+6*nrsp+i ]
pspm = pkt[ 1+7*nrsp+i ]
devclass_raw = struct.unpack ("BBB",
pkt[1+9*nrsp+3*i:1+9*nrsp+3*i+3])
devclass = (devclass_raw[2] << 16) | \
(devclass_raw[1] << 8) | \
devclass_raw[0]
clockoff = pkt[1+12*nrsp+2*i:1+12*nrsp+2*i+2]
self._device_discovered (addr, devclass,
psrm, pspm, clockoff, None, None)
elif event == _bt.EVT_INQUIRY_RESULT_WITH_RSSI:
nrsp = get_byte(pkt[0])
for i in range (nrsp):
addr = _bt.ba2str (pkt[1+6*i:1+6*i+6])
psrm = pkt[ 1+6*nrsp+i ]
pspm = pkt[ 1+7*nrsp+i ]
# devclass_raw = pkt[1+8*nrsp+3*i:1+8*nrsp+3*i+3]
# devclass = struct.unpack ("I", "%s\0" % devclass_raw)[0]
devclass_raw = struct.unpack ("BBB",
pkt[1+8*nrsp+3*i:1+8*nrsp+3*i+3])
devclass = (devclass_raw[2] << 16) | \
(devclass_raw[1] << 8) | \
devclass_raw[0]
clockoff = pkt[1+11*nrsp+2*i:1+11*nrsp+2*i+2]
rssi = byte_to_signed_int(get_byte(pkt[1+13*nrsp+i]))
self._device_discovered (addr, devclass,
psrm, pspm, clockoff, rssi, None)
elif _bt.HAVE_EVT_EXTENDED_INQUIRY_RESULT and event == _bt.EVT_EXTENDED_INQUIRY_RESULT:
nrsp = get_byte(pkt[0])
for i in range (nrsp):
addr = _bt.ba2str (pkt[1+6*i:1+6*i+6])
psrm = pkt[ 1+6*nrsp+i ]
pspm = pkt[ 1+7*nrsp+i ]
devclass_raw = struct.unpack ("BBB",
pkt[1+8*nrsp+3*i:1+8*nrsp+3*i+3])
devclass = (devclass_raw[2] << 16) | \
(devclass_raw[1] << 8) | \
devclass_raw[0]
clockoff = pkt[1+11*nrsp+2*i:1+11*nrsp+2*i+2]
rssi = byte_to_signed_int(get_byte(pkt[1+13*nrsp+i]))
data_len = _bt.EXTENDED_INQUIRY_INFO_SIZE - _bt.INQUIRY_INFO_WITH_RSSI_SIZE
data = pkt[1+14*nrsp+i:1+14*nrsp+i+data_len]
name = None
pos = 0
while(pos <= len(data)):
struct_len = get_byte(data[pos])
if struct_len == 0:
break
eir_type = get_byte(data[pos+1])
if eir_type == 0x09: # Complete local name
name = data[pos+2:pos+struct_len+1]
pos += struct_len + 2
self._device_discovered (addr, devclass,
psrm, pspm, clockoff, rssi, name)
elif event == _bt.EVT_INQUIRY_COMPLETE or event == _bt.EVT_CMD_COMPLETE:
self.is_inquiring = False
if len (self.names_to_find) == 0:
# print "inquiry complete (evt_inquiry_complete)"
self.sock.close ()
self._inquiry_complete ()
else:
self._send_next_name_req ()
elif event == _bt.EVT_CMD_STATUS:
# XXX shold this be " 0
address = list(self.names_to_find.keys ())[0]
device_class, rssi, psrm, pspm, clockoff = self.names_to_find[address]
bdaddr = _bt.str2ba (address) #TODO not supported in python3
cmd_pkt = "%s%s\0%s" % (bdaddr, psrm, clockoff)
try:
_bt.hci_send_cmd (self.sock, _bt.OGF_LINK_CTL, \
_bt.OCF_REMOTE_NAME_REQ, cmd_pkt)
except _bt.error as e:
raise BluetoothError (e.args[0],
"error request name of %s - %s:" %
(address, e.args[1]))
def fileno (self):
if not self.sock: return None
return self.sock.fileno ()
def pre_inquiry (self):
"""
Called just after find_devices is invoked, but just before the
inquiry is started.
This method exists to be overriden
"""
def device_discovered (self, address, device_class, rssi, name):
"""
Called when a bluetooth device is discovered.
address is the bluetooth address of the device
device_class is the Class of Device, as specified in [1]
passed in as a 3-byte string
name is the user-friendly name of the device if lookup_names was
set when the inquiry was started. otherwise None
This method exists to be overriden.
[1] https://www.bluetooth.org/foundry/assignnumb/document/baseband
"""
if name:
print(("found: %s - %s (class 0x%X, rssi %s)" % \
(address, name, device_class, rssi)))
else:
print(("found: %s (class 0x%X)" % (address, device_class)))
print(("found: %s (class 0x%X, rssi %s)" % \
(address, device_class, rssi)))
def _inquiry_complete (self):
"""
Called when an inquiry started by find_devices has completed.
"""
self.sock.close ()
self.sock = None
self.inquiry_complete()
def inquiry_complete (self):
"""
Called when an inquiry started by find_devices has completed.
"""
print("inquiry complete")
pybluez-0.23/bluetooth/btcommon.py 0000664 0000000 0000000 00000032147 13601523637 0017342 0 ustar 00root root 0000000 0000000 import sys
import struct
import binascii
L2CAP=0
RFCOMM=3
PORT_ANY=0
# Service Class IDs
SDP_SERVER_CLASS = "1000"
BROWSE_GRP_DESC_CLASS = "1001"
PUBLIC_BROWSE_GROUP = "1002"
SERIAL_PORT_CLASS = "1101"
LAN_ACCESS_CLASS = "1102"
DIALUP_NET_CLASS = "1103"
IRMC_SYNC_CLASS = "1104"
OBEX_OBJPUSH_CLASS = "1105"
OBEX_FILETRANS_CLASS = "1106"
IRMC_SYNC_CMD_CLASS = "1107"
HEADSET_CLASS = "1108"
CORDLESS_TELEPHONY_CLASS = "1109"
AUDIO_SOURCE_CLASS = "110a"
AUDIO_SINK_CLASS = "110b"
AV_REMOTE_TARGET_CLASS = "110c"
ADVANCED_AUDIO_CLASS = "110d"
AV_REMOTE_CLASS = "110e"
VIDEO_CONF_CLASS = "110f"
INTERCOM_CLASS = "1110"
FAX_CLASS = "1111"
HEADSET_AGW_CLASS = "1112"
WAP_CLASS = "1113"
WAP_CLIENT_CLASS = "1114"
PANU_CLASS = "1115"
NAP_CLASS = "1116"
GN_CLASS = "1117"
DIRECT_PRINTING_CLASS = "1118"
REFERENCE_PRINTING_CLASS = "1119"
IMAGING_CLASS = "111a"
IMAGING_RESPONDER_CLASS = "111b"
IMAGING_ARCHIVE_CLASS = "111c"
IMAGING_REFOBJS_CLASS = "111d"
HANDSFREE_CLASS = "111e"
HANDSFREE_AGW_CLASS = "111f"
DIRECT_PRT_REFOBJS_CLASS = "1120"
REFLECTED_UI_CLASS = "1121"
BASIC_PRINTING_CLASS = "1122"
PRINTING_STATUS_CLASS = "1123"
HID_CLASS = "1124"
HCR_CLASS = "1125"
HCR_PRINT_CLASS = "1126"
HCR_SCAN_CLASS = "1127"
CIP_CLASS = "1128"
VIDEO_CONF_GW_CLASS = "1129"
UDI_MT_CLASS = "112a"
UDI_TA_CLASS = "112b"
AV_CLASS = "112c"
SAP_CLASS = "112d"
PNP_INFO_CLASS = "1200"
GENERIC_NETWORKING_CLASS = "1201"
GENERIC_FILETRANS_CLASS = "1202"
GENERIC_AUDIO_CLASS = "1203"
GENERIC_TELEPHONY_CLASS = "1204"
UPNP_CLASS = "1205"
UPNP_IP_CLASS = "1206"
UPNP_PAN_CLASS = "1300"
UPNP_LAP_CLASS = "1301"
UPNP_L2CAP_CLASS = "1302"
VIDEO_SOURCE_CLASS = "1303"
VIDEO_SINK_CLASS = "1304"
# Bluetooth Profile Descriptors
SDP_SERVER_PROFILE = ( SDP_SERVER_CLASS, 0x0100)
BROWSE_GRP_DESC_PROFILE = ( BROWSE_GRP_DESC_CLASS, 0x0100)
SERIAL_PORT_PROFILE = ( SERIAL_PORT_CLASS, 0x0100)
LAN_ACCESS_PROFILE = ( LAN_ACCESS_CLASS, 0x0100)
DIALUP_NET_PROFILE = ( DIALUP_NET_CLASS, 0x0100)
IRMC_SYNC_PROFILE = ( IRMC_SYNC_CLASS, 0x0100)
OBEX_OBJPUSH_PROFILE = ( OBEX_OBJPUSH_CLASS, 0x0100)
OBEX_FILETRANS_PROFILE = ( OBEX_FILETRANS_CLASS, 0x0100)
IRMC_SYNC_CMD_PROFILE = ( IRMC_SYNC_CMD_CLASS, 0x0100)
HEADSET_PROFILE = ( HEADSET_CLASS, 0x0100)
CORDLESS_TELEPHONY_PROFILE = ( CORDLESS_TELEPHONY_CLASS, 0x0100)
AUDIO_SOURCE_PROFILE = ( AUDIO_SOURCE_CLASS, 0x0100)
AUDIO_SINK_PROFILE = ( AUDIO_SINK_CLASS, 0x0100)
AV_REMOTE_TARGET_PROFILE = ( AV_REMOTE_TARGET_CLASS, 0x0100)
ADVANCED_AUDIO_PROFILE = ( ADVANCED_AUDIO_CLASS, 0x0100)
AV_REMOTE_PROFILE = ( AV_REMOTE_CLASS, 0x0100)
VIDEO_CONF_PROFILE = ( VIDEO_CONF_CLASS, 0x0100)
INTERCOM_PROFILE = ( INTERCOM_CLASS, 0x0100)
FAX_PROFILE = ( FAX_CLASS, 0x0100)
HEADSET_AGW_PROFILE = ( HEADSET_AGW_CLASS, 0x0100)
WAP_PROFILE = ( WAP_CLASS, 0x0100)
WAP_CLIENT_PROFILE = ( WAP_CLIENT_CLASS, 0x0100)
PANU_PROFILE = ( PANU_CLASS, 0x0100)
NAP_PROFILE = ( NAP_CLASS, 0x0100)
GN_PROFILE = ( GN_CLASS, 0x0100)
DIRECT_PRINTING_PROFILE = ( DIRECT_PRINTING_CLASS, 0x0100)
REFERENCE_PRINTING_PROFILE = ( REFERENCE_PRINTING_CLASS, 0x0100)
IMAGING_PROFILE = ( IMAGING_CLASS, 0x0100)
IMAGING_RESPONDER_PROFILE = ( IMAGING_RESPONDER_CLASS, 0x0100)
IMAGING_ARCHIVE_PROFILE = ( IMAGING_ARCHIVE_CLASS, 0x0100)
IMAGING_REFOBJS_PROFILE = ( IMAGING_REFOBJS_CLASS, 0x0100)
HANDSFREE_PROFILE = ( HANDSFREE_CLASS, 0x0100)
HANDSFREE_AGW_PROFILE = ( HANDSFREE_AGW_CLASS, 0x0100)
DIRECT_PRT_REFOBJS_PROFILE = ( DIRECT_PRT_REFOBJS_CLASS, 0x0100)
REFLECTED_UI_PROFILE = ( REFLECTED_UI_CLASS, 0x0100)
BASIC_PRINTING_PROFILE = ( BASIC_PRINTING_CLASS, 0x0100)
PRINTING_STATUS_PROFILE = ( PRINTING_STATUS_CLASS, 0x0100)
HID_PROFILE = ( HID_CLASS, 0x0100)
HCR_PROFILE = ( HCR_SCAN_CLASS, 0x0100)
HCR_PRINT_PROFILE = ( HCR_PRINT_CLASS, 0x0100)
HCR_SCAN_PROFILE = ( HCR_SCAN_CLASS, 0x0100)
CIP_PROFILE = ( CIP_CLASS, 0x0100)
VIDEO_CONF_GW_PROFILE = ( VIDEO_CONF_GW_CLASS, 0x0100)
UDI_MT_PROFILE = ( UDI_MT_CLASS, 0x0100)
UDI_TA_PROFILE = ( UDI_TA_CLASS, 0x0100)
AV_PROFILE = ( AV_CLASS, 0x0100)
SAP_PROFILE = ( SAP_CLASS, 0x0100)
PNP_INFO_PROFILE = ( PNP_INFO_CLASS, 0x0100)
GENERIC_NETWORKING_PROFILE = ( GENERIC_NETWORKING_CLASS, 0x0100)
GENERIC_FILETRANS_PROFILE = ( GENERIC_FILETRANS_CLASS, 0x0100)
GENERIC_AUDIO_PROFILE = ( GENERIC_AUDIO_CLASS, 0x0100)
GENERIC_TELEPHONY_PROFILE = ( GENERIC_TELEPHONY_CLASS, 0x0100)
UPNP_PROFILE = ( UPNP_CLASS, 0x0100)
UPNP_IP_PROFILE = ( UPNP_IP_CLASS, 0x0100)
UPNP_PAN_PROFILE = ( UPNP_PAN_CLASS, 0x0100)
UPNP_LAP_PROFILE = ( UPNP_LAP_CLASS, 0x0100)
UPNP_L2CAP_PROFILE = ( UPNP_L2CAP_CLASS, 0x0100)
VIDEO_SOURCE_PROFILE = ( VIDEO_SOURCE_CLASS, 0x0100)
VIDEO_SINK_PROFILE = ( VIDEO_SINK_CLASS, 0x0100)
# Universal Service Attribute IDs
SERVICE_RECORD_HANDLE_ATTRID = 0x0000
SERVICE_CLASS_ID_LIST_ATTRID = 0x0001
SERVICE_RECORD_STATE_ATTRID = 0x0002
SERVICE_ID_ATTRID = 0x0003
PROTOCOL_DESCRIPTOR_LIST_ATTRID = 0x0004
BROWSE_GROUP_LIST_ATTRID = 0x0005
LANGUAGE_BASE_ATTRID_LIST_ATTRID = 0x0006
SERVICE_INFO_TIME_TO_LIVE_ATTRID = 0x0007
SERVICE_AVAILABILITY_ATTRID = 0x0008
BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRID = 0x0009
DOCUMENTATION_URL_ATTRID = 0x000a
CLIENT_EXECUTABLE_URL_ATTRID = 0x000b
ICON_URL_ATTRID = 0x000c
SERVICE_NAME_ATTRID = 0x0100
SERVICE_DESCRIPTION_ATTRID = 0x0101
PROVIDER_NAME_ATTRID = 0x0102
# Protocol UUIDs
SDP_UUID = "0001"
UDP_UUID = "0002"
RFCOMM_UUID = "0003"
TCP_UUID = "0004"
TCS_BIN_UUID = "0005"
TCS_AT_UUID = "0006"
OBEX_UUID = "0008"
IP_UUID = "0009"
FTP_UUID = "000a"
HTTP_UUID = "000c"
WSP_UUID = "000e"
BNEP_UUID = "000f"
UPNP_UUID = "0010"
HIDP_UUID = "0011"
HCRP_CTRL_UUID = "0012"
HCRP_DATA_UUID = "0014"
HCRP_NOTE_UUID = "0016"
AVCTP_UUID = "0017"
AVDTP_UUID = "0019"
CMTP_UUID = "001b"
UDI_UUID = "001d"
L2CAP_UUID = "0100"
# Inquiry Access Codes
IAC_GIAC = 0x9e8b33
IAC_LIAC = 0x9e8b00
class BluetoothError (IOError):
pass
def is_valid_address (s):
"""returns True if address is a valid Bluetooth address.
valid address are always strings of the form XX:XX:XX:XX:XX:XX
where X is a hexadecimal character. For example,
01:23:45:67:89:AB is a valid address, but IN:VA:LI:DA:DD:RE is not.
"""
try:
pairs = s.split (":")
if len (pairs) != 6: return False
if not all(0 <= int(b, 16) <= 255 for b in pairs): return False
except:
return False
return True
def is_valid_uuid (uuid):
"""
is_valid_uuid (uuid) -> bool
returns True if uuid is a valid 128-bit UUID.
valid UUIDs are always strings taking one of the following forms:
XXXX
XXXXXXXX
XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
where each X is a hexadecimal digit (case insensitive)
"""
try:
if len (uuid) == 4:
if int (uuid, 16) < 0: return False
elif len (uuid) == 8:
if int (uuid, 16) < 0: return False
elif len (uuid) == 36:
pieces = uuid.split ("-")
if len (pieces) != 5 or \
len (pieces[0]) != 8 or \
len (pieces[1]) != 4 or \
len (pieces[2]) != 4 or \
len (pieces[3]) != 4 or \
len (pieces[4]) != 12:
return False
[ int (p, 16) for p in pieces ]
else:
return False
except ValueError:
return False
except TypeError:
return False
return True
def to_full_uuid (uuid):
"""
converts a short 16-bit or 32-bit reserved UUID to a full 128-bit Bluetooth
UUID.
"""
if not is_valid_uuid (uuid): raise ValueError ("invalid UUID")
if len (uuid) == 4:
return "0000%s-0000-1000-8000-00805F9B34FB" % uuid
elif len (uuid) == 8:
return "%s-0000-1000-8000-00805F9B34FB" % uuid
else:
return uuid
# =============== parsing and constructing raw SDP records ============
def sdp_parse_size_desc (data):
dts = struct.unpack ("B", data[0:1])[0]
dtype, dsizedesc = dts >> 3, dts & 0x7
dstart = 1
if dtype == 0: dsize = 0
elif dsizedesc == 0: dsize = 1
elif dsizedesc == 1: dsize = 2
elif dsizedesc == 2: dsize = 4
elif dsizedesc == 3: dsize = 8
elif dsizedesc == 4: dsize = 16
elif dsizedesc == 5:
dsize = struct.unpack ("B", data[1:2])[0]
dstart += 1
elif dsizedesc == 6:
dsize = struct.unpack ("!H", data[1:3])[0]
dstart += 2
elif dsizedesc == 7:
dsize == struct.unpack ("!I", data[1:5])[0]
dstart += 4
if dtype > 8:
raise ValueError ("Invalid TypeSizeDescriptor byte %s %d, %d" \
% (binascii.hexlify (data[0:1]), dtype, dsizedesc))
return dtype, dsize, dstart
def sdp_parse_uuid (data, size):
if size == 2:
return binascii.hexlify (data)
elif size == 4:
return binascii.hexlify (data)
elif size == 16:
return "%08X-%04X-%04X-%04X-%04X%08X" % struct.unpack ("!IHHHHI", data)
else: return ValueError ("invalid UUID size")
def sdp_parse_int (data, size, signed):
fmts = { 1 : "!b" , 2 : "!h" , 4 : "!i" , 8 : "!q" , 16 : "!qq" }
fmt = fmts[size]
if not signed: fmt = fmt.upper ()
if fmt in [ "!qq", "!QQ" ]:
upp, low = struct.unpack ("!QQ", data)
result = ( upp << 64) | low
if signed:
result=- ((~ (result-1))&0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
return result
else:
return struct.unpack (fmt, data)[0]
def sdp_parse_data_elementSequence (data):
result = []
pos = 0
datalen = len (data)
while pos < datalen:
rtype, rval, consumed = sdp_parse_data_element (data[pos:])
pos += consumed
result.append ( (rtype, rval))
return result
def sdp_parse_data_element (data):
dtype, dsize, dstart = sdp_parse_size_desc (data)
elem = data[dstart:dstart+dsize]
if dtype == 0:
rtype, rval = "Nil", None
elif dtype == 1:
rtype, rval = "UInt%d"% (dsize*8), sdp_parse_int (elem, dsize, False)
elif dtype == 2:
rtype, rval = "SInt%d"% (dsize*8), sdp_parse_int (elem, dsize, True)
elif dtype == 3:
rtype, rval = "UUID", sdp_parse_uuid (elem, dsize)
elif dtype == 4:
rtype, rval = "String", elem
elif dtype == 5:
rtype, rval = "Bool", (struct.unpack ("B", elem)[0] != 0)
elif dtype == 6:
rtype, rval = "ElemSeq", sdp_parse_data_elementSequence (elem)
elif dtype == 7:
rtype, rval = "AltElemSeq", sdp_parse_data_elementSequence (elem)
elif dtype == 8:
rtype, rval = "URL", elem
return rtype, rval, dstart+dsize
def sdp_parse_raw_record (data):
dtype, dsize, dstart = sdp_parse_size_desc (data)
assert dtype == 6
pos = dstart
datalen = len (data)
record = {}
while pos < datalen:
type, attrid, consumed = sdp_parse_data_element (data[pos:])
assert type == "UInt16"
pos += consumed
type, attrval, consumed = sdp_parse_data_element (data[pos:])
pos += consumed
record[attrid] = attrval
return record
def sdp_make_data_element (type, value):
def maketsd (tdesc, sdesc):
return struct.pack ("B", (tdesc << 3) | sdesc)
def maketsdl (tdesc, size):
if size < (1<<8): return struct.pack ("!BB", tdesc << 3 | 5, size)
elif size < (1<<16): return struct.pack ("!BH", tdesc << 3 | 6, size)
else: return struct.pack ("!BI", tdesc << 3 | 7, size)
easyinttypes = { "UInt8" : (1, 0, "!B"), "UInt16" : (1, 1, "!H"),
"UInt32" : (1, 2, "!I"), "UInt64" : (1, 3, "!Q"),
"SInt8" : (2, 0, "!b"), "SInt16" : (2, 1, "!h"),
"SInt32" : (2, 2, "!i"), "SInt64" : (2, 3, "!q"),
}
if type == "Nil":
return maketsd (0, 0)
elif type in easyinttypes:
tdesc, sdesc, fmt = easyinttypes[type]
return maketsd (tdesc, sdesc) + struct.pack (fmt, value)
elif type == "UInt128":
ts = maketsd (1, 4)
upper = ts >> 64
lower = (ts & 0xFFFFFFFFFFFFFFFF)
return ts + struct.pack ("!QQ", upper, lower)
elif type == "SInt128":
ts = maketsd (2, 4)
# FIXME
raise NotImplementedError ("128-bit signed int NYI!")
elif type == "UUID":
if len (value) == 4:
return maketsd (3, 1) + binascii.unhexlify (value)
elif len (value) == 8:
return maketsd (3, 2) + binascii.unhexlify (value)
elif len (value) == 36:
return maketsd (3, 4) + binascii.unhexlify (value.replace ("-",""))
elif type == "String":
return maketsdl (4, len (value)) + str.encode(value)
elif type == "Bool":
return maketsd (5,0) + (value and "\x01" or "\x00")
elif type == "ElemSeq":
packedseq = bytes()
for subtype, subval in value:
nextelem = sdp_make_data_element (subtype, subval)
packedseq = packedseq + nextelem
return maketsdl (6, len (packedseq)) + packedseq
elif type == "AltElemSeq":
packedseq = bytes()
for subtype, subval in value:
packedseq = packedseq + sdp_make_data_element (subtype, subval)
return maketsdl (7, len (packedseq)) + packedseq
elif type == "URL":
return maketsdl (8, len (value)) + value
else:
raise ValueError ("invalid type %s" % type)
pybluez-0.23/bluetooth/macos.py 0000664 0000000 0000000 00000010352 13601523637 0016620 0 ustar 00root root 0000000 0000000 import lightblue
from .btcommon import *
def discover_devices(duration=8, flush_cache=True, lookup_names=False,
lookup_class=False, device_id=-1):
# This is order of discovered device attributes in C-code.
btAddresIndex = 0
namesIndex = 1
classIndex = 2
# Use lightblue to discover devices on OSX.
devices = lightblue.finddevices(getnames=lookup_names, length=duration)
ret = list()
for device in devices:
item = [device[btAddresIndex], ]
if lookup_names:
item.append(device[namesIndex])
if lookup_class:
item.append(device[classIndex])
# in case of address-only we return string not tuple
if len(item) == 1:
ret.append(item[0])
else:
ret.append(tuple(item))
return ret
def lookup_name(address, timeout=10):
print("TODO: implement")
# TODO: After a little looking around, it seems that we can go into some of the
# lightblue internals and enhance the amount of SDP information that is returned
# (e.g., CID/PSM, protocol, provider information).
#
# See: _searchservices() in _lightblue.py
def find_service(name=None, uuid=None, address=None):
if address is not None:
addresses = [address]
else:
addresses = discover_devices(lookup_names=False)
results = []
for address in addresses:
# print "[DEBUG] Browsing services on %s..." % (addr)
dresults = lightblue.findservices(addr=address, name=name)
for tup in dresults:
service = {}
# LightBlue performs a service discovery and returns the found
# services as a list of (device-address, service-port,
# service-name) tuples.
service["host"] = tup[0]
service["port"] = tup[1]
service["name"] = tup[2]
# Add extra keys for compatibility with PyBluez API.
service["description"] = None
service["provider"] = None
service["protocol"] = None
service["service-classes"] = []
service["profiles"] = []
service["service-id"] = None
results.append(service)
return results
def read_local_bdaddr():
return [lightblue.gethostaddr()]
def advertise_service(sock, name, service_id="", service_classes=None,
profiles=None, provider="", description="", protocols=None):
if protocols is None or protocols == RFCOMM:
protocols = [lightblue.RFCOMM]
lightblue.advertise(name, sock, protocols[0], service_id)
def stop_advertising(sock):
lightblue.stop_advertising(sock)
# ============================= BluetoothSocket ============================== #
class BluetoothSocket:
def __init__(self, proto=RFCOMM, _sock=None):
if _sock is None:
_sock = lightblue.socket()
self._sock = _sock
if proto != RFCOMM:
# name the protocol
raise NotImplementedError("Not supported protocol")
self._proto = lightblue.RFCOMM
self._addrport = None
def _getport(self):
return self._addrport[1]
def bind(self, addrport):
self._addrport = addrport
return self._sock.bind(addrport)
def listen(self, backlog):
return self._sock.listen(backlog)
def accept(self):
return self._sock.accept()
def connect(self, addrport):
return self._sock.connect(addrport)
def send(self, data):
return self._sock.send(data)
def recv(self, numbytes):
return self._sock.recv(numbytes)
def close(self):
return self._sock.close()
def getsockname(self):
return self._sock.getsockname()
def setblocking(self, blocking):
return self._sock.setblocking(blocking)
def settimeout(self, timeout):
return self._sock.settimeout(timeout)
def gettimeout(self):
return self._sock.gettimeout()
def fileno(self):
return self._sock.fileno()
def dup(self):
return BluetoothSocket(self._proto, self._sock)
def makefile(self, mode, bufsize):
return self.makefile(mode, bufsize)
# ============================= DeviceDiscoverer ============================= #
class DeviceDiscoverer:
def __init__ (self):
raise NotImplementedError
pybluez-0.23/bluetooth/msbt.py 0000664 0000000 0000000 00000022355 13601523637 0016471 0 ustar 00root root 0000000 0000000 from bluetooth import *
import bluetooth._msbt as bt
bt.initwinsock ()
# ============== SDP service registration and unregistration ============
def discover_devices (duration=8, flush_cache=True, lookup_names=False,
lookup_class=False, device_id=-1):
#this is order of items in C-code
btAddresIndex = 0
namesIndex = 1
classIndex = 2
try:
devices = bt.discover_devices(duration=duration, flush_cache=flush_cache)
except OSError:
return []
ret = list()
for device in devices:
item = [device[btAddresIndex],]
if lookup_names:
item.append(device[namesIndex])
if lookup_class:
item.append(device[classIndex])
if len(item) == 1: # in case of address-only we return string not tuple
ret.append(item[0])
else:
ret.append(tuple(i for i in item))
return ret
def read_local_bdaddr():
return bt.list_local()
def lookup_name (address, timeout=10):
if not is_valid_address (address):
raise ValueError ("Invalid Bluetooth address")
try:
return bt.lookup_name(address)
except OSError:
return None
class BluetoothSocket:
def __init__ (self, proto = RFCOMM, sockfd = None):
if proto not in [ RFCOMM ]:
raise ValueError ("invalid protocol")
if sockfd:
self._sockfd = sockfd
else:
self._sockfd = bt.socket (bt.SOCK_STREAM, bt.BTHPROTO_RFCOMM)
self._proto = proto
# used by advertise_service and stop_advertising
self._sdp_handle = None
self._raw_sdp_record = None
# used to track if in blocking or non-blocking mode (FIONBIO appears
# write only)
self._blocking = True
self._timeout = False
@property
def family (self):
return bt.AF_BTH
@property
def type (self):
return bt.SOCK_STREAM
@property
def proto (self):
return bt.BTHPROTO_RFCOMM
def bind (self, addrport):
if self._proto == RFCOMM:
addr, port = addrport
if port == 0: port = bt.BT_PORT_ANY
bt.bind (self._sockfd, addr, port)
def listen (self, backlog):
bt.listen (self._sockfd, backlog)
def accept (self):
clientfd, addr, port = bt.accept (self._sockfd)
client = BluetoothSocket (self._proto, sockfd=clientfd)
return client, (addr, port)
def connect (self, addrport):
addr, port = addrport
bt.connect (self._sockfd, addr, port)
def send (self, data):
return bt.send (self._sockfd, data)
def recv (self, numbytes):
return bt.recv (self._sockfd, numbytes)
def close (self):
return bt.close (self._sockfd)
def getsockname (self):
return bt.getsockname (self._sockfd)
def getpeername (self):
return bt.getpeername (self._sockfd)
getpeername.__doc__ = bt.getpeername.__doc__
def setblocking (self, blocking):
bt.setblocking (self._sockfd, blocking)
self._blocking = blocking
def settimeout (self, timeout):
if timeout < 0: raise ValueError ("invalid timeout")
if timeout == 0:
self.setblocking (False)
else:
self.setblocking (True)
bt.settimeout (self._sockfd, timeout)
self._timeout = timeout
def gettimeout (self):
if self._blocking and not self._timeout: return None
return bt.gettimeout (self._sockfd)
def fileno (self):
return self._sockfd
def dup (self):
return BluetoothSocket (self._proto, sockfd=bt.dup (self._sockfd))
def makefile (self):
# TODO
raise Exception("Not yet implemented")
def advertise_service (sock, name, service_id = "", service_classes = [], \
profiles = [], provider = "", description = "", protocols = []):
if service_id != "" and not is_valid_uuid (service_id):
raise ValueError ("invalid UUID specified for service_id")
for uuid in service_classes:
if not is_valid_uuid (uuid):
raise ValueError ("invalid UUID specified in service_classes")
for uuid, version in profiles:
if not is_valid_uuid (uuid) or version < 0 or version > 0xFFFF:
raise ValueError ("Invalid Profile Descriptor")
for uuid in protocols:
if not is_valid_uuid (uuid):
raise ValueError ("invalid UUID specified in protocols")
if sock._raw_sdp_record is not None:
raise IOError ("service already advertised")
avpairs = []
# service UUID
if len (service_id) > 0:
avpairs.append (("UInt16", SERVICE_ID_ATTRID))
avpairs.append (("UUID", service_id))
# service class list
if len (service_classes) > 0:
seq = [ ("UUID", svc_class) for svc_class in service_classes ]
avpairs.append (("UInt16", SERVICE_CLASS_ID_LIST_ATTRID))
avpairs.append (("ElemSeq", seq))
# set protocol and port information
assert sock._proto == RFCOMM
addr, port = sock.getsockname ()
avpairs.append (("UInt16", PROTOCOL_DESCRIPTOR_LIST_ATTRID))
l2cap_pd = ("ElemSeq", (("UUID", L2CAP_UUID),))
rfcomm_pd = ("ElemSeq", (("UUID", RFCOMM_UUID), ("UInt8", port)))
proto_list = [ l2cap_pd, rfcomm_pd ]
for proto_uuid in protocols:
proto_list.append (("ElemSeq", (("UUID", proto_uuid),)))
avpairs.append (("ElemSeq", proto_list))
# make the service publicly browseable
avpairs.append (("UInt16", BROWSE_GROUP_LIST_ATTRID))
avpairs.append (("ElemSeq", (("UUID", PUBLIC_BROWSE_GROUP),)))
# profile descriptor list
if len (profiles) > 0:
seq = [ ("ElemSeq", (("UUID",uuid), ("UInt16",version))) \
for uuid, version in profiles ]
avpairs.append (("UInt16",
BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRID))
avpairs.append (("ElemSeq", seq))
# service name
avpairs.append (("UInt16", SERVICE_NAME_ATTRID))
avpairs.append (("String", name))
# service description
if len (description) > 0:
avpairs.append (("UInt16", SERVICE_DESCRIPTION_ATTRID))
avpairs.append (("String", description))
# service provider
if len (provider) > 0:
avpairs.append (("UInt16", PROVIDER_NAME_ATTRID))
avpairs.append (("String", provider))
sock._raw_sdp_record = sdp_make_data_element ("ElemSeq", avpairs)
# pr = sdp_parse_raw_record (sock._raw_sdp_record)
# for attrid, val in pr.items ():
# print "%5s: %s" % (attrid, val)
# print binascii.hexlify (sock._raw_sdp_record)
# print repr (sock._raw_sdp_record)
sock._sdp_handle = bt.set_service_raw (sock._raw_sdp_record, True)
def stop_advertising (sock):
if sock._raw_sdp_record is None:
raise IOError ("service isn't advertised, " \
"but trying to un-advertise")
bt.set_service_raw (sock._raw_sdp_record, False, sock._sdp_handle)
sock._raw_sdp_record = None
sock._sdp_handle = None
def find_service (name = None, uuid = None, address = None):
if address is not None:
addresses = [ address ]
else:
addresses = discover_devices (lookup_names = False)
results = []
for addr in addresses:
uuidstr = uuid or PUBLIC_BROWSE_GROUP
if not is_valid_uuid (uuidstr): raise ValueError ("invalid UUID")
uuidstr = to_full_uuid (uuidstr)
dresults = bt.find_service (addr, uuidstr)
for dict in dresults:
raw = dict["rawrecord"]
record = sdp_parse_raw_record (raw)
if SERVICE_CLASS_ID_LIST_ATTRID in record:
svc_class_id_list = [ t[1] for t in \
record[SERVICE_CLASS_ID_LIST_ATTRID] ]
dict["service-classes"] = svc_class_id_list
else:
dict["services-classes"] = []
if BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRID in record:
pdl = []
for profile_desc in \
record[BLUETOOTH_PROFILE_DESCRIPTOR_LIST_ATTRID]:
uuidpair, versionpair = profile_desc[1]
pdl.append ((uuidpair[1], versionpair[1]))
dict["profiles"] = pdl
else:
dict["profiles"] = []
dict["provider"] = record.get (PROVIDER_NAME_ATTRID, None)
dict["service-id"] = record.get (SERVICE_ID_ATTRID, None)
# XXX the C version is buggy (retrieves an extra byte or two),
# so get the service name here even though it may have already
# been set
dict["name"] = record.get (SERVICE_NAME_ATTRID, None)
dict["handle"] = record.get (SERVICE_RECORD_HANDLE_ATTRID, None)
# if LANGUAGE_BASE_ATTRID_LIST_ATTRID in record:
# for triple in record[LANGUAGE_BASE_ATTRID_LIST_ATTRID]:
# code_ISO639, encoding, base_offset = triple
#
# if SERVICE_DESCRIPTION_ATTRID in record:
# service_description = record[SERVICE_DESCRIPTION_ATTRID]
if name is None:
results.extend (dresults)
else:
results.extend ([ d for d in dresults if d["name"] == name ])
return results
# =============== DeviceDiscoverer ==================
class DeviceDiscoverer:
def __init__ (self):
raise NotImplementedError
pybluez-0.23/bluetooth/widcomm.py 0000664 0000000 0000000 00000071571 13601523637 0017167 0 ustar 00root root 0000000 0000000 from .btcommon import *
import socket
import struct
import threading
import os
import _widcomm
DEFAULT_MTU = 672
def dbg (*args):
return
sys.stdout.write (*args)
sys.stdout.write ("\n")
def BD_ADDR_to_str (bda):
return "%02X:%02X:%02X:%02X:%02X:%02X" % \
(ord(bda[0]), ord(bda[1]), ord(bda[2]),
ord(bda[3]), ord(bda[4]), ord(bda[5]))
def str_to_BD_ADDR (s):
digits = [ int (c, 16) for c in s.split(":") ]
return struct.pack ("6B", *digits)
class WCInquirer:
DEVST_DOWN = 0
DEVST_UP = 1
DEVST_ERROR = 2
DEVST_UNLOADED = 3
DEVST_RELOADED = 4
def __init__ (self):
self._wcinq = _widcomm._WCInquirer ()
port = self._wcinq.get_sockport ()
self.readsock = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
self.readsock.connect (("127.0.0.1", port))
self._wcinq.accept_client ()
self.recently_discovered = []
self.inquiry_in_progress = False
self.sdp_query_in_progress = False
def fileno ():
return self.readsock.fileno ()
def start_inquiry (self):
self.recently_discovered = []
self.inquiry_in_progress = self._wcinq.start_inquiry ()
def read_msg (self):
intsize = struct.calcsize ("=i")
msg_type = struct.unpack ("=i", self.readsock.recv (intsize))[0]
if msg_type == _widcomm.INQ_DEVICE_RESPONDED:
fmt = "=6s3s248si"
data = self.readsock.recv (struct.calcsize (fmt))
bda, devclass, bdname, connected = struct.unpack (fmt, data)
bdaddr = BD_ADDR_to_str (bda)
bdname = bdname.strip ("\0")
self.recently_discovered.append ((bdaddr, devclass, bdname,
connected))
elif msg_type == _widcomm.INQ_INQUIRY_COMPLETE:
fmt = "=ih"
data = self.readsock.recv (struct.calcsize (fmt))
success, num_responses = struct.unpack (fmt, data)
self.inquiry_in_progress = False
elif msg_type == _widcomm.INQ_DISCOVERY_COMPLETE:
self.sdp_query_in_progress = False
elif msg_type == _widcomm.INQ_STACK_STATUS_CHANGE:
fmt = "=i"
data = self.readsock.recv (struct.calcsize (fmt))
new_status = struct.unpack (fmt, data)[0]
def start_discovery (self, addr, uuid = None):
bd_addr = str_to_BD_ADDR (addr)
if uuid is not None:
self.sdp_query_in_progress = \
self._wcinq.start_discovery (bd_addr, to_full_uuid (uuid))
else:
self.sdp_query_in_progress = \
self._wcinq.start_discovery (bd_addr)
self.sdp_query_in_progress = True
def read_discovery_records (self, addr, uuid = None):
if not is_valid_address (addr):
raise ValueError ("invalid Bluetooth address")
bd_addr = str_to_BD_ADDR (addr)
if uuid is not None:
dbg ("read_discovery_records (%s, %s)" % (addr, uuid))
return self._wcinq.read_discovery_records (bd_addr,
to_full_uuid (uuid))
else:
return self._wcinq.read_discovery_records (bd_addr)
def is_device_ready (self):
return self._wcinq.is_device_ready ()
def get_local_device_address (self):
return self._wcinq.get_local_device_address ()
inquirer = WCInquirer ()
def discover_devices (duration=8, flush_cache=True, lookup_names=False, lookup_class=False):
inquirer.start_inquiry ()
while inquirer.inquiry_in_progress:
inquirer.read_msg ()
discovered = inquirer.recently_discovered[:]
if not lookup_names and not lookup_class:
return [ tup[0] for tup in discovered ]
if lookup_names and not lookup_class:
result = []
for bdaddr, devClass, bdName, bConnected in discovered:
if bdName:
result.append ((bdaddr, bdName))
else:
result.append ((bdAddr, None))
return result
if not lookup_names and lookup_class:
result = []
for bdaddr, devClass, bdName, bConnected in discovered:
hex = "%02X%02X%02X" % (ord(devClass[0]), ord(devClass[1]), ord(devClass[2]))
devClass = int(hex, 16)
result.append ((bdAddr, devClass))
return result
if lookup_names and lookup_class:
result = []
for bdaddr, devClass, bdName, bConnected in discovered:
hex = "%02X%02X%02X" % (ord(devClass[0]), ord(devClass[1]), ord(devClass[2]))
devClass = int(hex, 16)
if bdName:
result.append ((bdaddr, bdName, devClass))
else:
result.append ((bdAddr, None, devClass))
return result
def lookup_name (address, timeout=10):
discover_devices ()
for bdaddr, devClass, bdName, bConnected in inquirer.recently_discovered:
if bdaddr == address:
return bdName
def advertise_service (sock, name, service_id = "", service_classes = [], \
profiles = [], provider = "", description = "", protocols = []):
sock._advertise_service (name, service_id, service_classes,
profiles, provider, description, protocols)
def stop_advertising (sock):
sock._stop_advertising ()
def find_service (name = None, uuid = None, address = None):
if address:
if address == "localhost": raise NotImplementedError
if not is_valid_address (address):
raise ValueError ("invalid Bluetooth address")
addresses = [ address ]
else:
addresses = discover_devices ()
if uuid and not is_valid_uuid (uuid):
raise ValueError ("invalid uuid ", uuid)
results = []
for addr in addresses:
inquirer.start_discovery (addr, uuid)
while inquirer.sdp_query_in_progress:
inquirer.read_msg ()
results.extend (inquirer.read_discovery_records (addr, uuid))
return results
def _port_return_code_to_str (code):
k = { _widcomm.RFCOMM_SUCCESS : "Success",
_widcomm.RFCOMM_ALREADY_OPENED : "Port already opened",
_widcomm.RFCOMM_NOT_OPENED : "Connection not open",
_widcomm.RFCOMM_HANDLE_ERROR: "This error should never occur " \
"(HANDLE_ERROR) and is a stack bug",
_widcomm.RFCOMM_LINE_ERR: "Line error",
_widcomm.RFCOMM_START_FAILED: "Connection attempt failed",
_widcomm.RFCOMM_PAR_NEG_FAILED: "Parameter negotion (MTU) failed",
_widcomm.RFCOMM_PORT_NEG_FAILED: "Port negotiation failed",
_widcomm.RFCOMM_PEER_CONNECTION_FAILED: "Connection ended by remote "\
"side",
_widcomm.RFCOMM_PEER_TIMEOUT: "Timeout by remote side",
_widcomm.RFCOMM_INVALID_PARAMETER: "Invalid parameter",
_widcomm.RFCOMM_UNKNOWN_ERROR: "Unknown error" }
if code in k:
return k[code]
else:
return "Invalid RFCOMM error code %s" % str (code)
def _port_ev_code_to_str (code):
d = { _widcomm.PORT_EV_RXFLAG : "Received certain character",
_widcomm.PORT_EV_TXEMPTY : "Transmit Queue Empty",
_widcomm.PORT_EV_CTS : "CTS changed state",
_widcomm.PORT_EV_DSR : "DSR changed state",
_widcomm.PORT_EV_RLSD : "RLSD changed state",
_widcomm.PORT_EV_BREAK : "BREAK received",
_widcomm.PORT_EV_ERR : "Line status error occurred",
_widcomm.PORT_EV_RING : "Ring signal detected",
_widcomm.PORT_EV_CTSS : "CTS state",
_widcomm.PORT_EV_DSRS : "DSR state",
_widcomm.PORT_EV_RLSDS : "RLSD state",
_widcomm.PORT_EV_OVERRUN : "Receiver buffer overrun",
_widcomm.PORT_EV_TXCHAR : "Any character transmitted",
_widcomm.PORT_EV_CONNECTED : "RFCOMM connection established",
_widcomm.PORT_EV_CONNECT_ERR : "Was not able to establish " \
"connection or disconnected",
_widcomm.PORT_EV_FC : "Flow control enabled flag changed by remote",
_widcomm.PORT_EV_FCS : "Flow control status true = enabled" }
result = []
for k, v in list(d.items ()):
if code & k:
result.append (v)
if len (result) == 0:
return "Invalid event code %d" % code
else:
return "\n".join (result)
def _sdp_checkraise (code):
if code == _widcomm.SDP_OK: return
elif code == _widcomm.SDP_COULD_NOT_ADD_RECORD:
raise BluetoothError ("Could not add SDP record")
elif code == _widcomm.SDP_INVALID_RECORD:
raise BluetoothError ("Invalid SDP record")
elif code == _widcomm.SDP_INVALID_PARAMETERS:
raise BluetoothError ("SDP: invalid parameters")
raise RuntimeError ("unknown SDP status code %s" % code)
class BluetoothSocket:
def __init__ (self, proto = RFCOMM, _sockdata = None):
if not proto in [ RFCOMM, L2CAP ]:
raise ValueError ("invalid protocol")
self.proto = proto
if proto == RFCOMM:
self.bind = self.rfcomm_bind
self.listen = self.rfcomm_listen
self.accept = self.rfcomm_accept
self.connect = self.rfcomm_connect
self.send = self.rfcomm_send
self.recv = self.rfcomm_recv
self.close = self.rfcomm_close
self.getsockname = self.rfcomm_getsockname
self.setblocking = self.rfcomm_setblocking
self.settimeout = self.rfcomm_settimeout
self.gettimeout = self.rfcomm_gettimeout
self.dup = self.rfcomm_dup
self.makefile = self.rfcomm_makefile
self.fileno = self.rfcomm_fileno
self.__make_cobjects = self.__rfcomm_make_cobjects
self._advertise_service = self.__rfcomm_advertise_service
if _sockdata:
self._wc, self._if, self.readsock = _sockdata
else:
self.__make_cobjects ()
self.connected = self._wc.is_connected ()
elif proto == L2CAP:
dbg ("creating l2cap socket")
self.bind = self.l2cap_bind
self.listen = self.l2cap_listen
self.accept = self.l2cap_accept
self.connect = self.l2cap_connect
self.send = self.l2cap_send
self.recv = self.l2cap_recv
self.close = self.l2cap_close
self.getsockname = self.l2cap_getsockname
self.setblocking = self.l2cap_setblocking
self.settimeout = self.l2cap_settimeout
self.gettimeout = self.l2cap_gettimeout
self.dup = self.l2cap_dup
self.makefile = self.l2cap_makefile
self.fileno = self.l2cap_fileno
self.__make_cobjects = self.__l2cap_make_cobjects
self._advertise_service = self.__l2cap_advertise_service
if _sockdata:
self._wc, self._if, self.readsock = _sockdata
self.connected = True
else:
self.__make_cobjects ()
self.connected = False
else:
raise NotImplementedError ()
self.nonblocking = False
self.connecting = False
self.listening = False
self.bound = False
self.received_data = []
self.last_event_code = None
self.port = 0
self._sdpservice = None
def _stop_advertising (self):
if not self._sdpservice:
raise BluetoothError ("not advertising any services")
self._sdpservice = None
def __rfcomm_make_cobjects (self):
self._wc = _widcomm._WCRfCommPort ()
self._if = _widcomm._WCRfCommIf ()
self.readsock = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
self.readsock.connect (("127.0.0.1", self._wc.get_sockport ()))
self._wc.accept_client ()
def rfcomm_read_msg (self):
intsize = struct.calcsize ("=i")
msg_type_data = self.readsock.recv (intsize)
msg_type = struct.unpack ("=i", msg_type_data)[0]
if msg_type == _widcomm.RFCOMM_DATA_RECEIVED:
datalen_fmt = "=i"
datalen_data = self.readsock.recv (struct.calcsize (datalen_fmt))
datalen = struct.unpack (datalen_fmt, datalen_data)[0]
self.received_data.append (self.readsock.recv (datalen))
elif msg_type == _widcomm.RFCOMM_EVENT_RECEIVED:
fmt = "=I"
data = self.readsock.recv (struct.calcsize (fmt))
code = struct.unpack (fmt, data)[0]
dbg ("event %X received" % code)
if code & _widcomm.PORT_EV_CONNECTED:
self.connecting = False
self.listening = False
self.connected = True
if code & _widcomm.PORT_EV_CONNECT_ERR:
self.connecting = False
self.listening = False
self.connected = False
raise BluetoothError ("Connection failed")
if code & _widcomm.PORT_EV_RXFLAG:
dbg ("Rx flag")
if code & _widcomm.PORT_EV_TXEMPTY:
dbg ("Tx queue empty")
if code & _widcomm.PORT_EV_CTS:
dbg ("CTS changed state")
if code & _widcomm.PORT_EV_DSR:
dbg ("DSR changed state")
if code & _widcomm.PORT_EV_RLSD:
dbg ("RLSD changed state")
if code & _widcomm.PORT_EV_BREAK:
dbg ("BREAK received")
if code & _widcomm.PORT_EV_ERR:
dbg ("Line status error")
if code & _widcomm.PORT_EV_RING:
dbg ("Ring")
if code & _widcomm.PORT_EV_CTSS:
dbg ("CTS state")
if code & _widcomm.PORT_EV_DSRS:
dbg ("DSR state")
if code & _widcomm.PORT_EV_RLSDS:
dbg ("RLSD state")
if code & _widcomm.PORT_EV_OVERRUN:
dbg ("Receive buffer overrun")
if code & _widcomm.PORT_EV_TXCHAR:
dbg ("Data transmitted")
if code & _widcomm.PORT_EV_FC:
dbg ("Flow control changed by remote")
if code & _widcomm.PORT_EV_FCS:
dbg ("Flow control status true = enabled")
self.last_event_code = code
def rfcomm_bind (self, addrport):
addr, port = addrport
if len (addr):
raise ValueError ("Widcomm stack can't bind to " \
"user-specified adapter")
result = self._if.assign_scn_value (RFCOMM_UUID, port)
if not result:
raise BluetoothError ("unable to bind to port")
self.bound = True
self.port = self._if.get_scn ()
def rfcomm_listen (self, backlog):
if self.connected:
raise BluetoothError ("already connected")
if self.listening:
raise BluetoothError ("already listening/connecting")
if backlog != 1:
raise ValueError ("Widcomm stack requires backlog == 1")
port = self._if.get_scn ()
self._if.set_security_level ("", _widcomm.BTM_SEC_NONE, True)
if not port:
raise BluetoothError ("not bound to a port")
result = self._wc.open_server (port, DEFAULT_MTU)
if result != _widcomm.RFCOMM_SUCCESS:
raise BluetoothError (_port_return_code_to_str (result))
self.listening = True
def rfcomm_accept (self):
if self.connected:
raise BluetoothError ("already connected")
while self.listening and not self.connected:
dbg ("waiting for connection")
self.rfcomm_read_msg ()
if self.connected:
port = self._if.get_scn ()
client_bdaddr = BD_ADDR_to_str (self._wc.is_connected ())
# XXX widcomm API doesn't provide a way to determine the RFCOMM
# channel number of the client
client_port = 0
# create a new socket object and give it ownership of the
# wrapped C++ objects, since those are the ones actually connected
_sockdata = self._wc, self._if, self.readsock
clientsock = BluetoothSocket (RFCOMM, _sockdata)
# now create new C++ objects
self.__rfcomm_make_cobjects ()
# self.bind (("", port))
# self.listen (1)
return clientsock, (client_bdaddr, client_port)
def rfcomm_connect (self, addrport):
addr, port = addrport
dbg ("connecting to %s port %d" % (addr, port))
if not is_valid_address (addr):
raise ValueError ("invalid address %s" % addr)
self._if.assign_scn_value (RFCOMM_UUID, port)
self._if.set_security_level ("", _widcomm.BTM_SEC_NONE, False)
result = self._wc.open_client (port, str_to_BD_ADDR (addr), DEFAULT_MTU)
if result != _widcomm.RFCOMM_SUCCESS:
raise BluetoothError (_port_return_code_to_str (result))
self.connecting = True
while self.connecting:
self.rfcomm_read_msg ()
if not self._wc.is_connected ():
raise BluetoothError ("connection failed")
def rfcomm_send (self, data):
dbg ("sending: [%s]" % data)
status, written = self._wc.write (data)
if status == _widcomm.RFCOMM_SUCCESS:
dbg ("sent okay")
return written
else:
raise BluetoothError (_port_return_code_to_str (status))
def rfcomm_recv (self, numbytes):
if self.nonblocking and not self.received_data:
# XXX are we supposed to raise an exception, or just return None?
return None
while not self.received_data and self._wc.is_connected ():
self.rfcomm_read_msg ()
if self.received_data:
data = self.received_data.pop (0)
if len(data) > numbytes:
self.received_data.insert (0, data[numbytes:])
return data[:numbytes]
else:
return data
def rfcomm_close (self):
self._wc.close ()
self._wc = None
self.bound = False
self.connecting = False
self.listening = False
self.connected = False
# return bt.close (self._sockfd)
def rfcomm_getsockname (self):
if not self.bound:
raise BluetoothError ("Socket not bound")
addr = inquirer.get_local_device_address ()
port = self._if.get_scn ()
return addr, port
def rfcomm_setblocking (self, blocking):
self.nonblocking = not blocking
self.readsock.setblocking (blocking)
def rfcomm_settimeout (self, timeout):
raise NotImplementedError
pass
# if timeout < 0: raise ValueError ("invalid timeout")
#
# if timeout == 0:
# self.setblocking (False)
# else:
# self.setblocking (True)
# # XXX this doesn't look correct
# timeout = 0 # winsock timeout still needs to be set 0
#
# s = bt.settimeout (self._sockfd, timeout)
# self._timeout = timeout
def rfcomm_gettimeout (self):
raise NotImplementedError
# if self._blocking and not self._timeout: return None
# return bt.gettimeout (self._sockfd)
def rfcomm_fileno (self):
return self.readsock.fileno ()
def rfcomm_dup (self):
raise NotImplementedError
def rfcomm_makefile (self):
raise NotImplementedError
def __rfcomm_advertise_service (self, name, service_id,
service_classes, profiles, provider, description,
protocols):
if self._sdpservice is not None:
raise BluetoothError ("Service already advertised")
if not self.listening:
raise BluetoothError ("Socket must be listening before advertised")
if protocols:
raise NotImplementedError ("extra protocols not yet supported in Widcomm stack")
self._sdpservice = _widcomm._WCSdpService ()
if service_classes:
service_classes = [ to_full_uuid (s) for s in service_classes ]
_sdp_checkraise (self._sdpservice.add_service_class_id_list ( \
service_classes))
# self._if.set_security_level (name, _widcomm.BTM_SEC_NONE, True)
_sdp_checkraise (self._sdpservice.add_rfcomm_protocol_descriptor ( \
self.port))
if profiles:
for uuid, version in profiles:
uuid = to_full_uuid (uuid)
_sdp_checkraise (self._sdpservice.add_profile_descriptor_list (\
uuid, version))
_sdp_checkraise (self._sdpservice.add_service_name (name))
_sdp_checkraise (self._sdpservice.make_public_browseable ())
def __l2cap_make_cobjects (self):
dbg ("__l2cap_make_cobjects")
self._wc = _widcomm._WCL2CapConn ()
self._if = _widcomm._WCL2CapIf ()
self.readsock = socket.socket (socket.AF_INET, socket.SOCK_STREAM)
self.readsock.connect (("127.0.0.1", self._wc.get_sockport ()))
self._wc.accept_client ()
def l2cap_read_msg (self):
intsize = struct.calcsize ("=i")
msg_type_data = self.readsock.recv (intsize)
msg_type = struct.unpack ("=i", msg_type_data)[0]
if msg_type == _widcomm.L2CAP_DATA_RECEIVED:
datalen_fmt = "=i"
datalen_data = self.readsock.recv (struct.calcsize (datalen_fmt))
datalen = struct.unpack (datalen_fmt, datalen_data)[0]
self.received_data.append (self.readsock.recv (datalen))
elif msg_type == _widcomm.L2CAP_INCOMING_CONNECTION:
result = self._wc.accept ()
if not result: raise BluetoothError ("accept() failed")
elif msg_type == _widcomm.L2CAP_REMOTE_DISCONNECTED:
dbg ("L2CAP_REMOTE_DISCONNECTED")
self.connecting = False
self.listening = False
self.connected = False
elif msg_type == _widcomm.L2CAP_CONNECTED:
self.connecting = False
self.listening = False
self.connected = True
# elif msg_type == _widcomm.PORT_EV_CONNECT_ERR:
# self.connecting = False
# self.listening = False
# raise BluetoothError ("Connection failed")
def l2cap_bind (self, addrport):
dbg ("l2cap_bind %s" % str(addrport))
addr, port = addrport
if len (addr):
raise ValueError ("Widcomm stack can't bind to " \
"user-specified adapter")
result = self._if.assign_psm_value (L2CAP_UUID, port)
if not result:
raise BluetoothError ("unable to bind to port")
self.bound = True
self.port = self._if.get_psm ()
result = self._if.register ()
if not result:
raise BluetoothError ("register() failed")
def l2cap_listen (self, backlog):
dbg ("l2cap_listen %s" % backlog)
if self.connected:
raise BluetoothError ("already connected")
if self.listening:
raise BluetoothError ("already listening/connecting")
if backlog != 1:
raise ValueError ("Widcomm stack requires backlog == 1")
port = self._if.get_psm ()
self._if.set_security_level ("", _widcomm.BTM_SEC_NONE, True)
if not port:
raise BluetoothError ("not bound to a port")
result = self._wc.listen (self._if)
if not result:
raise BluetoothError ("listen() failed. don't know why")
self.listening = True
def l2cap_accept (self):
dbg ("l2cap_accept")
if self.connected:
raise BluetoothError ("already connected")
while self.listening and not self.connected:
dbg ("waiting for connection")
self.l2cap_read_msg ()
if self.connected:
port = self._if.get_psm ()
client_bdaddr = BD_ADDR_to_str (self._wc.remote_bd_addr ())
# XXX widcomm API doesn't provide a way to determine the L2CAP
# PSM of the client
client_port = 0
# create a new socket object and give it ownership of the
# wrapped C++ objects, since those are the ones actually connected
_sockdata = self._wc, self._if, self.readsock
clientsock = BluetoothSocket (L2CAP, _sockdata)
# now create new C++ objects
self.__l2cap_make_cobjects ()
# self.bind (("", port))
# self.listen (1)
return clientsock, (client_bdaddr, client_port)
def l2cap_connect (self, addrport):
addr, port = addrport
dbg ("connecting to %s port %d" % (addr, port))
if not is_valid_address (addr):
raise ValueError ("invalid address %s" % addr)
if not self._if.assign_psm_value (L2CAP_UUID, port):
raise BluetoothError ("Failed to assign PSM %d" % port)
if not self._if.set_security_level ("", _widcomm.BTM_SEC_NONE, False):
raise BluetoothError ("Failed to set security level")
if not self._if.register ():
raise BluetoothError ("Failed to register PSM")
self.connecting = True
if not self._wc.connect (self._if, str_to_BD_ADDR (addr)):
raise BluetoothError ("Connect failed")
while self.connecting:
self.l2cap_read_msg ()
if not self.connected:
raise BluetoothError ("connection failed")
def l2cap_send (self, data):
dbg ("sending: [%s]" % data)
status, written = self._wc.write (data)
if status:
dbg ("sent okay")
return written
else:
raise BluetoothError (_port_return_code_to_str (status))
def l2cap_recv (self, numbytes):
if self.nonblocking and not self.received_data:
# XXX are we supposed to raise an exception, or just return None?
return None
while not self.received_data and self.connected:
self.l2cap_read_msg ()
if self.received_data:
data = self.received_data.pop (0)
if len(data) > numbytes:
self.received_data.insert (0, data[numbytes:])
return data[:numbytes]
else:
return data
def l2cap_close (self):
self._wc.disconnect ()
self._if.deregister ()
self._wc = None
self.bound = False
self.connecting = False
self.listening = False
self.connected = False
# return bt.close (self._sockfd)
def l2cap_getsockname (self):
if not self.bound:
raise BluetoothError ("Socket not bound")
addr = inquirer.get_local_device_address ()
port = self._if.get_psm ()
return addr, port
def l2cap_setblocking (self, blocking):
self.nonblocking = not blocking
self.readsock.setblocking (blocking)
def l2cap_settimeout (self, timeout):
raise NotImplementedError
# if timeout < 0: raise ValueError ("invalid timeout")
#
# if timeout == 0:
# self.setblocking (False)
# else:
# self.setblocking (True)
# # XXX this doesn't look correct
# timeout = 0 # winsock timeout still needs to be set 0
#
# s = bt.settimeout (self._sockfd, timeout)
# self._timeout = timeout
def l2cap_gettimeout (self):
raise NotImplementedError
# if self._blocking and not self._timeout: return None
# return bt.gettimeout (self._sockfd)
def l2cap_fileno (self):
return self.readsock.fileno ()
def l2cap_dup (self):
raise NotImplementedError
# return BluetoothSocket (self._proto, sockfd=bt.dup (self._sockfd))
def l2cap_makefile (self):
raise NotImplementedError
def __l2cap_advertise_service (self, name, service_id,
service_classes, profiles, provider, description,
protocols):
if self._sdpservice is not None:
raise BluetoothError ("Service already advertised")
if not self.listening:
raise BluetoothError ("Socket must be listening before advertised")
if protocols:
raise NotImplementedError ("extra protocols not yet supported in Widcomm stack")
self._sdpservice = _widcomm._WCSdpService ()
if service_classes:
service_classes = [ to_full_uuid (s) for s in service_classes ]
_sdp_checkraise (self._sdpservice.add_service_class_id_list ( \
service_classes))
_sdp_checkraise (self._sdpservice.add_l2cap_protocol_descriptor ( \
self.port))
if profiles:
for uuid, version in profiles:
uuid = to_full_uuid (uuid)
_sdp_checkraise (self._sdpservice.add_profile_descriptor_list (\
uuid, version))
_sdp_checkraise (self._sdpservice.add_service_name (name))
_sdp_checkraise (self._sdpservice.make_public_browseable ())
class DeviceDiscoverer:
def __init__ (self):
raise NotImplementedError
pybluez-0.23/bluez/ 0000775 0000000 0000000 00000000000 13601523637 0014257 5 ustar 00root root 0000000 0000000 pybluez-0.23/bluez/btmodule.c 0000664 0000000 0000000 00000334166 13601523637 0016253 0 ustar 00root root 0000000 0000000 /*
This module provides an interface to bluetooth. A great deal of the code is
taken from the pyaffix project.
- there are three kinds of bluetooth addresses used here
HCI address is a single int specifying the device id
L2CAP address is a pair (host, port)
RFCOMM address is a pair (host, channel)
SCO address is just a host
the host part of the address is always a string of the form "XX:XX:XX:XX:XX"
Local naming conventions:
- names starting with sock_ are socket object methods
- names starting with bt_ are module-level functions
*/
#include "btmodule.h"
#include "structmember.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "btsdp.h"
/* Socket object documentation */
PyDoc_STRVAR(sock_doc,
"BluetoothSocket(proto=RFCOMM) -> bluetooth socket object\n\
\n\
Open a socket of the given protocol. proto must be one of\n\
HCI, L2CAP, RFCOMM, or SCO. SCO sockets have\n\
not been tested at all yet.\n\
\n\
A BluetoothSocket object represents one endpoint of a bluetooth connection.\n\
\n\
Methods of BluetoothSocket objects (keyword arguments not allowed):\n\
\n\
accept() -- accept a connection, returning new socket and client address\n\
bind(addr) -- bind the socket to a local address\n\
close() -- close the socket\n\
connect(addr) -- connect the socket to a remote address\n\
connect_ex(addr) -- connect, return an error code instead of an exception\n\
dup() -- return a new socket object identical to the current one\n\
fileno() -- return underlying file descriptor\n\
getpeername() -- return remote address\n\
getsockname() -- return local address\n\
getsockopt(level, optname[, buflen]) -- get socket options\n\
gettimeout() -- return timeout or None\n\
listen(n) -- start listening for incoming connections\n\
makefile([mode, [bufsize]]) -- return a file object for the socket\n\
recv(buflen[, flags]) -- receive data\n\
recvfrom(buflen[, flags]) -- receive data and sender's address\n\
sendall(data[, flags]) -- send all data\n\
send(data[, flags]) -- send data, may not send all of it\n\
sendto(data[, flags], addr) -- send data to a given address\n\
setblocking(0 | 1) -- set or clear the blocking I/O flag\n\
setsockopt(level, optname, value) -- set socket options\n\
settimeout(None | float) -- set or clear the timeout\n\
shutdown(how) -- shut down traffic in one or both directions");
/* Global variable holding the exception type for errors detected
by this module (but not argument type or memory errors, etc.). */
PyObject *bluetooth_error;
static PyObject *socket_timeout;
/* A forward reference to the socket type object.
The sock_type variable contains pointers to various functions,
some of which call new_sockobject(), which uses sock_type, so
there has to be a circular reference. */
PyTypeObject sock_type;
/* Convenience function to raise an error according to errno
and return a NULL pointer from a function. */
PyObject *
set_error(void)
{
return PyErr_SetFromErrno(bluetooth_error);
}
/* Function to perform the setting of socket blocking mode
internally. block = (1 | 0). */
static int
internal_setblocking(PySocketSockObject *s, int block)
{
int delay_flag;
Py_BEGIN_ALLOW_THREADS
delay_flag = fcntl(s->sock_fd, F_GETFL, 0);
if (block)
delay_flag &= (~O_NONBLOCK);
else
delay_flag |= O_NONBLOCK;
fcntl(s->sock_fd, F_SETFL, delay_flag);
Py_END_ALLOW_THREADS
/* Since these don't return anything */
return 1;
}
/* Do a select() on the socket, if necessary (sock_timeout > 0).
The argument writing indicates the direction.
This does not raise an exception; we'll let our caller do that
after they've reacquired the interpreter lock.
Returns 1 on timeout, 0 otherwise. */
static int
internal_select(PySocketSockObject *s, int writing)
{
fd_set fds;
struct timeval tv;
int n;
/* Nothing to do unless we're in timeout mode (not non-blocking) */
if (s->sock_timeout <= 0.0)
return 0;
/* Guard against closed socket */
if (s->sock_fd < 0)
return 0;
/* Construct the arguments to select */
tv.tv_sec = (int)s->sock_timeout;
tv.tv_usec = (int)((s->sock_timeout - tv.tv_sec) * 1e6);
FD_ZERO(&fds);
FD_SET(s->sock_fd, &fds);
/* See if the socket is ready */
if (writing)
n = select(s->sock_fd+1, NULL, &fds, NULL, &tv);
else
n = select(s->sock_fd+1, &fds, NULL, NULL, &tv);
if (n == 0)
return 1;
return 0;
}
/* Initialize a new socket object. */
static double defaulttimeout = -1.0; /* Default timeout for new sockets */
static void
init_sockobject(PySocketSockObject *s, int fd, int family, int type, int proto)
{
s->sock_fd = fd;
s->sock_family = family;
s->sock_type = type;
s->sock_proto = proto;
s->sock_timeout = defaulttimeout;
s->errorhandler = &set_error;
if (defaulttimeout >= 0.0)
internal_setblocking(s, 0);
}
/* Create a new socket object.
This just creates the object and initializes it.
If the creation fails, return NULL and set an exception (implicit
in NEWOBJ()). */
static PySocketSockObject *
new_sockobject(int fd, int family, int type, int proto)
{
PySocketSockObject *s;
s = (PySocketSockObject *) PyType_GenericNew(&sock_type, NULL, NULL);
if (s != NULL)
init_sockobject(s, fd, family, type, proto);
return s;
}
/* Create an object representing the given socket address,
suitable for passing it back to bind(), connect() etc.
The family field of the sockaddr structure is inspected
to determine what kind of address it really is. */
/*ARGSUSED*/
static PyObject *
makesockaddr(PySocketSockObject *s, struct sockaddr *addr, int addrlen)
{
if (addrlen == 0) {
/* No address -- may be recvfrom() from known socket */
Py_RETURN_NONE;
} else {
char ba_name[18];
switch(s->sock_proto) {
case BTPROTO_HCI:
{
return Py_BuildValue("H",
((struct sockaddr_hci*)(addr))->hci_dev );
}
case BTPROTO_L2CAP:
{
struct sockaddr_l2 *a = (struct sockaddr_l2*)addr;
ba2str( &a->l2_bdaddr, ba_name );
return Py_BuildValue("sH", ba_name, btohs(a->l2_psm) );
}
case BTPROTO_RFCOMM:
{
struct sockaddr_rc *a = (struct sockaddr_rc*)addr;
ba2str( &a->rc_bdaddr, ba_name );
return Py_BuildValue("sB", ba_name, a->rc_channel );
}
case BTPROTO_SCO:
{
struct sockaddr_sco *a = (struct sockaddr_sco*)addr;
ba2str( &a->sco_bdaddr, ba_name );
return Py_BuildValue("s", ba_name);
}
default:
PyErr_SetString(bluetooth_error,
"getsockaddrarg: unknown Bluetooth protocol");
return 0;
}
}
}
/* Parse a socket address argument according to the socket object's
address family. Return 1 if the address was in the proper format,
0 of not. The address is returned through addr_ret, its length
through len_ret. */
static int
getsockaddrarg(PySocketSockObject *s, PyObject *args,
struct sockaddr *addr_ret, int *len_ret)
{
memset(addr_ret, 0, sizeof(struct sockaddr));
addr_ret->sa_family = AF_BLUETOOTH;
switch( s->sock_proto )
{
case BTPROTO_HCI:
{
struct sockaddr_hci *addr = (struct sockaddr_hci*) addr_ret;
int device;
int channel = HCI_CHANNEL_RAW;
if ( !PyArg_ParseTuple(args, "i|H", &device, &channel) ) {
return 0;
}
if (device == -1) {
addr->hci_dev = HCI_DEV_NONE;
} else {
addr->hci_dev = device;
}
addr->hci_channel = channel;
*len_ret = sizeof(struct sockaddr_hci);
return 1;
}
case BTPROTO_L2CAP:
{
struct sockaddr_l2* addr = (struct sockaddr_l2*) addr_ret;
char *ba_name = 0;
if ( !PyArg_ParseTuple(args, "sH", &ba_name, &addr->l2_psm) )
{
return 0;
}
str2ba( ba_name, &addr->l2_bdaddr );
// check for a valid PSM
if( ! ( 0x1 & addr->l2_psm ) ) {
PyErr_SetString( PyExc_ValueError, "Invalid PSM");
return 0;
}
addr->l2_psm = htobs(addr->l2_psm);
*len_ret = sizeof *addr;
return 1;
}
case BTPROTO_RFCOMM:
{
struct sockaddr_rc *addr = (struct sockaddr_rc*) addr_ret;
char *ba_name = 0;
if( !PyArg_ParseTuple(args, "sB", &ba_name, &addr->rc_channel) )
{
return 0;
}
str2ba( ba_name, &addr->rc_bdaddr );
*len_ret = sizeof *addr;
return 1;
}
case BTPROTO_SCO:
{
struct sockaddr_sco *addr = (struct sockaddr_sco*) addr_ret;
char *ba_name = 0;
if( !PyArg_ParseTuple(args, "s", &ba_name) )
{
return 0;
}
str2ba( ba_name, &addr->sco_bdaddr);
*len_ret = sizeof *addr;
return 1;
}
default:
{
PyErr_SetString(bluetooth_error,
"getsockaddrarg: unknown Bluetooth protocol");
return 0;
}
}
}
/* Determin device can be advertisable('UP, RUNNING, PSCAN, ISCAN' state).
If advertisable, return 0. Else, return -1. */
static int
_adv_available(struct hci_dev_info *di)
{
uint32_t *flags = &di->flags;
if (hci_test_bit(HCI_RAW, &flags) && !bacmp(&di->bdaddr, BDADDR_ANY)) {
int dd = hci_open_dev(di->dev_id);
if (dd < 0)
return -1;
hci_read_bd_addr(dd, &di->bdaddr, 1000);
hci_close_dev(dd);
}
return (hci_test_bit(HCI_UP, flags) &&
hci_test_bit(HCI_RUNNING, flags) &&
hci_test_bit(HCI_PSCAN, flags) &&
hci_test_bit(HCI_ISCAN, flags)) != 0 ? 0 : -1;
}
/* Inspect all devices in order to know whether advertisable device exists. */
static int
_any_adv_available(void)
{
struct hci_dev_list_req *dl = NULL;
struct hci_dev_req *dr = NULL;
struct hci_dev_info di = {0,};
int result = -1;
int ctl = -1;
int i;
if ((ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI)) < 0) {
return -1;
}
if (!(dl = malloc(HCI_MAX_DEV * sizeof(struct hci_dev_req) +
sizeof(uint16_t)))) {
goto CLEAN_UP_RETURN;
}
dl->dev_num = HCI_MAX_DEV;
dr = dl->dev_req;
if (ioctl(ctl, HCIGETDEVLIST, (void *) dl) < 0) {
goto CLEAN_UP_RETURN;
}
for (i = 0; i< dl->dev_num; i++) {
di.dev_id = (dr+i)->dev_id;
if (ioctl(ctl, HCIGETDEVINFO, (void *) &di) < 0)
continue;
/* if find adv-available device, return */
if(_adv_available(&di) == 0)
{
result = 0;
goto CLEAN_UP_RETURN;
}
}
CLEAN_UP_RETURN:
close(ctl);
free(dl);
return result;
}
/* Determine the socket can be advertisable or not.
It will work if socket is bound to specific device or not.
If advertisable, return 0. Else, return -1 */
static int
adv_available(PySocketSockObject *socko)
{
bdaddr_t ba = {{0, }}; /* GCC bug? */
struct sockaddr addr = {0, };
int dev_id = -1;
socklen_t alen = sizeof(addr);
struct sockaddr_l2 const * addr_l2 = (struct sockaddr_l2 const *)&addr;
struct sockaddr_rc const * addr_rc = (struct sockaddr_rc const *)&addr;
/* get ba */
if(getsockname(socko->sock_fd, &addr, &alen) < 0)
return -1;
switch(socko->sock_proto)
{
case BTPROTO_L2CAP:
ba = addr_l2->l2_bdaddr;
break;
case BTPROTO_RFCOMM:
ba = addr_rc->rc_bdaddr;
break;
default:
/* The others are not yet implmented.
In fact, I don't spec of the others.
To have compatibility with old version, return 0(success). */
return 0;
}
/* get dev_id from ba */
if(bacmp(&ba, BDADDR_ANY) == 0)
dev_id = -1;
else
dev_id = hci_get_route(&ba);
if(dev_id == -1)
/* if dev_id is not specified, inspect all devices. */
{
return _any_adv_available();
}
else
/* if device specified, inspect it. */
{
struct hci_dev_info di;
if(hci_devinfo(dev_id, &di))
return -1;
return _adv_available(&di);
}
}
/* Get the address length according to the socket object's address family.
Return 1 if the family is known, 0 otherwise. The length is returned
through len_ret. */
int
getsockaddrlen(PySocketSockObject *s, socklen_t *len_ret)
{
switch(s->sock_proto)
{
case BTPROTO_L2CAP:
*len_ret = sizeof (struct sockaddr_l2);
return 1;
case BTPROTO_RFCOMM:
*len_ret = sizeof (struct sockaddr_rc);
return 1;
case BTPROTO_SCO:
*len_ret = sizeof (struct sockaddr_sco);
return 1;
case BTPROTO_HCI:
*len_ret = sizeof (struct sockaddr_hci);
return 1;
default:
PyErr_SetString(bluetooth_error,
"getsockaddrlen: unknown bluetooth protocol");
return 0;
}
}
int
str2uuid( const char *uuid_str, uuid_t *uuid )
{
uint32_t uuid_int[4];
char *endptr;
if( strlen( uuid_str ) == 36 ) {
// Parse uuid128 standard format: 12345678-9012-3456-7890-123456789012
char buf[9] = { 0 };
if( uuid_str[8] != '-' && uuid_str[13] != '-' &&
uuid_str[18] != '-' && uuid_str[23] != '-' ) {
return 0;
}
// first 8-bytes
strncpy(buf, uuid_str, 8);
uuid_int[0] = htonl( strtoul( buf, &endptr, 16 ) );
if( endptr != buf + 8 ) return 0;
// second 8-bytes
strncpy(buf, uuid_str+9, 4);
strncpy(buf+4, uuid_str+14, 4);
uuid_int[1] = htonl( strtoul( buf, &endptr, 16 ) );
if( endptr != buf + 8 ) return 0;
// third 8-bytes
strncpy(buf, uuid_str+19, 4);
strncpy(buf+4, uuid_str+24, 4);
uuid_int[2] = htonl( strtoul( buf, &endptr, 16 ) );
if( endptr != buf + 8 ) return 0;
// fourth 8-bytes
strncpy(buf, uuid_str+28, 8);
uuid_int[3] = htonl( strtoul( buf, &endptr, 16 ) );
if( endptr != buf + 8 ) return 0;
if( uuid != NULL ) sdp_uuid128_create( uuid, uuid_int );
} else if ( strlen( uuid_str ) == 8 ) {
// 32-bit reserved UUID
uint32_t i = strtoul( uuid_str, &endptr, 16 );
if( endptr != uuid_str + 8 ) return 0;
if( uuid != NULL ) sdp_uuid32_create( uuid, i );
} else if( strlen( uuid_str ) == 4 ) {
// 16-bit reserved UUID
int i = strtol( uuid_str, &endptr, 16 );
if( endptr != uuid_str + 4 ) return 0;
if( uuid != NULL ) sdp_uuid16_create( uuid, i );
} else {
return 0;
}
return 1;
}
int
pyunicode2uuid( PyObject *item, uuid_t *uuid )
{
#if PY_MAJOR_VERSION >= 3
PyObject* ascii = PyUnicode_AsASCIIString( item );
int ret = str2uuid( PyBytes_AsString( ascii ), uuid );
Py_XDECREF( ascii );
return ret;
#else
return str2uuid( PyString_AsString( item ), NULL );
#endif
}
void
uuid2str( const uuid_t *uuid, char *dest )
{
if( uuid->type == SDP_UUID16 ) {
sprintf(dest, "%04X", uuid->value.uuid16 );
} else if( uuid->type == SDP_UUID32 ) {
sprintf(dest, "%08X", uuid->value.uuid32 );
} else if( uuid->type == SDP_UUID128 ) {
uint32_t *data = (uint32_t*)(&uuid->value.uuid128);
sprintf(dest, "%08X-%04X-%04X-%04X-%04X%08X",
ntohl(data[0]),
ntohl(data[1])>>16,
(ntohl(data[1])<<16)>>16,
ntohl(data[2])>>16,
(ntohl(data[2])<<16)>>16,
ntohl(data[3]));
}
}
// =================== socket methods ==================== //
/* s.accept() method */
static PyObject *
sock_accept(PySocketSockObject *s)
{
char addrbuf[256];
int newfd;
socklen_t addrlen;
PyObject *sock = NULL;
PyObject *addr = NULL;
PyObject *res = NULL;
int timeout;
if (!getsockaddrlen(s, &addrlen))
return NULL;
memset(addrbuf, 0, addrlen);
newfd = -1;
Py_BEGIN_ALLOW_THREADS
timeout = internal_select(s, 0);
if (!timeout)
newfd = accept(s->sock_fd, (struct sockaddr *) addrbuf, &addrlen);
Py_END_ALLOW_THREADS
if (timeout) {
PyErr_SetString(socket_timeout, "timed out");
return NULL;
}
if (newfd < 0)
return s->errorhandler();
/* Create the new object with unspecified family,
to avoid calls to bind() etc. on it. */
sock = (PyObject *) new_sockobject(newfd,
s->sock_family,
s->sock_type,
s->sock_proto);
if (sock == NULL) {
close(newfd);
goto finally;
}
addr = makesockaddr(s, (struct sockaddr *)addrbuf, addrlen);
if (addr == NULL)
goto finally;
res = Py_BuildValue("OO", sock, addr);
finally:
Py_XDECREF(sock);
Py_XDECREF(addr);
return res;
}
PyDoc_STRVAR(accept_doc,
"accept() -> (socket object, address info)\n\
\n\
Wait for an incoming connection. Return a new socket representing the\n\
connection, and the address of the client. For L2CAP sockets, the address\n\
is a (host, psm) tuple. For RFCOMM sockets, the address is a (host, channel)\n\
tuple. For SCO sockets, the address is just a host.");
/* s.setblocking(flag) method. Argument:
False -- non-blocking mode; same as settimeout(0)
True -- blocking mode; same as settimeout(None)
*/
static PyObject *
sock_setblocking(PySocketSockObject *s, PyObject *arg)
{
int block;
block = PyInt_AsLong(arg);
if (block == -1 && PyErr_Occurred())
return NULL;
s->sock_timeout = block ? -1.0 : 0.0;
internal_setblocking(s, block);
Py_RETURN_NONE;
}
PyDoc_STRVAR(setblocking_doc,
"setblocking(flag)\n\
\n\
Set the socket to blocking (flag is true) or non-blocking (false).\n\
setblocking(True) is equivalent to settimeout(None);\n\
setblocking(False) is equivalent to settimeout(0.0).");
/* s.settimeout(timeout) method. Argument:
None -- no timeout, blocking mode; same as setblocking(True)
0.0 -- non-blocking mode; same as setblocking(False)
> 0 -- timeout mode; operations time out after timeout seconds
< 0 -- illegal; raises an exception
*/
static PyObject *
sock_settimeout(PySocketSockObject *s, PyObject *arg)
{
double timeout;
if (arg == Py_None)
timeout = -1.0;
else {
timeout = PyFloat_AsDouble(arg);
if (timeout < 0.0) {
if (!PyErr_Occurred())
PyErr_SetString(PyExc_ValueError, "Timeout value out of range");
return NULL;
}
}
s->sock_timeout = timeout;
internal_setblocking(s, timeout < 0.0);
Py_RETURN_NONE;
}
PyDoc_STRVAR(settimeout_doc,
"settimeout(timeout)\n\
\n\
Set a timeout on socket operations. 'timeout' can be a float,\n\
giving in seconds, or None. Setting a timeout of None disables\n\
the timeout feature and is equivalent to setblocking(1).\n\
Setting a timeout of zero is the same as setblocking(0).");
/* s.gettimeout() method.
Returns the timeout associated with a socket. */
static PyObject *
sock_gettimeout(PySocketSockObject *s)
{
if (s->sock_timeout < 0.0)
Py_RETURN_NONE;
else
return PyFloat_FromDouble(s->sock_timeout);
}
PyDoc_STRVAR(gettimeout_doc,
"gettimeout() -> timeout\n\
\n\
Returns the timeout in floating seconds associated with socket \n\
operations. A timeout of None indicates that timeouts on socket \n\
operations are disabled.");
/* s.setsockopt() method.
With an integer third argument, sets an integer option.
With a string third argument, sets an option from a buffer;
use optional built-in module 'struct' to encode the string. */
static PyObject *
sock_setsockopt(PySocketSockObject *s, PyObject *args)
{
int level;
int optname;
int res;
void *buf;
int buflen;
int flag;
if (PyArg_ParseTuple(args, "iii:setsockopt", &level, &optname, &flag)) {
buf = (void *) &flag;
buflen = sizeof flag;
} else {
PyErr_Clear();
if (!PyArg_ParseTuple(args, "iis#:setsockopt",
&level, &optname, &buf, &buflen)) {
return NULL;
}
}
res = setsockopt(s->sock_fd, level, optname, buf, buflen);
if (res < 0)
return s->errorhandler();
Py_RETURN_NONE;
}
PyDoc_STRVAR(setsockopt_doc,
"setsockopt(level, option, value)\n\
\n\
Set a socket option. See the Unix manual for level and option.\n\
The value argument can either be an integer or a string.");
/* s.getsockopt() method.
With two arguments, retrieves an integer option.
With a third integer argument, retrieves a string buffer of that size;
use optional built-in module 'struct' to decode the string. */
static PyObject *
sock_getsockopt(PySocketSockObject *s, PyObject *args)
{
int level;
int optname;
int res;
socklen_t buflen = 0;
if (!PyArg_ParseTuple(args, "ii|i:getsockopt", &level, &optname, &buflen))
return NULL;
if (buflen == 0) {
int flag = 0;
socklen_t flagsize = sizeof flag;
res = getsockopt(s->sock_fd, level, optname, (void *)&flag, &flagsize);
if (res < 0)
return s->errorhandler();
return PyInt_FromLong(flag);
} else if (buflen <= 0 || buflen > 1024) {
PyErr_SetString(bluetooth_error, "getsockopt buflen out of range");
return NULL;
} else {
PyObject *buf = PyString_FromStringAndSize((char *)NULL, buflen);
if (buf == NULL)
return NULL;
res = getsockopt(s->sock_fd, level, optname,
(void *)PyString_AS_STRING(buf), &buflen);
if (res < 0) {
Py_DECREF(buf);
return s->errorhandler();
}
_PyString_Resize(&buf, buflen);
return buf;
}
return NULL;
}
PyDoc_STRVAR(getsockopt_doc,
"getsockopt(level, option[, buffersize]) -> value\n\
\n\
Get a socket option. See the Unix manual for level and option.\n\
If a nonzero buffersize argument is given, the return value is a\n\
string of that length; otherwise it is an integer.");
static PyObject *
sock_setl2capsecurity(PySocketSockObject *s, PyObject *args)
{
int level;
struct bt_security sec;
if (! PyArg_ParseTuple(args, "i:setsockopt", &level))
return NULL;
memset(&sec, 0, sizeof(sec));
sec.level = level;
if (setsockopt(s->sock_fd, SOL_BLUETOOTH, BT_SECURITY, &sec,
sizeof(sec)) == 0)
Py_RETURN_NONE;
if (errno != ENOPROTOOPT)
return s->errorhandler();
int lm_map[] = {
0,
L2CAP_LM_AUTH,
L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT,
L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE,
}, opt = lm_map[level];
if (setsockopt(s->sock_fd, SOL_L2CAP, L2CAP_LM, &opt, sizeof(opt)) < 0)
return s->errorhandler();
Py_RETURN_NONE;
}
PyDoc_STRVAR(setl2capsecurity_doc,
"setl2capsecurity(BT_SECURITY_*) -> value\n\
\n\
Sets socket security. Levels are BT_SECURITY_SDP, LOW, MEDIUM and HIGH.");
/* s.bind(sockaddr) method */
static PyObject *
sock_bind(PySocketSockObject *s, PyObject *addro)
{
struct sockaddr addr = { 0 };
int addrlen;
int res;
if (!getsockaddrarg(s, addro, &addr, &addrlen))
return NULL;
Py_BEGIN_ALLOW_THREADS
res = bind(s->sock_fd, &addr, addrlen);
Py_END_ALLOW_THREADS
if (res < 0)
return s->errorhandler();
Py_RETURN_NONE;
}
PyDoc_STRVAR(bind_doc,
"bind(address)\n\
\n\
Bind the socket to a local address. address must always be a tuple.\n\
HCI sockets: ( device number, channel )\n\
device number should be 0, 1, 2, etc.\n\
L2CAP sockets: ( host, psm )\n\
host should be an address e.g. \"01:23:45:67:89:ab\"\n\
psm should be an unsigned integer\n\
RFCOMM sockets: ( host, channel )\n\
SCO sockets: ( host )");
/* s.close() method.
Set the file descriptor to -1 so operations tried subsequently
will surely fail. */
static PyObject *
sock_close(PySocketSockObject *s)
{
int fd;
if ((fd = s->sock_fd) != -1) {
s->sock_fd = -1;
Py_BEGIN_ALLOW_THREADS
(void) close(fd);
Py_END_ALLOW_THREADS
}
if( s->sdp_session ) {
sdp_close( s->sdp_session );
s->sdp_record_handle = 0;
s->sdp_session = NULL;
}
Py_RETURN_NONE;
}
PyDoc_STRVAR(close_doc,
"close()\n\
\n\
Close the socket. It cannot be used after this call.");
static int
internal_connect(PySocketSockObject *s, struct sockaddr *addr, int addrlen,
int *timeoutp)
{
int res, timeout;
timeout = 0;
res = connect(s->sock_fd, addr, addrlen);
if (s->sock_timeout > 0.0) {
if (res < 0 && errno == EINPROGRESS) {
timeout = internal_select(s, 1);
res = connect(s->sock_fd, addr, addrlen);
if (res < 0 && errno == EISCONN)
res = 0;
}
}
if (res < 0)
res = errno;
*timeoutp = timeout;
return res;
}
/* s.connect(sockaddr) method */
static PyObject *
sock_connect(PySocketSockObject *s, PyObject *addro)
{
struct sockaddr addr = { 0 };
int addrlen;
int res;
int timeout;
if (!getsockaddrarg(s, addro, &addr, &addrlen))
return NULL;
Py_BEGIN_ALLOW_THREADS
res = internal_connect(s, &addr, addrlen, &timeout);
Py_END_ALLOW_THREADS
if (timeout) {
PyErr_SetString(socket_timeout, "timed out");
return NULL;
}
if (res != 0)
return s->errorhandler();
Py_RETURN_NONE;
}
PyDoc_STRVAR(connect_doc,
"connect(address)\n\
\n\
Connect the socket to a remote address. For L2CAP sockets, the address is a \n\
(host,psm) tuple. For RFCOMM sockets, the address is a (host,channel) tuple.\n\
For SCO sockets, the address is just the host.");
/* s.connect_ex(sockaddr) method */
static PyObject *
sock_connect_ex(PySocketSockObject *s, PyObject *addro)
{
struct sockaddr addr = { 0 };
int addrlen;
int res;
int timeout;
if (!getsockaddrarg(s, addro, &addr, &addrlen))
return NULL;
Py_BEGIN_ALLOW_THREADS
res = internal_connect(s, &addr, addrlen, &timeout);
Py_END_ALLOW_THREADS
return PyInt_FromLong((long) res);
}
PyDoc_STRVAR(connect_ex_doc,
"connect_ex(address) -> errno\n\
\n\
This is like connect(address), but returns an error code (the errno value)\n\
instead of raising an exception when an error occurs.");
/* s.fileno() method */
static PyObject *
sock_fileno(PySocketSockObject *s)
{
return PyInt_FromLong((long) s->sock_fd);
}
PyDoc_STRVAR(fileno_doc,
"fileno() -> integer\n\
\n\
Return the integer file descriptor of the socket.");
#ifndef NO_DUP
/* s.dup() method */
static PyObject *
sock_dup(PySocketSockObject *s)
{
int newfd;
PyObject *sock;
newfd = dup(s->sock_fd);
if (newfd < 0)
return s->errorhandler();
sock = (PyObject *) new_sockobject(newfd,
s->sock_family,
s->sock_type,
s->sock_proto);
if (sock == NULL)
close(newfd);
return sock;
}
PyDoc_STRVAR(dup_doc,
"dup() -> socket object\n\
\n\
Return a new socket object connected to the same system resource.");
#endif
/* s.getsockname() method */
static PyObject *
sock_getsockname(PySocketSockObject *s)
{
char addrbuf[256];
int res;
socklen_t addrlen;
if (!getsockaddrlen(s, &addrlen))
return NULL;
memset(addrbuf, 0, addrlen);
Py_BEGIN_ALLOW_THREADS
res = getsockname(s->sock_fd, (struct sockaddr *) addrbuf, &addrlen);
Py_END_ALLOW_THREADS
if (res < 0)
return s->errorhandler();
return makesockaddr(s, (struct sockaddr *) addrbuf, addrlen);
}
PyDoc_STRVAR(getsockname_doc,
"getsockname() -> address info\n\
\n\
Return the address of the local endpoint.");
/* s.getpeername() method */
static PyObject *
sock_getpeername(PySocketSockObject *s)
{
char addrbuf[256];
int res;
socklen_t addrlen;
if (!getsockaddrlen(s, &addrlen))
return NULL;
memset(addrbuf, 0, addrlen);
Py_BEGIN_ALLOW_THREADS
res = getpeername(s->sock_fd, (struct sockaddr *) addrbuf, &addrlen);
Py_END_ALLOW_THREADS
if (res < 0)
return s->errorhandler();
return makesockaddr(s, (struct sockaddr *) addrbuf, addrlen);
}
PyDoc_STRVAR(getpeername_doc,
"getpeername() -> address info\n\
\n\
Return the address of the remote endpoint. For HCI sockets, the address is a\n\
device number (0, 1, 2, etc). For L2CAP sockets, the address is a \n\
(host,psm) tuple. For RFCOMM sockets, the address is a (host,channel) tuple.\n\
For SCO sockets, the address is just the host.");
/* s.listen(n) method */
static PyObject *
sock_listen(PySocketSockObject *s, PyObject *arg)
{
int backlog;
int res;
backlog = PyInt_AsLong(arg);
if (backlog == -1 && PyErr_Occurred())
return NULL;
Py_BEGIN_ALLOW_THREADS
if (backlog < 1)
backlog = 1;
res = listen(s->sock_fd, backlog);
Py_END_ALLOW_THREADS
if (res < 0)
return s->errorhandler();
s->is_listening_socket = 1;
Py_RETURN_NONE;
}
PyDoc_STRVAR(listen_doc,
"listen(backlog)\n\
\n\
Enable a server to accept connections. The backlog argument must be at\n\
least 1; it specifies the number of unaccepted connection that the system\n\
will allow before refusing new connections.");
#ifndef NO_DUP
/* s.makefile(mode) method.
Create a new open file object referring to a dupped version of
the socket's file descriptor. (The dup() call is necessary so
that the open file and socket objects may be closed independent
of each other.)
The mode argument specifies 'r' or 'w' passed to fdopen(). */
static PyObject *
sock_makefile(PySocketSockObject *s, PyObject *args)
{
extern int fclose(FILE *);
char *mode = "r";
int bufsize = -1;
int fd;
FILE *fp;
PyObject *f;
if (!PyArg_ParseTuple(args, "|si:makefile", &mode, &bufsize))
return NULL;
if ((fd = dup(s->sock_fd)) < 0 || (fp = fdopen(fd, mode)) == NULL)
{
if (fd >= 0)
close(fd);
return s->errorhandler();
}
#if PY_MAJOR_VERSION >= 3
f = PyFile_FromFd(fd, "", mode, bufsize, NULL, NULL, NULL, 1);
#else
f = PyFile_FromFile(fp, "", mode, fclose);
if (f != NULL)
PyFile_SetBufSize(f, bufsize);
#endif
return f;
}
PyDoc_STRVAR(makefile_doc,
"makefile([mode[, buffersize]]) -> file object\n\
\n\
Return a regular file object corresponding to the socket.\n\
The mode and buffersize arguments are as for the built-in open() function.");
#endif /* NO_DUP */
/* s.recv(nbytes [,flags]) method */
static PyObject *
sock_recv(PySocketSockObject *s, PyObject *args)
{
int len, n = 0, flags = 0, timeout;
PyObject *buf;
if (!PyArg_ParseTuple(args, "i|i:recv", &len, &flags))
return NULL;
if (len < 0) {
PyErr_SetString(PyExc_ValueError, "negative buffersize in recv");
return NULL;
}
buf = PyString_FromStringAndSize((char *) 0, len);
if (buf == NULL)
return NULL;
Py_BEGIN_ALLOW_THREADS
timeout = internal_select(s, 0);
if (!timeout)
n = recv(s->sock_fd, PyString_AS_STRING(buf), len, flags);
Py_END_ALLOW_THREADS
if (timeout) {
Py_DECREF(buf);
PyErr_SetString(socket_timeout, "timed out");
return NULL;
}
if (n < 0) {
Py_DECREF(buf);
return s->errorhandler();
}
if (n != len)
_PyString_Resize(&buf, n);
return buf;
}
PyDoc_STRVAR(recv_doc,
"recv(buffersize[, flags]) -> data\n\
\n\
Receive up to buffersize bytes from the socket. For the optional flags\n\
argument, see the Unix manual. When no data is available, block until\n\
at least one byte is available or until the remote end is closed. When\n\
the remote end is closed and all data is read, return the empty string.");
/* s.recvfrom(nbytes [,flags]) method */
static PyObject *
sock_recvfrom(PySocketSockObject *s, PyObject *args)
{
char addrbuf[256];
PyObject *buf = NULL;
PyObject *addr = NULL;
PyObject *ret = NULL;
int len, n = 0, flags = 0, timeout;
socklen_t addrlen;
if (!PyArg_ParseTuple(args, "i|i:recvfrom", &len, &flags))
return NULL;
if (!getsockaddrlen(s, &addrlen))
return NULL;
buf = PyString_FromStringAndSize((char *) 0, len);
if (buf == NULL)
return NULL;
Py_BEGIN_ALLOW_THREADS
memset(addrbuf, 0, addrlen);
timeout = internal_select(s, 0);
if (!timeout)
n = recvfrom(s->sock_fd, PyString_AS_STRING(buf), len, flags,
(void *)addrbuf, &addrlen
);
Py_END_ALLOW_THREADS
if (timeout) {
Py_DECREF(buf);
PyErr_SetString(socket_timeout, "timed out");
return NULL;
}
if (n < 0) {
Py_DECREF(buf);
return s->errorhandler();
}
if (n != len && _PyString_Resize(&buf, n) < 0)
return NULL;
if (!(addr = makesockaddr(s, (struct sockaddr *)addrbuf, addrlen)))
goto finally;
ret = Py_BuildValue("OO", buf, addr);
finally:
Py_XDECREF(addr);
Py_XDECREF(buf);
return ret;
}
PyDoc_STRVAR(recvfrom_doc,
"recvfrom(buffersize[, flags]) -> (data, address info)\n\
\n\
Like recv(buffersize, flags) but also return the sender's address info.");
/* s.send(data [,flags]) method */
static PyObject *
sock_send(PySocketSockObject *s, PyObject *args)
{
char *buf;
int len, n = 0, flags = 0, timeout;
if (!PyArg_ParseTuple(args, "s#|i:send", &buf, &len, &flags))
return NULL;
Py_BEGIN_ALLOW_THREADS
timeout = internal_select(s, 1);
if (!timeout)
n = send(s->sock_fd, buf, len, flags);
Py_END_ALLOW_THREADS
if (timeout) {
PyErr_SetString(socket_timeout, "timed out");
return NULL;
}
if (n < 0)
return s->errorhandler();
return PyInt_FromLong((long)n);
}
PyDoc_STRVAR(send_doc,
"send(data[, flags]) -> count\n\
\n\
Send a data string to the socket. For the optional flags\n\
argument, see the Unix manual. Return the number of bytes\n\
sent; this may be less than len(data) if the network is busy.");
/* s.sendall(data [,flags]) method */
static PyObject *
sock_sendall(PySocketSockObject *s, PyObject *args)
{
char *buf;
int len, n = 0, flags = 0, timeout;
if (!PyArg_ParseTuple(args, "s#|i:sendall", &buf, &len, &flags))
return NULL;
Py_BEGIN_ALLOW_THREADS
do {
timeout = internal_select(s, 1);
if (timeout)
break;
n = send(s->sock_fd, buf, len, flags);
if (n < 0)
break;
buf += n;
len -= n;
} while (len > 0);
Py_END_ALLOW_THREADS
if (timeout) {
PyErr_SetString(socket_timeout, "timed out");
return NULL;
}
if (n < 0)
return s->errorhandler();
Py_RETURN_NONE;
}
PyDoc_STRVAR(sendall_doc,
"sendall(data[, flags])\n\
\n\
Send a data string to the socket. For the optional flags\n\
argument, see the Unix manual. This calls send() repeatedly\n\
until all data is sent. If an error occurs, it's impossible\n\
to tell how much data has been sent.");
/* s.sendto(data, [flags,] sockaddr) method */
static PyObject *
sock_sendto(PySocketSockObject *s, PyObject *args)
{
PyObject *addro;
char *buf;
struct sockaddr addr = { 0 };
int addrlen, len, n = 0, flags, timeout;
flags = 0;
if (!PyArg_ParseTuple(args, "s#O:sendto", &buf, &len, &addro)) {
PyErr_Clear();
if (!PyArg_ParseTuple(args, "s#iO:sendto", &buf, &len, &flags, &addro))
return NULL;
}
if (!getsockaddrarg(s, addro, &addr, &addrlen))
return NULL;
Py_BEGIN_ALLOW_THREADS
timeout = internal_select(s, 1);
if (!timeout)
n = sendto(s->sock_fd, buf, len, flags, &addr, addrlen);
Py_END_ALLOW_THREADS
if (timeout) {
PyErr_SetString(socket_timeout, "timed out");
return NULL;
}
if (n < 0)
return s->errorhandler();
return PyInt_FromLong((long)n);
}
PyDoc_STRVAR(sendto_doc,
"sendto(data[, flags], address) -> count\n\
\n\
Like send(data, flags) but allows specifying the destination address.\n\
For IP sockets, the address is a pair (hostaddr, port).");
/* s.shutdown(how) method */
static PyObject *
sock_shutdown(PySocketSockObject *s, PyObject *arg)
{
int how;
int res;
how = PyInt_AsLong(arg);
if (how == -1 && PyErr_Occurred())
return NULL;
Py_BEGIN_ALLOW_THREADS
res = shutdown(s->sock_fd, how);
Py_END_ALLOW_THREADS
if (res < 0)
return s->errorhandler();
Py_RETURN_NONE;
}
PyDoc_STRVAR(shutdown_doc,
"shutdown(flag)\n\
\n\
Shut down the reading side of the socket (flag == 0), the writing side\n\
of the socket (flag == 1), or both ends (flag == 2).");
/* s.getsockid() method */
static PyObject *
sock_getsockid(PySocketSockObject *s, PyObject *arg)
{
int dd;
dd = s->sock_fd;
return Py_BuildValue("i", dd);
}
/* List of methods for socket objects */
static PyMethodDef sock_methods[] = {
{"accept", (PyCFunction)sock_accept, METH_NOARGS,
accept_doc},
{"bind", (PyCFunction)sock_bind, METH_O,
bind_doc},
{"close", (PyCFunction)sock_close, METH_NOARGS,
close_doc},
{"connect", (PyCFunction)sock_connect, METH_O,
connect_doc},
{"connect_ex", (PyCFunction)sock_connect_ex, METH_O,
connect_ex_doc},
#ifndef NO_DUP
{"dup", (PyCFunction)sock_dup, METH_NOARGS,
dup_doc},
#endif
{"fileno", (PyCFunction)sock_fileno, METH_NOARGS,
fileno_doc},
{"getpeername", (PyCFunction)sock_getpeername,
METH_NOARGS, getpeername_doc},
{"getsockid", (PyCFunction)sock_getsockid,
METH_NOARGS, "Gets socket id."},
{"getsockname", (PyCFunction)sock_getsockname,
METH_NOARGS, getsockname_doc},
{"getsockopt", (PyCFunction)sock_getsockopt, METH_VARARGS,
getsockopt_doc},
{"listen", (PyCFunction)sock_listen, METH_O,
listen_doc},
#ifndef NO_DUP
{"makefile", (PyCFunction)sock_makefile, METH_VARARGS,
makefile_doc},
#endif
{"recv", (PyCFunction)sock_recv, METH_VARARGS,
recv_doc},
{"recvfrom", (PyCFunction)sock_recvfrom, METH_VARARGS,
recvfrom_doc},
{"send", (PyCFunction)sock_send, METH_VARARGS,
send_doc},
{"sendall", (PyCFunction)sock_sendall, METH_VARARGS,
sendall_doc},
{"sendto", (PyCFunction)sock_sendto, METH_VARARGS,
sendto_doc},
{"setblocking", (PyCFunction)sock_setblocking, METH_O,
setblocking_doc},
{"settimeout", (PyCFunction)sock_settimeout, METH_O,
settimeout_doc},
{"gettimeout", (PyCFunction)sock_gettimeout, METH_NOARGS,
gettimeout_doc},
{"setsockopt", (PyCFunction)sock_setsockopt, METH_VARARGS,
setsockopt_doc},
{"setl2capsecurity", (PyCFunction)sock_setl2capsecurity, METH_VARARGS,
setl2capsecurity_doc},
{"shutdown", (PyCFunction)sock_shutdown, METH_O,
shutdown_doc},
{NULL, NULL} /* sentinel */
};
/* SockObject members */
static PyMemberDef sock_memberlist[] = {
{"family", T_INT, offsetof(PySocketSockObject, sock_family), READONLY, "the socket family"},
{"type", T_INT, offsetof(PySocketSockObject, sock_type), READONLY, "the socket type"},
{"proto", T_INT, offsetof(PySocketSockObject, sock_proto), READONLY, "the socket protocol"},
{NULL} /* sentinel */
};
static PyGetSetDef sock_getsetlist[] = {
{"timeout", (getter)sock_gettimeout, NULL, PyDoc_STR("the socket timeout")},
{NULL} /* sentinel */
};
/* Deallocate a socket object in response to the last Py_DECREF().
First close the file description. */
static void
sock_dealloc(PySocketSockObject *s)
{
// close the OS file descriptor
if (s->sock_fd != -1) {
Py_BEGIN_ALLOW_THREADS
close(s->sock_fd);
Py_END_ALLOW_THREADS
}
if( s->sdp_session ) {
sdp_close( s->sdp_session );
s->sdp_record_handle = 0;
s->sdp_session = NULL;
}
Py_TYPE(s)->tp_free((PyObject *)s);
}
static PyObject *
sock_repr(PySocketSockObject *s)
{
char buf[512];
#if SIZEOF_SOCKET_T > SIZEOF_LONG
if (s->sock_fd > LONG_MAX) {
/* this can occur on Win64, and actually there is a special
ugly printf formatter for decimal pointer length integer
printing, only bother if necessary*/
PyErr_SetString(PyExc_OverflowError,
"no printf formatter to display "
"the socket descriptor in decimal");
return NULL;
}
#endif
PyOS_snprintf(
buf, sizeof(buf),
"",
(long)s->sock_fd, s->sock_family,
s->sock_type,
s->sock_proto);
return PyString_FromString(buf);
}
/* Create a new, uninitialized socket object. */
static PyObject *
sock_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *new;
new = type->tp_alloc(type, 0);
if (new != NULL) {
((PySocketSockObject *)new)->sock_fd = -1;
((PySocketSockObject *)new)->sock_timeout = -1.0;
((PySocketSockObject *)new)->errorhandler = &set_error;
}
return new;
}
/* Initialize a new socket object. */
/*ARGSUSED*/
static int
sock_initobj(PyObject *self, PyObject *args, PyObject *kwds)
{
PySocketSockObject *s = (PySocketSockObject *)self;
int fd;
int family = AF_BLUETOOTH, type = SOCK_STREAM, proto = BTPROTO_RFCOMM;
static char *keywords[] = {"proto", 0};
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i:socket", keywords, &proto))
return -1;
switch(proto) {
case BTPROTO_HCI:
type = SOCK_RAW;
break;
case BTPROTO_L2CAP:
type = SOCK_SEQPACKET;
break;
case BTPROTO_RFCOMM:
type = SOCK_STREAM;
break;
case BTPROTO_SCO:
type = SOCK_SEQPACKET;
break;
}
Py_BEGIN_ALLOW_THREADS
fd = socket(family, type, proto);
Py_END_ALLOW_THREADS
if (fd < 0)
{
set_error();
return -1;
}
init_sockobject(s, fd, family, type, proto);
/* From now on, ignore SIGPIPE and let the error checking
do the work. */
#ifdef SIGPIPE
(void) signal(SIGPIPE, SIG_IGN);
#endif
return 0;
}
/* Type object for socket objects. */
PyTypeObject sock_type = {
#if PY_MAJOR_VERSION < 3
PyObject_HEAD_INIT(0) /* Must fill in type value later */
0, /* ob_size */
#else
PyVarObject_HEAD_INIT(NULL, 0) /* Must fill in type value later */
#endif
"_bluetooth.btsocket", /* tp_name */
sizeof(PySocketSockObject), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)sock_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
(reprfunc)sock_repr,/* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
sock_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
sock_methods, /* tp_methods */
sock_memberlist, /* tp_members */
sock_getsetlist, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
sock_initobj, /* tp_init */
PyType_GenericAlloc,/* tp_alloc */
sock_new, /* tp_new */
PyObject_Del, /* tp_free */
};
#ifndef NO_DUP
/* Create a socket object from a numeric file description.
Useful e.g. if stdin is a socket.
Additional arguments as for socket(). */
/*ARGSUSED*/
static PyObject *
bt_fromfd(PyObject *self, PyObject *args)
{
PySocketSockObject *s;
int fd;
int family, type, proto = 0;
if (!PyArg_ParseTuple(args, "iii|i:fromfd", &fd, &family, &type, &proto))
return NULL;
/* Dup the fd so it and the socket can be closed independently */
fd = dup(fd);
if (fd < 0)
return set_error();
s = new_sockobject(fd, family, type, proto);
/* From now on, ignore SIGPIPE and let the error checking do the work. */
#ifdef SIGPIPE
(void) signal(SIGPIPE, SIG_IGN);
#endif
return (PyObject *) s;
}
PyDoc_STRVAR(bt_fromfd_doc,
"fromfd(fd, family, type[, proto]) -> socket object\n\
\n\
Create a socket object from the given file descriptor.\n\
The remaining arguments are the same as for socket().");
#endif /* NO_DUP */
static PyObject *
bt_btohs(PyObject *self, PyObject *args)
{
int x1, x2;
if (!PyArg_ParseTuple(args, "i:btohs", &x1)) {
return NULL;
}
x2 = (int)btohs((short)x1);
return PyInt_FromLong(x2);
}
PyDoc_STRVAR(bt_btohs_doc,
"btohs(integer) -> integer\n\
\n\
Convert a 16-bit integer from bluetooth to host byte order.");
static PyObject *
bt_btohl(PyObject *self, PyObject *args)
{
unsigned long x;
PyObject *arg;
if (!PyArg_ParseTuple(args, "O:btohl", &arg)) {
return NULL;
}
if (PyInt_Check(arg)) {
x = PyInt_AS_LONG(arg);
if (x == (unsigned long) -1 && PyErr_Occurred())
return NULL;
}
else if (PyLong_Check(arg)) {
x = PyLong_AsUnsignedLong(arg);
if (x == (unsigned long) -1 && PyErr_Occurred())
return NULL;
#if SIZEOF_LONG > 4
{
unsigned long y;
/* only want the trailing 32 bits */
y = x & 0xFFFFFFFFUL;
if (y ^ x)
return PyErr_Format(PyExc_OverflowError,
"long int larger than 32 bits");
x = y;
}
#endif
}
else
return PyErr_Format(PyExc_TypeError,
"expected int/long, %s found",
arg->ob_type->tp_name);
if (x == (unsigned long) -1 && PyErr_Occurred())
return NULL;
return PyInt_FromLong(btohl(x));
}
PyDoc_STRVAR(bt_btohl_doc,
"btohl(integer) -> integer\n\
\n\
Convert a 32-bit integer from bluetooth to host byte order.");
static PyObject *
bt_htobs(PyObject *self, PyObject *args)
{
unsigned long x1, x2;
if (!PyArg_ParseTuple(args, "i:htobs", &x1)) {
return NULL;
}
x2 = (int)htobs((short)x1);
return PyInt_FromLong(x2);
}
PyDoc_STRVAR(bt_htobs_doc,
"htobs(integer) -> integer\n\
\n\
Convert a 16-bit integer from host to bluetooth byte order.");
static PyObject *
bt_htobl(PyObject *self, PyObject *args)
{
unsigned long x;
PyObject *arg;
if (!PyArg_ParseTuple(args, "O:htobl", &arg)) {
return NULL;
}
if (PyInt_Check(arg)) {
x = PyInt_AS_LONG(arg);
if (x == (unsigned long) -1 && PyErr_Occurred())
return NULL;
}
else if (PyLong_Check(arg)) {
x = PyLong_AsUnsignedLong(arg);
if (x == (unsigned long) -1 && PyErr_Occurred())
return NULL;
#if SIZEOF_LONG > 4
{
unsigned long y;
/* only want the trailing 32 bits */
y = x & 0xFFFFFFFFUL;
if (y ^ x)
return PyErr_Format(PyExc_OverflowError,
"long int larger than 32 bits");
x = y;
}
#endif
}
else
return PyErr_Format(PyExc_TypeError,
"expected int/long, %s found",
arg->ob_type->tp_name);
return PyInt_FromLong(htobl(x));
}
//static PyObject *
//bt_get_available_port_number( PyObject *self, PyObject *arg )
//{
// int protocol = -1;
// int s;
//
// protocol = PyInt_AsLong(arg);
//
// if (protocol == -1 && PyErr_Occurred())
// return NULL;
//
// switch(protocol) {
// case BTPROTO_RFCOMM:
// {
// struct sockaddr_rc sockaddr = { 0 };
// int s, psm;
// s = socket( AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM );
//
// sockaddr.rc_family = AF_BLUETOOTH;
// bacppy( &sockaddr.rc_bdaddr, BDADDR_ANY
// }
// break;
// case BTPROTO_L2CAP:
// {
// loc_addr.l2_family = AF_BLUETOOTH;
// bacpy( &loc_addr.l2_bdaddr, BDADDR_ANY );
// loc_addr.l2_psm = htobs(0x1001);
//
// }
// break;
// default:
// {
// PyErr_SetString( PyExc_ValueError,
// "protocol must be either RFCOMM or L2CAP" );
// return 0;
// }
// break;
// }
// Py_RETURN_NONE;
//}
PyDoc_STRVAR(bt_htobl_doc,
"htobl(integer) -> integer\n\
\n\
Convert a 32-bit integer from host to bluetooth byte order.");
/* Python API to getting and setting the default timeout value. */
static PyObject *
bt_getdefaulttimeout(PyObject *self)
{
if (defaulttimeout < 0.0)
Py_RETURN_NONE;
else
return PyFloat_FromDouble(defaulttimeout);
}
PyDoc_STRVAR(bt_getdefaulttimeout_doc,
"getdefaulttimeout() -> timeout\n\
\n\
Returns the default timeout in floating seconds for new socket objects.\n\
A value of None indicates that new socket objects have no timeout.\n\
When the socket module is first imported, the default is None.");
static PyObject *
bt_setdefaulttimeout(PyObject *self, PyObject *arg)
{
double timeout;
if (arg == Py_None)
timeout = -1.0;
else {
timeout = PyFloat_AsDouble(arg);
if (timeout < 0.0) {
if (!PyErr_Occurred())
PyErr_SetString(PyExc_ValueError, "Timeout value out of range");
return NULL;
}
}
defaulttimeout = timeout;
Py_RETURN_NONE;
}
PyDoc_STRVAR(bt_setdefaulttimeout_doc,
"setdefaulttimeout(timeout)\n\
\n\
Set the default timeout in floating seconds for new socket objects.\n\
A value of None indicates that new socket objects have no timeout.\n\
When the socket module is first imported, the default is None.");
/*
* ----------------------------------------------------------------------
* HCI Section (Calvin)
*
* This section provides the socket methods for calling HCI commands.
* These commands may be called statically, and implementation is
* independent from the rest of the module (except for bt_methods[]).
*
* ----------------------------------------------------------------------
*
*/
/*
* params: (int) device number
* effect: opens and binds a new HCI socket
* return: a PySocketSockObject, or NULL on failure
*/
static PyObject *
bt_hci_open_dev(PyObject *self, PyObject *args)
{
int dev = -1, fd;
PySocketSockObject *s = NULL;
if ( !PyArg_ParseTuple(args, "|i", &dev) )
{
return NULL;
}
// if the device was not specified, just use the first available bt device
if (dev < 0) {
dev = hci_get_route(NULL);
}
if (dev < 0) {
PyErr_SetString(bluetooth_error, "no available bluetoot devices");
return 0;
}
Py_BEGIN_ALLOW_THREADS
fd = hci_open_dev(dev);
Py_END_ALLOW_THREADS
s = (PySocketSockObject *)PyType_GenericNew(&sock_type, NULL, NULL);
if (s != NULL) init_sockobject(s, fd, AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
return (PyObject*)s;
}
PyDoc_STRVAR(bt_hci_open_dev_doc, "hci_open_dev");
/*
* params: (int) device number
* effect: closes an HCI socket
*/
static PyObject *
bt_hci_close_dev(PyObject *self, PyObject *args)
{
int dev, err;
if ( !PyArg_ParseTuple(args, "i", &dev) )
{
return NULL;
}
Py_BEGIN_ALLOW_THREADS
err = hci_close_dev(dev);
Py_END_ALLOW_THREADS
if( err < 0 ) return set_error();
Py_RETURN_NONE;
}
PyDoc_STRVAR(bt_hci_close_dev_doc,
"hci_close_dev(dev_id)\n\
\n\
Closes the specified device id. Note: device id is NOT a btoscket.\n\
You can also use btsocket.close() to close a specific socket.");
/*
* params: (int) socket fd, (uint_16) ogf control bits
* (uint_16) ocf control bits, (struct) command params
* effect: executes command described by the OGF and OCF bits
* (see bluetooth/hci.h)
* return: (int) 0 on success, -1 on failure
*/
static PyObject *
bt_hci_send_cmd(PyObject *self, PyObject *args)
{
PySocketSockObject *socko = NULL;
int err, plen = 0;
uint16_t ogf, ocf;
char *param = NULL;
int dd = 0;
if ( !PyArg_ParseTuple(args, "OHH|s#", &socko, &ogf, &ocf, ¶m, &plen)) {
return NULL;
}
dd = socko->sock_fd;
Py_BEGIN_ALLOW_THREADS
err = hci_send_cmd(dd, ogf, ocf, plen, (void*)param);
Py_END_ALLOW_THREADS
if( err ) return socko->errorhandler();
return Py_BuildValue("i", err);
}
PyDoc_STRVAR(bt_hci_send_cmd_doc,
"hci_send_cmd(sock, ogf, ocf, params)\n\
\n\
Transmits the specified HCI command to the socket.\n\
sock - the btoscket object to use\n\
ogf, pcf - see bluetooth specification\n\
params - packed command parameters (use the struct module to do this)");
static PyObject *
bt_hci_send_req(PyObject *self, PyObject *args, PyObject *kwds)
{
PySocketSockObject *socko = NULL;
int err;
int to=0;
char rparam[256];
struct hci_request req = { 0 };
int dd = 0;
static char *keywords[] = { "sock", "ogf", "ocf", "event", "rlen", "params",
"timeout", 0 };
if( !PyArg_ParseTupleAndKeywords(args, kwds, "OHHii|s#i", keywords,
&socko, &req.ogf, &req.ocf, &req.event, &req.rlen,
&req.cparam, &req.clen, &to) )
return 0;
req.rparam = rparam;
dd = socko->sock_fd;
Py_BEGIN_ALLOW_THREADS
err = hci_send_req( dd, &req, to );
Py_END_ALLOW_THREADS
if( err< 0 ) return socko->errorhandler();
return PyString_FromStringAndSize(rparam, req.rlen);
}
PyDoc_STRVAR(bt_hci_send_req_doc,
"hci_send_req(sock, ogf, ocf, event, rlen, params=None, timeout=0)\n\
\n\
Transmits a HCI cmomand to the socket and waits for the specified event.\n\
sock - the btsocket object\n\
ogf, ocf - see bluetooth specification\n\
event - the event to wait for. Probably one of EVT_*\n\
rlen - the size of the returned packet to expect. This must be\n\
specified since bt won't know how much data to expect\n\
otherwise\n\
params - the command parameters\n\
timeout - timeout, in milliseconds");
static PyObject*
bt_hci_inquiry(PyObject *self, PyObject *args, PyObject *kwds)
{
int i, err;
int dev_id = 0;
int length = 8;
int flush = 1;
int flags = 0;
int lookup_class = 0;
int iac = 0x9e8b33;
char ba_name[19];
inquiry_info *info = NULL;
PySocketSockObject *socko = NULL;
struct hci_inquiry_req *ir;
char buf[sizeof(*ir) + sizeof(inquiry_info) * 250];
PyObject *rtn_list = (PyObject *)NULL;
static char *keywords[] = {"sock", "duration", "flush_cache",
"lookup_class", "device_id", "iac", 0};
if( !PyArg_ParseTupleAndKeywords(args, kwds, "O|iiiii", keywords,
&socko, &length, &flush, &lookup_class, &dev_id, &iac) )
{
return 0;
}
flags |= (flush) ? IREQ_CACHE_FLUSH : 0;
ir = (struct hci_inquiry_req*)buf;
ir->dev_id = dev_id;
ir->num_rsp = 250;
ir->length = length;
ir->flags = flags;
ir->lap[0] = iac & 0xff;
ir->lap[1] = (iac >> 8) & 0xff;
ir->lap[2] = (iac >> 16) & 0xff;
Py_BEGIN_ALLOW_THREADS
err = ioctl(socko->sock_fd, HCIINQUIRY, (unsigned long) buf);
Py_END_ALLOW_THREADS
if( err < 0 ) return socko->errorhandler();
info = (inquiry_info*)(buf + sizeof(*ir));
if( (rtn_list = PyList_New(0)) == NULL ) return 0;
memset( ba_name, 0, sizeof(ba_name) );
// fill in the list with the discovered bluetooth addresses
for(i=0;inum_rsp;i++) {
PyObject * addr_entry = (PyObject *)NULL;
int err;
ba2str( &(info+i)->bdaddr, ba_name );
addr_entry = PyString_FromString( ba_name );
if (lookup_class) {
PyObject *item_tuple = PyTuple_New(2);
int dev_class = (info+i)->dev_class[2] << 16 |
(info+i)->dev_class[1] << 8 |
(info+i)->dev_class[0];
PyObject *class_entry = PyInt_FromLong( dev_class );
err = PyTuple_SetItem( item_tuple, 0, addr_entry );
if (err) {
Py_XDECREF( item_tuple );
Py_XDECREF( rtn_list );
return NULL;
}
err = PyTuple_SetItem( item_tuple, 1, class_entry );
if (err) {
Py_XDECREF( item_tuple );
Py_XDECREF( rtn_list );
return NULL;
}
err = PyList_Append( rtn_list, item_tuple );
Py_DECREF( item_tuple );
if (err) {
Py_XDECREF( rtn_list );
return NULL;
}
} else {
err = PyList_Append( rtn_list, addr_entry );
Py_DECREF( addr_entry );
if (err) {
Py_XDECREF( rtn_list );
return NULL;
}
}
}
return rtn_list;
}
PyDoc_STRVAR(bt_hci_inquiry_doc,
"hci_inquiry(dev_id=0, duration=8, flush_cache=True\n\
\n\
Performs a device inquiry using the specified device (usually 0 or 1).\n\
The inquiry will last 1.28 * duration seconds. If flush_cache is True, then\n\
previously discovered devices will not be returned in the inquiry.)");
static PyObject*
bt_hci_read_remote_name(PyObject *self, PyObject *args, PyObject *kwds)
{
char *addr = NULL;
bdaddr_t ba;
int timeout = 5192;
static char name[249];
PySocketSockObject *socko = NULL;
int err = 0;
static char *keywords[] = {"dd", "bdaddr", "timeout", 0};
if( !PyArg_ParseTupleAndKeywords(args, kwds, "Os|i", keywords,
&socko, &addr, &timeout) )
{
return 0;
}
str2ba( addr, &ba );
memset( name, 0, sizeof(name) );
Py_BEGIN_ALLOW_THREADS
err = hci_read_remote_name( socko->sock_fd, &ba, sizeof(name)-1,
name, timeout );
Py_END_ALLOW_THREADS
if( err < 0)
return PyErr_SetFromErrno(bluetooth_error);
return PyString_FromString( name );
}
PyDoc_STRVAR(bt_hci_read_remote_name_doc,
"hci_read_remote_name(sock, bdaddr, timeout=5192)\n\
\n\
Performs a remote name request to the specified bluetooth device.\n\
sock - the HCI socket object to use\n\
bdaddr - the bluetooth address of the remote device\n\
timeout - maximum amount of time, in milliseconds, to wait\n\
\n\
Returns the name of the device, or raises an error on failure");
static char *opcode2str(uint16_t opcode);
static PyObject*
bt_hci_opcode_name(PyObject *self, PyObject *args)
{
int opcode;
PyArg_ParseTuple(args,"i", &opcode);
// DPRINTF("opcode = %x\n", opcode);
const char* cmd_name = opcode2str (opcode);
return PyString_FromString( cmd_name );
}
PyDoc_STRVAR(bt_hci_opcode_name_doc,
"hci_opcode_name(opcode)\n\
\n\
Performs a remote name request to the specified bluetooth device.\n\
sock - the HCI socket object to use\n\
bdaddr - the bluetooth address of the remote device\n\
timeout - maximum amount of time, in milliseconds, to wait\n\
\n\
Returns the name of the device, or raises an error on failure");
#define EVENT_NUM 77
static char *event_str[];
static PyObject*
bt_hci_event_name(PyObject *self, PyObject *args)
{
int eventNum;
PyArg_ParseTuple(args,"i", &eventNum);
if ((eventNum > EVENT_NUM) || (eventNum < 0)) {
PyErr_SetString(bluetooth_error,
"hci_event_name: invalid event number");
return 0;
}
const char* event_name = event_str[eventNum];
return PyString_FromString( event_name );
}
PyDoc_STRVAR(bt_hci_event_name_doc,
"hci_event_name(eventNum)\n\
\n\
Returns a string withe description of the HCI event.\n\
sock - the HCI socket object to use\n\
eventNum - valid number\n\
\n\
Returns the name of the device, or raises an error on failure");
// lot of repetitive code... yay macros!!
#define DECL_HCI_FILTER_OP_1(name, docstring) \
static PyObject * bt_hci_filter_ ## name (PyObject *self, PyObject *args )\
{ \
char *param; \
int len, arg; \
if( !PyArg_ParseTuple(args,"s#i", ¶m, &len, &arg) ) \
return 0; \
if( len != sizeof(struct hci_filter) ) { \
PyErr_SetString(PyExc_ValueError, "bad filter"); \
return 0; \
} \
hci_filter_ ## name ( arg, (struct hci_filter*)param ); \
return PyString_FromStringAndSize(param, len); \
} \
PyDoc_STRVAR(bt_hci_filter_ ## name ## _doc, docstring);
DECL_HCI_FILTER_OP_1(set_ptype, "set ptype!")
DECL_HCI_FILTER_OP_1(clear_ptype, "clear ptype!")
DECL_HCI_FILTER_OP_1(test_ptype, "test ptype!")
DECL_HCI_FILTER_OP_1(set_event, "set event!")
DECL_HCI_FILTER_OP_1(clear_event, "clear event!")
DECL_HCI_FILTER_OP_1(test_event, "test event!")
DECL_HCI_FILTER_OP_1(set_opcode, "set opcode!")
DECL_HCI_FILTER_OP_1(test_opcode, "test opcode!")
#undef DECL_HCI_FILTER_OP_1
#define DECL_HCI_FILTER_OP_2(name, docstring) \
static PyObject * bt_hci_filter_ ## name (PyObject *self, PyObject *args )\
{ \
char *param; \
int len; \
if( !PyArg_ParseTuple(args,"s#", ¶m, &len) ) \
return 0; \
if( len != sizeof(struct hci_filter) ) { \
PyErr_SetString(PyExc_ValueError, "bad filter"); \
return 0; \
} \
hci_filter_ ## name ( (struct hci_filter*)param ); \
return PyString_FromStringAndSize(param, len); \
} \
PyDoc_STRVAR(bt_hci_filter_ ## name ## _doc, docstring);
DECL_HCI_FILTER_OP_2(all_events, "all events!");
DECL_HCI_FILTER_OP_2(clear, "clear filter");
DECL_HCI_FILTER_OP_2(all_ptypes, "all packet types!");
DECL_HCI_FILTER_OP_2(clear_opcode, "clear opcode!")
#undef DECL_HCI_FILTER_OP_2
static PyObject *
bt_cmd_opcode_pack(PyObject *self, PyObject *args )
{
uint16_t opcode, ogf, ocf;
if (!PyArg_ParseTuple(args, "HH", &ogf, &ocf )) return 0;
opcode = cmd_opcode_pack(ogf, ocf);
return Py_BuildValue("H", opcode);
}
PyDoc_STRVAR(bt_cmd_opcode_pack_doc,
"cmd_opcode_pack(ogf, ocf)\n\
\n\
Packs an OCF and an OGF value together to form a opcode");
static PyObject *
bt_cmd_opcode_ogf(PyObject *self, PyObject *args )
{
uint16_t opcode;
if (!PyArg_ParseTuple(args, "H", &opcode)) return 0;
return Py_BuildValue("H", cmd_opcode_ogf(opcode));
}
PyDoc_STRVAR(bt_cmd_opcode_ogf_doc,
"cmd_opcode_ogf(opcode)\n\
\n\
Convenience function to extract and return the OGF value from an opcode");
static PyObject *
bt_cmd_opcode_ocf(PyObject *self, PyObject *args )
{
uint16_t opcode;
if (!PyArg_ParseTuple(args, "H", &opcode)) return 0;
return Py_BuildValue("H", cmd_opcode_ocf(opcode));
}
PyDoc_STRVAR(bt_cmd_opcode_ocf_doc,
"cmd_opcode_ocf(opcode)\n\
\n\
Convenience function to extract and return the OCF value from an opcode");
static PyObject *
bt_ba2str(PyObject *self, PyObject *args)
{
char *data=NULL;
int len=0;
char ba_str[19] = {0};
if (!PyArg_ParseTuple(args, "s#", &data, &len)) return 0;
ba2str((bdaddr_t*)data, ba_str);
return PyString_FromString( ba_str );
// return Py_BuildValue("s#", ba_str, 18);
}
PyDoc_STRVAR(bt_ba2str_doc,
"ba2str(data)\n\
\n\
Converts a packed bluetooth address to a human readable string");
static PyObject *
bt_str2ba(PyObject *self, PyObject *args)
{
char *ba_str=NULL;
bdaddr_t ba;
if (!PyArg_ParseTuple(args, "s", &ba_str)) return 0;
str2ba( ba_str, &ba );
return Py_BuildValue(BYTES_FORMAT_CHR, (char*)(&ba), sizeof(ba));
}
PyDoc_STRVAR(bt_str2ba_doc,
"str2ba(string)\n\
\n\
Converts a bluetooth address string into a packed bluetooth address.\n\
The string should be of the form \"XX:XX:XX:XX:XX:XX\"");
/*
* params: (string) device address
* effect: -
* return: Device id
*/
static PyObject *
bt_hci_devid(PyObject *self, PyObject *args)
{
char *devaddr=NULL;
int devid;
if ( !PyArg_ParseTuple(args, "|s", &devaddr) )
{
return NULL;
}
if (devaddr)
devid=hci_devid(devaddr);
else
devid=hci_get_route(NULL);
return Py_BuildValue("i",devid);
}
PyDoc_STRVAR( bt_hci_devid_doc,
"hci_devid(address)\n\
\n\
Get the device id for the local device with specified address.");
/*
* params: (string) device address
* effect: -
* return: Device id
*/
static PyObject *
bt_hci_role(PyObject *self, PyObject *args)
{
int devid;
int fd;
int role;
if ( !PyArg_ParseTuple(args, "ii", &fd, &devid) )
return NULL;
struct hci_dev_info di = {dev_id: devid};
if (ioctl(fd, HCIGETDEVINFO, (void *) &di))
return NULL;
role = di.link_mode == HCI_LM_MASTER;
return Py_BuildValue("i", role);
}
PyDoc_STRVAR( bt_hci_role_doc,
"hci_role(hci_fd, dev_id)\n\
\n\
Get the role (master or slave) of the device id.");
/*
* params: (string) device address
* effect: -
* return: Device id
*/
static PyObject *
bt_hci_read_clock(PyObject *self, PyObject *args)
{
int fd;
int handle;
int which;
int timeout;
uint32_t btclock;
uint16_t accuracy;
int res;
if ( !PyArg_ParseTuple(args, "iiii", &fd, &handle, &which, &timeout) )
return NULL;
res = hci_read_clock(fd, handle, which, &btclock, &accuracy, timeout);
if (res)
Py_RETURN_NONE;
return Py_BuildValue("(ii)", btclock, accuracy);
}
PyDoc_STRVAR( bt_hci_read_clock_doc,
"hci_read_clock(hci_fd, acl_handle, which_clock, timeout_ms)\n\
\n\
Get the Bluetooth Clock (native or piconet).");
/*
* params: (string) device address
* effect: -
* return: Device id
*/
static PyObject *
bt_hci_get_route(PyObject *self, PyObject *args)
{
int dev_id = 0;
char *addr = NULL;
bdaddr_t ba;
if ( !PyArg_ParseTuple(args, "|s", &addr) ) {
return NULL;
}
if(addr && strlen(addr)) {
str2ba( addr, &ba );
dev_id = hci_get_route(&ba);
} else {
dev_id = hci_get_route(NULL);
}
if (dev_id < 0) {
return PyErr_SetFromErrno(PyExc_OSError);
}
return PyInt_FromLong(dev_id);
}
PyDoc_STRVAR( bt_hci_get_route_doc,
"hci_get_route(address)\n\
\n\
Get the device id through which remote specified addr can be reached.");
/*
* params: (string) device address
* effect: -
* return: Device id
*/
static PyObject *
bt_hci_acl_conn_handle(PyObject *self, PyObject *args)
{
int fd;
char *devaddr=NULL;
bdaddr_t binaddr;
struct hci_conn_info_req *cr;
char buf[sizeof(struct hci_conn_info_req) + sizeof(struct hci_conn_info)];
int handle = -1;
if ( !PyArg_ParseTuple(args, "is", &fd, &devaddr) )
return NULL;
if (devaddr)
str2ba(devaddr, &binaddr);
else
str2ba("00:00:00:00:00:00", &binaddr);
cr = (struct hci_conn_info_req*) &buf;
bacpy(&cr->bdaddr, &binaddr);
cr->type = ACL_LINK;
if (ioctl(fd, HCIGETCONNINFO, (unsigned long) cr) == 0)
handle = htobs(cr->conn_info->handle);
return Py_BuildValue("i", handle);
}
PyDoc_STRVAR( bt_hci_acl_conn_handle_doc,
"hci_acl_conn_handle(hci_fd, address)\n\
\n\
Get the ACL connection handle for the given remote device addr.");
static PyObject *
bt_hci_filter_new(PyObject *self, PyObject *args)
{
struct hci_filter flt;
int len = sizeof(flt);
hci_filter_clear( &flt );
return Py_BuildValue("s#", (char*)&flt, len);
}
PyDoc_STRVAR(bt_hci_filter_new_doc,
"hci_filter_new()\n\
\n\
Returns a new HCI filter suitable for operating on with the hci_filter_*\n\
methods, and for passing to getsockopt and setsockopt. The filter is\n\
initially cleared");
/*
* -------------------
* End of HCI section
* -------------------
*/
/* ========= SDP specific bluetooth module methods ========== */
PyObject *
bt_sdp_advertise_service( PyObject *self, PyObject *args )
{
PySocketSockObject *socko = NULL;
char *name = NULL,
*service_id_str = NULL,
*provider = NULL,
*description = NULL;
PyObject *service_classes, *profiles, *protocols;
int namelen = 0, provlen = 0, desclen = 0;
uuid_t svc_uuid = { 0 };
int i;
char addrbuf[256] = { 0 };
int res;
socklen_t addrlen;
struct sockaddr *sockaddr;
uuid_t root_uuid, l2cap_uuid, rfcomm_uuid;
sdp_list_t *l2cap_list = 0,
*rfcomm_list = 0,
*root_list = 0,
*proto_list = 0,
*profile_list = 0,
*svc_class_list = 0,
*access_proto_list = 0;
sdp_data_t *channel = 0, *psm = 0;
sdp_record_t record;
sdp_session_t *session = 0;
int err = 0;
if (!PyArg_ParseTuple(args, "O!s#sOOs#s#O", &sock_type, &socko, &name,
&namelen, &service_id_str, &service_classes,
&profiles, &provider, &provlen, &description, &desclen,
&protocols)) {
return 0;
}
if( provlen == 0 ) provider = NULL;
if( desclen == 0 ) description = NULL;
if( socko->sdp_record_handle != 0 ) {
PyErr_SetString(bluetooth_error,
"SDP service record already registered with this socket!");
return 0;
}
if( namelen == 0 ) {
PyErr_SetString(bluetooth_error, "must specify name!");
return 0;
}
// convert the service ID string into a uuid_t if it was specified
if( strlen(service_id_str) && ! str2uuid( service_id_str, &svc_uuid ) ) {
PyErr_SetString(PyExc_ValueError, "invalid service ID");
return NULL;
}
// service_classes must be a list / sequence
if (! PySequence_Check(service_classes)) {
PyErr_SetString(PyExc_ValueError, "service_classes must be a sequence");
return 0;
}
// make sure each item in the list is a valid UUID
for(i = 0; i < PySequence_Length(service_classes); ++i) {
PyObject *item = PySequence_GetItem(service_classes, i);
if( ! pyunicode2uuid( item, NULL ) ) {
PyErr_SetString(PyExc_ValueError,
"service_classes must be a list of "
"strings, each either of the form XXXX or "
"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX");
return 0;
}
}
// profiles must be a list / sequence
if (! PySequence_Check(profiles)) {
PyErr_SetString(PyExc_ValueError, "profiles must be a sequence");
return 0;
}
// make sure each item in the list is a valid ( uuid, version ) pair
for(i = 0; i < PySequence_Length(profiles); ++i) {
char *profile_uuid_str = NULL;
uint16_t version;
PyObject *tuple = PySequence_GetItem(profiles, i);
if ( ( ! PySequence_Check(tuple) ) ||
( ! PyArg_ParseTuple(tuple, "sH",
&profile_uuid_str, &version)) ||
( ! str2uuid( profile_uuid_str, NULL ) )
) {
PyErr_SetString(PyExc_ValueError,
"Each profile must be a ('uuid', version) tuple");
return 0;
}
}
// protocols must be a list / sequence
if (! PySequence_Check(protocols)) {
PyErr_SetString(PyExc_ValueError, "protocols must be a sequence");
return 0;
}
// make sure each item in the list is a valid UUID
for(i = 0; i < PySequence_Length(protocols); ++i) {
PyObject *item = PySequence_GetItem(protocols, i);
if( ! pyunicode2uuid( item, NULL ) ) {
PyErr_SetString(PyExc_ValueError,
"protocols must be a list of "
"strings, each either of the form XXXX or "
"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX");
return 0;
}
}
// verify that the socket is bound and listening
if( ! socko->is_listening_socket ) {
PyErr_SetString(bluetooth_error,
"must have already called socket.listen()");
return 0;
}
// verify whether device can be advertisable
if(adv_available(socko) < 0) {
PyErr_SetString(bluetooth_error, "no advertisable device");
return 0;
}
// get the socket information
if (!getsockaddrlen(socko, &addrlen)) {
PyErr_SetString(bluetooth_error, "error getting socket information");
return 0;
}
Py_BEGIN_ALLOW_THREADS
res = getsockname(socko->sock_fd, (struct sockaddr *) addrbuf, &addrlen);
Py_END_ALLOW_THREADS
if (res < 0) {
PyErr_SetString(bluetooth_error, "error getting socket information");
return 0;
}
sockaddr = (struct sockaddr *)addrbuf;
// can only deal with L2CAP and RFCOMM sockets
if( socko->sock_proto != BTPROTO_L2CAP &&
socko->sock_proto != BTPROTO_RFCOMM ) {
PyErr_SetString(bluetooth_error,
"Sorry, can only advertise L2CAP and RFCOMM sockets for now");
return 0;
}
// abort if this socket is already advertising a service
if( socko->sdp_record_handle != 0 && socko->sdp_session != NULL ) {
PyErr_SetString(bluetooth_error,
"This socket is already being used to advertise a service!\n"
"Use stop_advertising first!\n");
return 0;
}
// okay, now construct the SDP service record.
memset( &record, 0, sizeof(sdp_record_t) );
record.handle = 0xffffffff;
// make the service record publicly browsable
sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
root_list = sdp_list_append(0, &root_uuid);
sdp_set_browse_groups( &record, root_list );
// set l2cap information (this will always go in)
sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
l2cap_list = sdp_list_append( 0, &l2cap_uuid );
proto_list = sdp_list_append( 0, l2cap_list );
if( socko->sock_proto == BTPROTO_RFCOMM ) {
// register the RFCOMM channel for RFCOMM sockets
uint8_t rfcomm_channel = ((struct sockaddr_rc*)sockaddr)->rc_channel;
sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
channel = sdp_data_alloc(SDP_UINT8, &rfcomm_channel);
rfcomm_list = sdp_list_append( 0, &rfcomm_uuid );
sdp_list_append( rfcomm_list, channel );
sdp_list_append( proto_list, rfcomm_list );
} else {
// register the PSM for L2CAP sockets
unsigned short l2cap_psm = ((struct sockaddr_l2*)sockaddr)->l2_psm;
psm = sdp_data_alloc(SDP_UINT16, &l2cap_psm);
sdp_list_append(l2cap_list, psm);
}
// add additional protocols, if any
sdp_list_t *extra_protos_array[PySequence_Length(protocols)];
if (PySequence_Length(protocols) > 0) {
for(i = 0; i < PySequence_Length(protocols); i++) {
uuid_t *proto_uuid = (uuid_t*) malloc( sizeof( uuid_t ) );
PyObject *item = PySequence_GetItem(protocols, i);
pyunicode2uuid( item, proto_uuid );
sdp_list_t *new_list;
new_list = sdp_list_append( 0, proto_uuid );
proto_list = sdp_list_append( proto_list, new_list );
// keep track, to free the list later
extra_protos_array[i] = new_list;
}
}
access_proto_list = sdp_list_append( 0, proto_list );
sdp_set_access_protos( &record, access_proto_list );
// add service classes, if any
for(i = 0; i < PySequence_Length(service_classes); i++) {
uuid_t *svc_class_uuid = (uuid_t*) malloc( sizeof( uuid_t ) );
PyObject *item = PySequence_GetItem(service_classes, i);
pyunicode2uuid( item, svc_class_uuid );
svc_class_list = sdp_list_append(svc_class_list, svc_class_uuid);
}
sdp_set_service_classes(&record, svc_class_list);
// add profiles, if any
for(i = 0; i < PySequence_Length(profiles); i++) {
char *profile_uuid_str;
sdp_profile_desc_t *profile_desc =
(sdp_profile_desc_t*)malloc(sizeof(sdp_profile_desc_t));
PyObject *tuple = PySequence_GetItem(profiles, i);
PyArg_ParseTuple(tuple, "sH", &profile_uuid_str,
&profile_desc->version);
str2uuid( profile_uuid_str, &profile_desc->uuid );
profile_list = sdp_list_append( profile_list, profile_desc );
}
sdp_set_profile_descs(&record, profile_list);
// set the name, provider and description
sdp_set_info_attr( &record, name, provider, description );
// set the general service ID, if needed
if( strlen(service_id_str) ) sdp_set_service_id( &record, svc_uuid );
// connect to the local SDP server, register the service record, and
// disconnect
Py_BEGIN_ALLOW_THREADS
session = sdp_connect( BDADDR_ANY, BDADDR_LOCAL, 0 );
Py_END_ALLOW_THREADS
if (!session) {
PyErr_SetFromErrno (bluetooth_error);
return 0;
}
socko->sdp_session = session;
Py_BEGIN_ALLOW_THREADS
err = sdp_record_register(session, &record, 0);
Py_END_ALLOW_THREADS
// cleanup
if( psm ) sdp_data_free( psm );
if( channel ) sdp_data_free( channel );
sdp_list_free( l2cap_list, 0 );
sdp_list_free( rfcomm_list, 0 );
for(i = 0; i < PySequence_Length(protocols); i++) {
sdp_list_free( extra_protos_array[i], free );
}
sdp_list_free( root_list, 0 );
sdp_list_free( access_proto_list, 0 );
sdp_list_free( svc_class_list, free );
sdp_list_free( profile_list, free );
if( err ) {
PyErr_SetFromErrno(bluetooth_error);
return 0;
}
socko->sdp_record_handle = record.handle;
Py_RETURN_NONE;
}
PyDoc_STRVAR( bt_sdp_advertise_service_doc,
"sdp_advertise_service( socket, name )\n\
\n\
Registers a service with the local SDP server.\n\
\n\
socket must be a bound, listening socket - you must have already\n\
called socket.listen(). Only L2CAP and RFCOMM sockets are supported.\n\
\n\
name is the name that you want to appear in the SDP record\n\
\n\
Registered services will be automatically unregistered when the socket is\n\
closed.");
PyObject *
bt_sdp_stop_advertising( PyObject *self, PyObject *args )
{
PySocketSockObject *socko = NULL;
if ( !PyArg_ParseTuple(args, "O!", &sock_type, &socko ) ) {
return 0;
}
// verify that we got a real socket object
if( ! socko || (Py_TYPE(socko) != &sock_type) ) {
// TODO change this to a more accurate exception type
PyErr_SetString(bluetooth_error,
"must pass in _bluetooth.socket object");
return 0;
}
if( socko->sdp_session != NULL ) {
Py_BEGIN_ALLOW_THREADS
sdp_close( socko->sdp_session );
Py_END_ALLOW_THREADS
socko->sdp_session = NULL;
socko->sdp_record_handle = 0;
} else {
PyErr_SetString( bluetooth_error, "not currently advertising!");
}
Py_RETURN_NONE;
}
PyDoc_STRVAR( bt_sdp_stop_advertising_doc,
"sdp_stop_advertising( socket )\n\
\n\
Stop advertising services associated with this socket");
/* List of functions exported by this module. */
#define DECL_BT_METHOD(name, argtype) \
{ #name, (PyCFunction)bt_ ##name, argtype, bt_ ## name ## _doc }
static PyMethodDef bt_methods[] = {
DECL_BT_METHOD( hci_devid, METH_VARARGS ),
DECL_BT_METHOD( hci_get_route, METH_VARARGS ),
DECL_BT_METHOD( hci_role, METH_VARARGS ),
DECL_BT_METHOD( hci_read_clock, METH_VARARGS ),
DECL_BT_METHOD( hci_acl_conn_handle, METH_VARARGS ),
DECL_BT_METHOD( hci_open_dev, METH_VARARGS ),
DECL_BT_METHOD( hci_close_dev, METH_VARARGS ),
DECL_BT_METHOD( hci_send_cmd, METH_VARARGS ),
DECL_BT_METHOD( hci_send_req, METH_VARARGS | METH_KEYWORDS ),
DECL_BT_METHOD( hci_inquiry, METH_VARARGS | METH_KEYWORDS ),
DECL_BT_METHOD( hci_read_remote_name, METH_VARARGS | METH_KEYWORDS ),
DECL_BT_METHOD( hci_filter_new, METH_VARARGS ),
DECL_BT_METHOD( hci_filter_clear, METH_VARARGS ),
DECL_BT_METHOD( hci_filter_all_events, METH_VARARGS ),
DECL_BT_METHOD( hci_filter_all_ptypes, METH_VARARGS ),
DECL_BT_METHOD( hci_filter_clear_opcode, METH_VARARGS ),
DECL_BT_METHOD( hci_filter_set_ptype, METH_VARARGS ),
DECL_BT_METHOD( hci_filter_clear_ptype, METH_VARARGS ),
DECL_BT_METHOD( hci_filter_test_ptype, METH_VARARGS ),
DECL_BT_METHOD( hci_filter_set_event, METH_VARARGS ),
DECL_BT_METHOD( hci_filter_clear_event, METH_VARARGS ),
DECL_BT_METHOD( hci_filter_test_event, METH_VARARGS ),
DECL_BT_METHOD( hci_filter_set_opcode, METH_VARARGS ),
DECL_BT_METHOD( hci_filter_test_opcode, METH_VARARGS ),
DECL_BT_METHOD( cmd_opcode_pack, METH_VARARGS ),
DECL_BT_METHOD( cmd_opcode_ogf, METH_VARARGS ),
DECL_BT_METHOD( cmd_opcode_ocf, METH_VARARGS ),
DECL_BT_METHOD( ba2str, METH_VARARGS ),
DECL_BT_METHOD( str2ba, METH_VARARGS ),
DECL_BT_METHOD( hci_opcode_name, METH_VARARGS),
DECL_BT_METHOD( hci_event_name, METH_VARARGS),
#ifndef NO_DUP
DECL_BT_METHOD( fromfd, METH_VARARGS ),
#endif
DECL_BT_METHOD( btohs, METH_VARARGS ),
DECL_BT_METHOD( btohl, METH_VARARGS ),
DECL_BT_METHOD( htobs, METH_VARARGS ),
DECL_BT_METHOD( htobl, METH_VARARGS ),
DECL_BT_METHOD( getdefaulttimeout, METH_NOARGS ),
DECL_BT_METHOD( setdefaulttimeout, METH_O ),
DECL_BT_METHOD( sdp_advertise_service, METH_VARARGS ),
DECL_BT_METHOD( sdp_stop_advertising, METH_VARARGS ),
// DECL_BT_METHOD( advertise_service, METH_VARARGS | METH_KEYWORDS ),
{NULL, NULL} /* Sentinel */
};
#undef DECL_BT_METHOD
/* Initialize the bt module.
*/
PyDoc_STRVAR(socket_doc,
"Implementation module for bluetooth operations.\n\
\n\
See the bluetooth module for documentation.");
#if PY_MAJOR_VERSION >= 3
#define INITERROR return NULL
static struct PyModuleDef moduledef = {
PyModuleDef_HEAD_INIT,
"_bluetooth",
socket_doc,
-1,
bt_methods,
NULL,
NULL,
NULL,
NULL
};
PyMODINIT_FUNC
PyInit__bluetooth(void)
#else
#define INITERROR return
PyMODINIT_FUNC
init_bluetooth(void)
#endif
{
Py_TYPE(&sock_type) = &PyType_Type;
Py_TYPE(&sdp_session_type) = &PyType_Type;
#if PY_MAJOR_VERSION >= 3
PyObject *m = PyModule_Create(&moduledef);
#else
PyObject *m = Py_InitModule3("_bluetooth", bt_methods, socket_doc);
#endif
if (m == NULL)
INITERROR;
bluetooth_error = PyErr_NewException("_bluetooth.error", NULL, NULL);
if (bluetooth_error == NULL)
INITERROR;
Py_INCREF(bluetooth_error);
PyModule_AddObject(m, "error", bluetooth_error);
socket_timeout = PyErr_NewException("_bluetooth.timeout", bluetooth_error,
NULL);
if (socket_timeout == NULL)
INITERROR;
Py_INCREF(socket_timeout);
PyModule_AddObject(m, "timeout", socket_timeout);
Py_INCREF((PyObject *)&sock_type);
if (PyModule_AddObject(m, "btsocket", (PyObject *)&sock_type) != 0)
INITERROR;
Py_INCREF((PyObject *)&sdp_session_type);
if (PyModule_AddObject(m, "SDPSession", (PyObject *)&sdp_session_type) != 0)
INITERROR;
// Global variables that can be accessible from Python.
// PyModule_AddIntMacro(m, PF_BLUETOOTH);
// PyModule_AddIntMacro(m, AF_BLUETOOTH);
PyModule_AddIntMacro(m, SOL_HCI);
PyModule_AddIntMacro(m, HCI_DATA_DIR);
PyModule_AddIntMacro(m, HCI_TIME_STAMP);
PyModule_AddIntMacro(m, HCI_FILTER);
PyModule_AddIntMacro(m, HCI_MAX_EVENT_SIZE);
PyModule_AddIntMacro(m, HCI_EVENT_HDR_SIZE);
PyModule_AddIntConstant(m, "HCI", BTPROTO_HCI);
PyModule_AddIntConstant(m, "L2CAP", BTPROTO_L2CAP);
PyModule_AddIntConstant(m, "RFCOMM", BTPROTO_RFCOMM);
PyModule_AddIntConstant(m, "SCO", BTPROTO_SCO);
// /* Socket types */
// PyModule_AddIntMacro(m, SOCK_STREAM);
// PyModule_AddIntMacro(m, SOCK_DGRAM);
// PyModule_AddIntMacro(m, SOCK_RAW);
// PyModule_AddIntMacro(m, SOCK_SEQPACKET);
/* HCI Constants */
/* HCI OGF values */
#ifdef OGF_LINK_CTL
PyModule_AddIntMacro(m, OGF_LINK_CTL);
#endif
#ifdef OGF_LINK_POLICY
PyModule_AddIntMacro(m, OGF_LINK_POLICY);
#endif
#ifdef OGF_HOST_CTL
PyModule_AddIntMacro(m, OGF_HOST_CTL);
#endif
#ifdef OGF_INFO_PARAM
PyModule_AddIntMacro(m, OGF_INFO_PARAM);
#endif
#ifdef OGF_STATUS_PARAM
PyModule_AddIntMacro(m, OGF_STATUS_PARAM);
#endif
#ifdef OGF_TESTING_CMD
PyModule_AddIntMacro(m, OGF_TESTING_CMD);
#endif
#ifdef OGF_VENDOR_CMD
PyModule_AddIntMacro(m, OGF_VENDOR_CMD);
#endif
/* HCI OCF values */
#ifdef OCF_INQUIRY
PyModule_AddIntMacro(m, OCF_INQUIRY);
#endif
#ifdef OCF_INQUIRY_CANCEL
PyModule_AddIntMacro(m, OCF_INQUIRY_CANCEL);
#endif
#ifdef OCF_PERIODIC_INQUIRY
PyModule_AddIntMacro(m, OCF_PERIODIC_INQUIRY);
#endif
#ifdef OCF_EXIT_PERIODIC_INQUIRY
PyModule_AddIntMacro(m, OCF_EXIT_PERIODIC_INQUIRY);
#endif
#ifdef OCF_CREATE_CONN
PyModule_AddIntMacro(m, OCF_CREATE_CONN);
#endif
#ifdef CREATE_CONN_CP_SIZE
PyModule_AddIntMacro(m, CREATE_CONN_CP_SIZE);
#endif
#ifdef ACL_PTYPE_MASK
PyModule_AddIntMacro(m, ACL_PTYPE_MASK);
#endif
#ifdef OCF_DISCONNECT
PyModule_AddIntMacro(m, OCF_DISCONNECT);
#endif
#ifdef OCF_ADD_SCO
PyModule_AddIntMacro(m, OCF_ADD_SCO);
#endif
#ifdef OCF_ACCEPT_CONN_REQ
PyModule_AddIntMacro(m, OCF_ACCEPT_CONN_REQ);
#endif
#ifdef OCF_REJECT_CONN_REQ
PyModule_AddIntMacro(m, OCF_REJECT_CONN_REQ);
#endif
#ifdef OCF_LINK_KEY_REPLY
PyModule_AddIntMacro(m, OCF_LINK_KEY_REPLY);
#endif
#ifdef OCF_LINK_KEY_NEG_REPLY
PyModule_AddIntMacro(m, OCF_LINK_KEY_NEG_REPLY);
#endif
#ifdef OCF_PIN_CODE_REPLY
PyModule_AddIntMacro(m, OCF_PIN_CODE_REPLY);
#endif
#ifdef OCF_PIN_CODE_NEG_REPLY
PyModule_AddIntMacro(m, OCF_PIN_CODE_NEG_REPLY);
#endif
#ifdef OCF_SET_CONN_PTYPE
PyModule_AddIntMacro(m, OCF_SET_CONN_PTYPE);
#endif
#ifdef OCF_AUTH_REQUESTED
PyModule_AddIntMacro(m, OCF_AUTH_REQUESTED);
#endif
#ifdef OCF_SET_CONN_ENCRYPT
PyModule_AddIntMacro(m, OCF_SET_CONN_ENCRYPT);
#endif
#ifdef OCF_REMOTE_NAME_REQ
PyModule_AddIntMacro(m, OCF_REMOTE_NAME_REQ);
#endif
#ifdef OCF_READ_REMOTE_FEATURES
PyModule_AddIntMacro(m, OCF_READ_REMOTE_FEATURES);
#endif
#ifdef OCF_READ_REMOTE_EXT_FEATURES
PyModule_AddIntMacro(m, OCF_READ_REMOTE_EXT_FEATURES);
#endif
#ifdef OCF_READ_REMOTE_VERSION
PyModule_AddIntMacro(m, OCF_READ_REMOTE_VERSION);
#endif
#ifdef OCF_READ_CLOCK_OFFSET
PyModule_AddIntMacro(m, OCF_READ_CLOCK_OFFSET);
#endif
#ifdef OCF_READ_CLOCK_OFFSET
PyModule_AddIntMacro(m, OCF_READ_CLOCK);
#endif
#ifdef OCF_IO_CAPABILITY_REPLY
PyModule_AddIntMacro(m, OCF_IO_CAPABILITY_REPLY);
#endif
#ifdef OCF_USER_CONFIRM_REPLY
PyModule_AddIntMacro(m, OCF_USER_CONFIRM_REPLY);
#endif
#ifdef OCF_HOLD_MODE
PyModule_AddIntMacro(m, OCF_HOLD_MODE);
#endif
#ifdef OCF_SNIFF_MODE
PyModule_AddIntMacro(m, OCF_SNIFF_MODE);
#endif
#ifdef OCF_EXIT_SNIFF_MODE
PyModule_AddIntMacro(m, OCF_EXIT_SNIFF_MODE);
#endif
#ifdef OCF_PARK_MODE
PyModule_AddIntMacro(m, OCF_PARK_MODE);
#endif
#ifdef OCF_EXIT_PARK_MODE
PyModule_AddIntMacro(m, OCF_EXIT_PARK_MODE);
#endif
#ifdef OCF_QOS_SETUP
PyModule_AddIntMacro(m, OCF_QOS_SETUP);
#endif
#ifdef OCF_ROLE_DISCOVERY
PyModule_AddIntMacro(m, OCF_ROLE_DISCOVERY);
#endif
#ifdef OCF_SWITCH_ROLE
PyModule_AddIntMacro(m, OCF_SWITCH_ROLE);
#endif
#ifdef OCF_READ_LINK_POLICY
PyModule_AddIntMacro(m, OCF_READ_LINK_POLICY);
#endif
#ifdef OCF_WRITE_LINK_POLICY
PyModule_AddIntMacro(m, OCF_WRITE_LINK_POLICY);
#endif
#ifdef OCF_RESET
PyModule_AddIntMacro(m, OCF_RESET);
#endif
#ifdef OCF_SET_EVENT_MASK
PyModule_AddIntMacro(m, OCF_SET_EVENT_MASK);
#endif
#ifdef OCF_SET_EVENT_FLT
PyModule_AddIntMacro(m, OCF_SET_EVENT_FLT);
#endif
#ifdef OCF_CHANGE_LOCAL_NAME
PyModule_AddIntMacro(m, OCF_CHANGE_LOCAL_NAME);
#endif
#ifdef OCF_READ_LOCAL_NAME
PyModule_AddIntMacro(m, OCF_READ_LOCAL_NAME);
#endif
#ifdef OCF_WRITE_CA_TIMEOUT
PyModule_AddIntMacro(m, OCF_WRITE_CA_TIMEOUT);
#endif
#ifdef OCF_WRITE_PG_TIMEOUT
PyModule_AddIntMacro(m, OCF_WRITE_PG_TIMEOUT);
#endif
#ifdef OCF_READ_PAGE_TIMEOUT
PyModule_AddIntMacro(m, OCF_READ_PAGE_TIMEOUT);
#endif
#ifdef OCF_WRITE_PAGE_TIMEOUT
PyModule_AddIntMacro(m, OCF_WRITE_PAGE_TIMEOUT);
#endif
#ifdef OCF_READ_SCAN_ENABLE
PyModule_AddIntMacro(m, OCF_READ_SCAN_ENABLE);
#endif
#ifdef OCF_WRITE_SCAN_ENABLE
PyModule_AddIntMacro(m, OCF_WRITE_SCAN_ENABLE);
#endif
#ifdef OCF_READ_PAGE_ACTIVITY
PyModule_AddIntMacro(m, OCF_READ_PAGE_ACTIVITY);
#endif
#ifdef OCF_WRITE_PAGE_ACTIVITY
PyModule_AddIntMacro(m, OCF_WRITE_PAGE_ACTIVITY);
#endif
#ifdef OCF_READ_INQ_ACTIVITY
PyModule_AddIntMacro(m, OCF_READ_INQ_ACTIVITY);
#endif
#ifdef OCF_WRITE_INQ_ACTIVITY
PyModule_AddIntMacro(m, OCF_WRITE_INQ_ACTIVITY);
#endif
#ifdef OCF_READ_AUTH_ENABLE
PyModule_AddIntMacro(m, OCF_READ_AUTH_ENABLE);
#endif
#ifdef OCF_WRITE_AUTH_ENABLE
PyModule_AddIntMacro(m, OCF_WRITE_AUTH_ENABLE);
#endif
#ifdef OCF_READ_ENCRYPT_MODE
PyModule_AddIntMacro(m, OCF_READ_ENCRYPT_MODE);
#endif
#ifdef OCF_WRITE_ENCRYPT_MODE
PyModule_AddIntMacro(m, OCF_WRITE_ENCRYPT_MODE);
#endif
#ifdef OCF_READ_CLASS_OF_DEV
PyModule_AddIntMacro(m, OCF_READ_CLASS_OF_DEV);
#endif
#ifdef OCF_WRITE_CLASS_OF_DEV
PyModule_AddIntMacro(m, OCF_WRITE_CLASS_OF_DEV);
#endif
#ifdef OCF_READ_VOICE_SETTING
PyModule_AddIntMacro(m, OCF_READ_VOICE_SETTING);
#endif
#ifdef OCF_WRITE_VOICE_SETTING
PyModule_AddIntMacro(m, OCF_WRITE_VOICE_SETTING);
#endif
#ifdef OCF_READ_TRANSMIT_POWER_LEVEL
PyModule_AddIntMacro(m, OCF_READ_TRANSMIT_POWER_LEVEL);
#endif
#ifdef OCF_HOST_BUFFER_SIZE
PyModule_AddIntMacro(m, OCF_HOST_BUFFER_SIZE);
#endif
#ifdef OCF_READ_LINK_SUPERVISION_TIMEOUT
PyModule_AddIntMacro(m, OCF_READ_LINK_SUPERVISION_TIMEOUT);
#endif
#ifdef OCF_WRITE_LINK_SUPERVISION_TIMEOUT
PyModule_AddIntMacro(m, OCF_WRITE_LINK_SUPERVISION_TIMEOUT);
#endif
#ifdef OCF_READ_CURRENT_IAC_LAP
PyModule_AddIntMacro(m, OCF_READ_CURRENT_IAC_LAP);
#endif
#ifdef OCF_WRITE_CURRENT_IAC_LAP
PyModule_AddIntMacro(m, OCF_WRITE_CURRENT_IAC_LAP);
#endif
#ifdef OCF_READ_INQUIRY_MODE
PyModule_AddIntMacro(m, OCF_READ_INQUIRY_MODE);
#endif
#ifdef OCF_WRITE_INQUIRY_MODE
PyModule_AddIntMacro(m, OCF_WRITE_INQUIRY_MODE);
#endif
#ifdef OCF_READ_AFH_MODE
PyModule_AddIntMacro(m, OCF_READ_AFH_MODE);
#endif
#ifdef OCF_WRITE_AFH_MODE
PyModule_AddIntMacro(m, OCF_WRITE_AFH_MODE);
#endif
#ifdef OCF_WRITE_EXT_INQUIRY_RESPONSE
PyModule_AddIntMacro(m, OCF_WRITE_EXT_INQUIRY_RESPONSE);
#endif
#ifdef OCF_WRITE_SIMPLE_PAIRING_MODE
PyModule_AddIntMacro(m, OCF_WRITE_SIMPLE_PAIRING_MODE);
#endif
#ifdef OCF_READ_LOCAL_VERSION
PyModule_AddIntMacro(m, OCF_READ_LOCAL_VERSION);
#endif
#ifdef OCF_READ_LOCAL_FEATURES
PyModule_AddIntMacro(m, OCF_READ_LOCAL_FEATURES);
#endif
#ifdef OCF_READ_BUFFER_SIZE
PyModule_AddIntMacro(m, OCF_READ_BUFFER_SIZE);
#endif
#ifdef OCF_READ_BD_ADDR
PyModule_AddIntMacro(m, OCF_READ_BD_ADDR);
#endif
#ifdef OCF_READ_FAILED_CONTACT_COUNTER
PyModule_AddIntMacro(m, OCF_READ_FAILED_CONTACT_COUNTER);
#endif
#ifdef OCF_RESET_FAILED_CONTACT_COUNTER
PyModule_AddIntMacro(m, OCF_RESET_FAILED_CONTACT_COUNTER);
#endif
#ifdef OCF_GET_LINK_QUALITY
PyModule_AddIntMacro(m, OCF_GET_LINK_QUALITY);
#endif
#ifdef OCF_READ_RSSI
PyModule_AddIntMacro(m, OCF_READ_RSSI);
#endif
#ifdef OCF_READ_AFH_MAP
PyModule_AddIntMacro(m, OCF_READ_AFH_MAP);
#endif
/* HCI events */
#ifdef EVT_INQUIRY_COMPLETE
PyModule_AddIntMacro(m, EVT_INQUIRY_COMPLETE);
#endif
#ifdef EVT_INQUIRY_RESULT
PyModule_AddIntMacro(m, EVT_INQUIRY_RESULT);
#endif
#ifdef EVT_CONN_COMPLETE
PyModule_AddIntMacro(m, EVT_CONN_COMPLETE);
#endif
#ifdef EVT_CONN_COMPLETE_SIZE
PyModule_AddIntMacro(m, EVT_CONN_COMPLETE_SIZE);
#endif
#ifdef EVT_CONN_REQUEST
PyModule_AddIntMacro(m, EVT_CONN_REQUEST);
#endif
#ifdef EVT_CONN_REQUEST_SIZE
PyModule_AddIntMacro(m, EVT_CONN_REQUEST_SIZE);
#endif
#ifdef EVT_DISCONN_COMPLETE
PyModule_AddIntMacro(m, EVT_DISCONN_COMPLETE);
#endif
#ifdef EVT_DISCONN_COMPLETE_SIZE
PyModule_AddIntMacro(m, EVT_DISCONN_COMPLETE_SIZE);
#endif
#ifdef EVT_AUTH_COMPLETE
PyModule_AddIntMacro(m, EVT_AUTH_COMPLETE);
#endif
#ifdef EVT_AUTH_COMPLETE_SIZE
PyModule_AddIntMacro(m, EVT_AUTH_COMPLETE_SIZE);
#endif
#ifdef EVT_REMOTE_NAME_REQ_COMPLETE
PyModule_AddIntMacro(m, EVT_REMOTE_NAME_REQ_COMPLETE);
#endif
#ifdef EVT_REMOTE_NAME_REQ_COMPLETE_SIZE
PyModule_AddIntMacro(m, EVT_REMOTE_NAME_REQ_COMPLETE_SIZE);
#endif
#ifdef EVT_ENCRYPT_CHANGE
PyModule_AddIntMacro(m, EVT_ENCRYPT_CHANGE);
#endif
#ifdef EVT_ENCRYPT_CHANGE_SIZE
PyModule_AddIntMacro(m, EVT_ENCRYPT_CHANGE_SIZE);
#endif
#ifdef EVT_READ_REMOTE_FEATURES_COMPLETE
PyModule_AddIntMacro(m, EVT_READ_REMOTE_FEATURES_COMPLETE);
#endif
#ifdef EVT_READ_REMOTE_FEATURES_COMPLETE_SIZE
PyModule_AddIntMacro(m, EVT_READ_REMOTE_FEATURES_COMPLETE_SIZE);
#endif
#ifdef EVT_READ_REMOTE_VERSION_COMPLETE
PyModule_AddIntMacro(m, EVT_READ_REMOTE_VERSION_COMPLETE);
#endif
#ifdef EVT_READ_REMOTE_VERSION_COMPLETE_SIZE
PyModule_AddIntMacro(m, EVT_READ_REMOTE_VERSION_COMPLETE_SIZE);
#endif
#ifdef EVT_QOS_SETUP_COMPLETE
PyModule_AddIntMacro(m, EVT_QOS_SETUP_COMPLETE);
#endif
#ifdef EVT_QOS_SETUP_COMPLETE_SIZE
PyModule_AddIntMacro(m, EVT_QOS_SETUP_COMPLETE_SIZE);
#endif
#ifdef EVT_CMD_COMPLETE
PyModule_AddIntMacro(m, EVT_CMD_COMPLETE);
#endif
#ifdef EVT_CMD_COMPLETE_SIZE
PyModule_AddIntMacro(m, EVT_CMD_COMPLETE_SIZE);
#endif
#ifdef EVT_CMD_STATUS
PyModule_AddIntMacro(m, EVT_CMD_STATUS);
#endif
#ifdef EVT_CMD_STATUS_SIZE
PyModule_AddIntMacro(m, EVT_CMD_STATUS_SIZE);
#endif
#ifdef EVT_ROLE_CHANGE
PyModule_AddIntMacro(m, EVT_ROLE_CHANGE);
#endif
#ifdef EVT_ROLE_CHANGE_SIZE
PyModule_AddIntMacro(m, EVT_ROLE_CHANGE_SIZE);
#endif
#ifdef EVT_NUM_COMP_PKTS
PyModule_AddIntMacro(m, EVT_NUM_COMP_PKTS);
#endif
#ifdef EVT_NUM_COMP_PKTS_SIZE
PyModule_AddIntMacro(m, EVT_NUM_COMP_PKTS_SIZE);
#endif
#ifdef EVT_MODE_CHANGE
PyModule_AddIntMacro(m, EVT_MODE_CHANGE);
#endif
#ifdef EVT_MODE_CHANGE_SIZE
PyModule_AddIntMacro(m, EVT_MODE_CHANGE_SIZE);
#endif
#ifdef EVT_PIN_CODE_REQ
PyModule_AddIntMacro(m, EVT_PIN_CODE_REQ);
#endif
#ifdef EVT_PIN_CODE_REQ_SIZE
PyModule_AddIntMacro(m, EVT_PIN_CODE_REQ_SIZE);
#endif
#ifdef EVT_LINK_KEY_REQ
PyModule_AddIntMacro(m, EVT_LINK_KEY_REQ);
#endif
#ifdef EVT_LINK_KEY_REQ_SIZE
PyModule_AddIntMacro(m, EVT_LINK_KEY_REQ_SIZE);
#endif
#ifdef EVT_LINK_KEY_NOTIFY
PyModule_AddIntMacro(m, EVT_LINK_KEY_NOTIFY);
#endif
#ifdef EVT_LINK_KEY_NOTIFY_SIZE
PyModule_AddIntMacro(m, EVT_LINK_KEY_NOTIFY_SIZE);
#endif
#ifdef EVT_MAX_SLOTS_CHANGE
PyModule_AddIntMacro(m, EVT_MAX_SLOTS_CHANGE);
#endif
#ifdef EVT_READ_CLOCK_OFFSET_COMPLETE
PyModule_AddIntMacro(m, EVT_READ_CLOCK_OFFSET_COMPLETE);
#endif
#ifdef EVT_READ_CLOCK_OFFSET_COMPLETE_SIZE
PyModule_AddIntMacro(m, EVT_READ_CLOCK_OFFSET_COMPLETE_SIZE);
#endif
#ifdef EVT_CONN_PTYPE_CHANGED
PyModule_AddIntMacro(m, EVT_CONN_PTYPE_CHANGED);
#endif
#ifdef EVT_CONN_PTYPE_CHANGED_SIZE
PyModule_AddIntMacro(m, EVT_CONN_PTYPE_CHANGED_SIZE);
#endif
#ifdef EVT_QOS_VIOLATION
PyModule_AddIntMacro(m, EVT_QOS_VIOLATION);
#endif
#ifdef EVT_QOS_VIOLATION_SIZE
PyModule_AddIntMacro(m, EVT_QOS_VIOLATION_SIZE);
#endif
#ifdef EVT_PSCAN_REP_MODE_CHANGE
PyModule_AddIntMacro(m,EVT_PSCAN_REP_MODE_CHANGE);
#endif
#ifdef EVT_FLOW_SPEC_COMPLETE
PyModule_AddIntMacro(m,EVT_FLOW_SPEC_COMPLETE);
#endif
#ifdef EVT_FLOW_SPEC_MODIFY_COMPLETE
PyModule_AddIntMacro(m,EVT_FLOW_SPEC_MODIFY_COMPLETE);
#endif
#ifdef EVT_INQUIRY_RESULT_WITH_RSSI
PyModule_AddIntMacro(m, EVT_INQUIRY_RESULT_WITH_RSSI);
#endif
#ifdef EVT_READ_REMOTE_EXT_FEATURES_COMPLETE
PyModule_AddIntMacro(m, EVT_READ_REMOTE_EXT_FEATURES_COMPLETE);
#endif
#ifdef EVT_EXTENDED_INQUIRY_RESULT
PyModule_AddIntMacro(m, EVT_EXTENDED_INQUIRY_RESULT);
PyModule_AddIntConstant(m, "HAVE_EVT_EXTENDED_INQUIRY_RESULT", 1);
#else
PyModule_AddIntConstant(m, "HAVE_EVT_EXTENDED_INQUIRY_RESULT", 0);
#endif
#ifdef EVT_DISCONNECT_LOGICAL_LINK_COMPLETE
PyModule_AddIntMacro(m, EVT_DISCONNECT_LOGICAL_LINK_COMPLETE);
#endif
#ifdef EVT_IO_CAPABILITY_REQUEST
PyModule_AddIntMacro(m, EVT_IO_CAPABILITY_REQUEST);
#endif
#ifdef EVT_IO_CAPABILITY_RESPONSE
PyModule_AddIntMacro(m, EVT_IO_CAPABILITY_RESPONSE);
#endif
#ifdef EVT_USER_CONFIRM_REQUEST
PyModule_AddIntMacro(m, EVT_USER_CONFIRM_REQUEST);
#endif
#ifdef EVT_SIMPLE_PAIRING_COMPLETE
PyModule_AddIntMacro(m, EVT_SIMPLE_PAIRING_COMPLETE);
#endif
#ifdef EVT_TESTING
PyModule_AddIntMacro(m, EVT_TESTING);
#endif
#ifdef EVT_VENDOR
PyModule_AddIntMacro(m, EVT_VENDOR);
#endif
#ifdef EVT_STACK_INTERNAL
PyModule_AddIntMacro(m, EVT_STACK_INTERNAL);
#endif
#ifdef EVT_STACK_INTERNAL_SIZE
PyModule_AddIntMacro(m, EVT_STACK_INTERNAL_SIZE);
#endif
#ifdef EVT_SI_DEVICE
PyModule_AddIntMacro(m, EVT_SI_DEVICE);
#endif
#ifdef EVT_SI_DEVICE_SIZE
PyModule_AddIntMacro(m, EVT_SI_DEVICE_SIZE);
#endif
#ifdef EVT_SI_SECURITY
PyModule_AddIntMacro(m, EVT_SI_SECURITY);
#endif
#ifdef EVT_NUMBER_COMPLETED_BLOCKS
PyModule_AddIntMacro(m, EVT_NUMBER_COMPLETED_BLOCKS);
#endif
/* HCI packet types */
#ifdef HCI_COMMAND_PKT
PyModule_AddIntMacro(m, HCI_COMMAND_PKT);
#endif
#ifdef HCI_ACLDATA_PKT
PyModule_AddIntMacro(m, HCI_ACLDATA_PKT);
#endif
#ifdef HCI_SCODATA_PKT
PyModule_AddIntMacro(m, HCI_SCODATA_PKT);
#endif
#ifdef HCI_EVENT_PKT
PyModule_AddIntMacro(m, HCI_EVENT_PKT);
#endif
#ifdef HCI_UNKNOWN_PKT
PyModule_AddIntMacro(m, HCI_UNKNOWN_PKT);
#endif
/* socket options */
#ifdef SO_DEBUG
PyModule_AddIntMacro(m, SO_DEBUG);
#endif
#ifdef SO_ACCEPTCONN
PyModule_AddIntMacro(m, SO_ACCEPTCONN);
#endif
#ifdef SO_REUSEADDR
PyModule_AddIntMacro(m, SO_REUSEADDR);
#endif
#ifdef SO_KEEPALIVE
PyModule_AddIntMacro(m, SO_KEEPALIVE);
#endif
#ifdef SO_DONTROUTE
PyModule_AddIntMacro(m, SO_DONTROUTE);
#endif
#ifdef SO_BROADCAST
PyModule_AddIntMacro(m, SO_BROADCAST);
#endif
#ifdef SO_USELOOPBACK
PyModule_AddIntMacro(m, SO_USELOOPBACK);
#endif
#ifdef SO_LINGER
PyModule_AddIntMacro(m, SO_LINGER);
#endif
#ifdef SO_OOBINLINE
PyModule_AddIntMacro(m, SO_OOBINLINE);
#endif
#ifdef SO_REUSEPORT
PyModule_AddIntMacro(m, SO_REUSEPORT);
#endif
#ifdef SO_SNDBUF
PyModule_AddIntMacro(m, SO_SNDBUF);
#endif
#ifdef SO_RCVBUF
PyModule_AddIntMacro(m, SO_RCVBUF);
#endif
#ifdef SO_SNDLOWAT
PyModule_AddIntMacro(m, SO_SNDLOWAT);
#endif
#ifdef SO_RCVLOWAT
PyModule_AddIntMacro(m, SO_RCVLOWAT);
#endif
#ifdef SO_SNDTIMEO
PyModule_AddIntMacro(m, SO_SNDTIMEO);
#endif
#ifdef SO_RCVTIMEO
PyModule_AddIntMacro(m, SO_RCVTIMEO);
#endif
#ifdef SO_ERROR
PyModule_AddIntMacro(m, SO_ERROR);
#endif
#ifdef SO_TYPE
PyModule_AddIntMacro(m, SO_TYPE);
#endif
/* Maximum number of connections for "listen" */
#ifdef SOMAXCONN
PyModule_AddIntMacro(m, SOMAXCONN);
#else
PyModule_AddIntMacro(m, SOMAXCONN);
#endif
/* Flags for send, recv */
#ifdef MSG_OOB
PyModule_AddIntMacro(m, MSG_OOB);
#endif
#ifdef MSG_PEEK
PyModule_AddIntMacro(m, MSG_PEEK);
#endif
#ifdef MSG_DONTROUTE
PyModule_AddIntMacro(m, MSG_DONTROUTE);
#endif
#ifdef MSG_DONTWAIT
PyModule_AddIntMacro(m, MSG_DONTWAIT);
#endif
#ifdef MSG_EOR
PyModule_AddIntMacro(m, MSG_EOR);
#endif
#ifdef MSG_TRUNC
PyModule_AddIntMacro(m, MSG_TRUNC);
#endif
#ifdef MSG_CTRUNC
PyModule_AddIntMacro(m, MSG_CTRUNC);
#endif
#ifdef MSG_WAITALL
PyModule_AddIntMacro(m, MSG_WAITALL);
#endif
#ifdef MSG_BTAG
PyModule_AddIntMacro(m, MSG_BTAG);
#endif
#ifdef MSG_ETAG
PyModule_AddIntMacro(m, MSG_ETAG);
#endif
/* Size of inquiry info */
#ifdef INQUIRY_INFO_WITH_RSSI_SIZE
PyModule_AddIntMacro(m, INQUIRY_INFO_WITH_RSSI_SIZE);
#endif
#ifdef EXTENDED_INQUIRY_INFO_SIZE
PyModule_AddIntMacro(m, EXTENDED_INQUIRY_INFO_SIZE);
#endif
/* Protocol level and numbers, usable for [gs]etsockopt */
PyModule_AddIntMacro(m, SOL_SOCKET);
PyModule_AddIntMacro(m, SOL_L2CAP);
PyModule_AddIntMacro(m, SOL_RFCOMM);
PyModule_AddIntMacro(m, SOL_SCO);
PyModule_AddIntMacro(m, SCO_OPTIONS);
PyModule_AddIntMacro(m, L2CAP_OPTIONS);
/* special channels to bind() */
PyModule_AddIntMacro(m, HCI_CHANNEL_CONTROL);
PyModule_AddIntMacro(m, HCI_CHANNEL_USER);
PyModule_AddIntMacro(m, HCI_DEV_NONE);
/* ioctl */
PyModule_AddIntMacro(m, HCIDEVUP);
PyModule_AddIntMacro(m, HCIDEVDOWN);
PyModule_AddIntMacro(m, HCIDEVRESET);
PyModule_AddIntMacro(m, HCIDEVRESTAT);
PyModule_AddIntMacro(m, HCIGETDEVLIST);
PyModule_AddIntMacro(m, HCIGETDEVINFO);
PyModule_AddIntMacro(m, HCIGETCONNLIST);
PyModule_AddIntMacro(m, HCIGETCONNINFO);
PyModule_AddIntMacro(m, HCISETRAW);
PyModule_AddIntMacro(m, HCISETSCAN);
PyModule_AddIntMacro(m, HCISETAUTH);
PyModule_AddIntMacro(m, HCISETENCRYPT);
PyModule_AddIntMacro(m, HCISETPTYPE);
PyModule_AddIntMacro(m, HCISETLINKPOL);
PyModule_AddIntMacro(m, HCISETLINKMODE);
PyModule_AddIntMacro(m, HCISETACLMTU);
PyModule_AddIntMacro(m, HCISETSCOMTU);
PyModule_AddIntMacro(m, HCIINQUIRY);
PyModule_AddIntMacro(m, ACL_LINK);
PyModule_AddIntMacro(m, SCO_LINK);
/* RFCOMM */
PyModule_AddIntMacro(m, RFCOMM_LM);
PyModule_AddIntMacro(m, RFCOMM_LM_MASTER);
PyModule_AddIntMacro(m, RFCOMM_LM_AUTH );
PyModule_AddIntMacro(m, RFCOMM_LM_ENCRYPT);
PyModule_AddIntMacro(m, RFCOMM_LM_TRUSTED);
PyModule_AddIntMacro(m, RFCOMM_LM_RELIABLE);
PyModule_AddIntMacro(m, RFCOMM_LM_SECURE);
/* L2CAP */
PyModule_AddIntMacro(m, L2CAP_LM);
PyModule_AddIntMacro(m, L2CAP_LM_MASTER);
PyModule_AddIntMacro(m, L2CAP_LM_AUTH);
PyModule_AddIntMacro(m, L2CAP_LM_ENCRYPT);
PyModule_AddIntMacro(m, L2CAP_LM_TRUSTED);
PyModule_AddIntMacro(m, L2CAP_LM_RELIABLE);
PyModule_AddIntMacro(m, L2CAP_LM_SECURE);
PyModule_AddIntMacro(m, L2CAP_COMMAND_REJ);
PyModule_AddIntMacro(m, L2CAP_CONN_REQ );
PyModule_AddIntMacro(m, L2CAP_CONN_RSP );
PyModule_AddIntMacro(m, L2CAP_CONF_REQ );
PyModule_AddIntMacro(m, L2CAP_CONF_RSP );
PyModule_AddIntMacro(m, L2CAP_DISCONN_REQ);
PyModule_AddIntMacro(m, L2CAP_DISCONN_RSP);
PyModule_AddIntMacro(m, L2CAP_ECHO_REQ );
PyModule_AddIntMacro(m, L2CAP_ECHO_RSP );
PyModule_AddIntMacro(m, L2CAP_INFO_REQ );
PyModule_AddIntMacro(m, L2CAP_INFO_RSP );
PyModule_AddIntMacro(m, L2CAP_MODE_BASIC);
PyModule_AddIntMacro(m, L2CAP_MODE_RETRANS);
PyModule_AddIntMacro(m, L2CAP_MODE_FLOWCTL);
PyModule_AddIntMacro(m, L2CAP_MODE_ERTM);
PyModule_AddIntMacro(m, L2CAP_MODE_STREAMING);
PyModule_AddIntMacro(m, BT_SECURITY);
PyModule_AddIntMacro(m, BT_SECURITY_SDP);
PyModule_AddIntMacro(m, BT_SECURITY_LOW);
PyModule_AddIntMacro(m, BT_SECURITY_MEDIUM);
PyModule_AddIntMacro(m, BT_SECURITY_HIGH);
#ifdef BT_DEFER_SETUP
PyModule_AddIntMacro(m, BT_DEFER_SETUP);
#endif
PyModule_AddIntMacro(m, SOL_BLUETOOTH);
#if PY_MAJOR_VERSION >= 3
return m;
#endif
}
/*
* Affix socket module
* Socket module for python based in the original socket module for python
* This code is a copy from socket.c source code from python2.2 with
* updates/modifications to support affix socket interface *
* AAA FFFFFFF FFFFFFF IIIIIII X X
* A A F F I X X
* A A F F I X X
* AAAAAAA FFFF FFFF I X X
* A A F F I X X
* A A F F IIIIIII X X
*
* Any modifications of this sourcecode must keep this information !!!!!
*
* by Carlos Chinea
* (C) Nokia Research Center, 2004
*/
static char *event_str[EVENT_NUM + 1] = {
"Unknown",
"Inquiry Complete",
"Inquiry Result",
"Connect Complete",
"Connect Request",
"Disconn Complete",
"Auth Complete",
"Remote Name Req Complete",
"Encrypt Change",
"Change Connection Link Key Complete",
"Master Link Key Complete",
"Read Remote Supported Features",
"Read Remote Ver Info Complete",
"QoS Setup Complete",
"Command Complete",
"Command Status",
"Hardware Error",
"Flush Occurred",
"Role Change",
"Number of Completed Packets",
"Mode Change",
"Return Link Keys",
"PIN Code Request",
"Link Key Request",
"Link Key Notification",
"Loopback Command",
"Data Buffer Overflow",
"Max Slots Change",
"Read Clock Offset Complete",
"Connection Packet Type Changed",
"QoS Violation",
"Page Scan Mode Change",
"Page Scan Repetition Mode Change",
"Flow Specification Complete",
"Inquiry Result with RSSI",
"Read Remote Extended Features",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Synchronous Connect Complete",
"Synchronous Connect Changed",
"Sniff Subrate",
"Extended Inquiry Result",
"Encryption Key Refresh Complete",
"IO Capability Request",
"IO Capability Response",
"User Confirmation Request",
"User Passkey Request",
"Remote OOB Data Request",
"Simple Pairing Complete",
"Unknown",
"Link Supervision Timeout Change",
"Enhanced Flush Complete",
"Unknown",
"User Passkey Notification",
"Keypress Notification",
"Remote Host Supported Features Notification",
"LE Meta Event",
"Unknown",
"Physical Link Complete",
"Channel Selected",
"Disconnection Physical Link Complete",
"Physical Link Loss Early Warning",
"Physical Link Recovery",
"Logical Link Complete",
"Disconnection Logical Link Complete",
"Flow Spec Modify Complete",
"Number Of Completed Data Blocks",
"AMP Start Test",
"AMP Test End",
"AMP Receiver Report",
"Short Range Mode Change Complete",
"AMP Status Change",
};
#define CMD_LINKCTL_NUM 60
static char *cmd_linkctl_str[CMD_LINKCTL_NUM + 1] = {
"Unknown",
"Inquiry",
"Inquiry Cancel",
"Periodic Inquiry Mode",
"Exit Periodic Inquiry Mode",
"Create Connection",
"Disconnect",
"Add SCO Connection",
"Create Connection Cancel",
"Accept Connection Request",
"Reject Connection Request",
"Link Key Request Reply",
"Link Key Request Negative Reply",
"PIN Code Request Reply",
"PIN Code Request Negative Reply",
"Change Connection Packet Type",
"Unknown",
"Authentication Requested",
"Unknown",
"Set Connection Encryption",
"Unknown",
"Change Connection Link Key",
"Unknown",
"Master Link Key",
"Unknown",
"Remote Name Request",
"Remote Name Request Cancel",
"Read Remote Supported Features",
"Read Remote Extended Features",
"Read Remote Version Information",
"Unknown",
"Read Clock Offset",
"Read LMP Handle",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Setup Synchronous Connection",
"Accept Synchronous Connection",
"Reject Synchronous Connection",
"IO Capability Request Reply",
"User Confirmation Request Reply",
"User Confirmation Request Negative Reply",
"User Passkey Request Reply",
"User Passkey Request Negative Reply",
"Remote OOB Data Request Reply",
"Unknown",
"Unknown",
"Remote OOB Data Request Negative Reply",
"IO Capability Request Negative Reply",
"Create Physical Link",
"Accept Physical Link",
"Disconnect Physical Link",
"Create Logical Link",
"Accept Logical Link",
"Disconnect Logical Link",
"Logical Link Cancel",
"Flow Spec Modify",
};
#define CMD_LINKPOL_NUM 17
static char *cmd_linkpol_str[CMD_LINKPOL_NUM + 1] = {
"Unknown",
"Hold Mode",
"Unknown",
"Sniff Mode",
"Exit Sniff Mode",
"Park State",
"Exit Park State",
"QoS Setup",
"Unknown",
"Role Discovery",
"Unknown",
"Switch Role",
"Read Link Policy Settings",
"Write Link Policy Settings",
"Read Default Link Policy Settings",
"Write Default Link Policy Settings",
"Flow Specification",
"Sniff Subrating",
};
#define CMD_HOSTCTL_NUM 109
static char *cmd_hostctl_str[CMD_HOSTCTL_NUM + 1] = {
"Unknown",
"Set Event Mask",
"Unknown",
"Reset",
"Unknown",
"Set Event Filter",
"Unknown",
"Unknown",
"Flush",
"Read PIN Type ",
"Write PIN Type",
"Create New Unit Key",
"Unknown",
"Read Stored Link Key",
"Unknown",
"Unknown",
"Unknown",
"Write Stored Link Key",
"Delete Stored Link Key",
"Write Local Name",
"Read Local Name",
"Read Connection Accept Timeout",
"Write Connection Accept Timeout",
"Read Page Timeout",
"Write Page Timeout",
"Read Scan Enable",
"Write Scan Enable",
"Read Page Scan Activity",
"Write Page Scan Activity",
"Read Inquiry Scan Activity",
"Write Inquiry Scan Activity",
"Read Authentication Enable",
"Write Authentication Enable",
"Read Encryption Mode",
"Write Encryption Mode",
"Read Class of Device",
"Write Class of Device",
"Read Voice Setting",
"Write Voice Setting",
"Read Automatic Flush Timeout",
"Write Automatic Flush Timeout",
"Read Num Broadcast Retransmissions",
"Write Num Broadcast Retransmissions",
"Read Hold Mode Activity ",
"Write Hold Mode Activity",
"Read Transmit Power Level",
"Read Synchronous Flow Control Enable",
"Write Synchronous Flow Control Enable",
"Unknown",
"Set Host Controller To Host Flow Control",
"Unknown",
"Host Buffer Size",
"Unknown",
"Host Number of Completed Packets",
"Read Link Supervision Timeout",
"Write Link Supervision Timeout",
"Read Number of Supported IAC",
"Read Current IAC LAP",
"Write Current IAC LAP",
"Read Page Scan Period Mode",
"Write Page Scan Period Mode",
"Read Page Scan Mode",
"Write Page Scan Mode",
"Set AFH Host Channel Classification",
"Unknown",
"Unknown",
"Read Inquiry Scan Type",
"Write Inquiry Scan Type",
"Read Inquiry Mode",
"Write Inquiry Mode",
"Read Page Scan Type",
"Write Page Scan Type",
"Read AFH Channel Assessment Mode",
"Write AFH Channel Assessment Mode",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Unknown",
"Read Extended Inquiry Response",
"Write Extended Inquiry Response",
"Refresh Encryption Key",
"Unknown",
"Read Simple Pairing Mode",
"Write Simple Pairing Mode",
"Read Local OOB Data",
"Read Inquiry Response Transmit Power Level",
"Write Inquiry Transmit Power Level",
"Read Default Erroneous Data Reporting",
"Write Default Erroneous Data Reporting",
"Unknown",
"Unknown",
"Unknown",
"Enhanced Flush",
"Unknown",
"Read Logical Link Accept Timeout",
"Write Logical Link Accept Timeout",
"Set Event Mask Page 2",
"Read Location Data",
"Write Location Data",
"Read Flow Control Mode",
"Write Flow Control Mode",
"Read Enhanced Transmit Power Level",
"Read Best Effort Flush Timeout",
"Write Best Effort Flush Timeout",
"Short Range Mode",
"Read LE Host Supported",
"Write LE Host Supported",
};
#define CMD_INFO_NUM 10
static char *cmd_info_str[CMD_INFO_NUM + 1] = {
"Unknown",
"Read Local Version Information",
"Read Local Supported Commands",
"Read Local Supported Features",
"Read Local Extended Features",
"Read Buffer Size",
"Unknown",
"Read Country Code",
"Unknown",
"Read BD ADDR",
"Read Data Block Size",
};
#define CMD_STATUS_NUM 11
static char *cmd_status_str[CMD_STATUS_NUM + 1] = {
"Unknown",
"Read Failed Contact Counter",
"Reset Failed Contact Counter",
"Read Link Quality",
"Unknown",
"Read RSSI",
"Read AFH Channel Map",
"Read Clock",
"Read Encryption Key Size",
"Read Local AMP Info",
"Read Local AMP ASSOC",
"Write Remote AMP ASSOC"
};
#define CMD_TESTING_NUM 4
static char *cmd_testing_str[CMD_TESTING_NUM + 1] = {
"Unknown",
"Read Loopback Mode",
"Write Loopback Mode",
"Enable Device Under Test mode",
"Unknown",
};
#define CMD_LE_NUM 31
static char *cmd_le_str[CMD_LE_NUM + 1] = {
"Unknown",
"LE Set Event Mask",
"LE Read Buffer Size",
"LE Read Local Supported Features",
"Unknown",
"LE Set Random Address",
"LE Set Advertising Parameters",
"LE Read Advertising Channel Tx Power",
"LE Set Advertising Data",
"LE Set Scan Response Data",
"LE Set Advertise Enable",
"LE Set Scan Parameters",
"LE Set Scan Enable",
"LE Create Connection",
"LE Create Connection Cancel",
"LE Read White List Size",
"LE Clear White List",
"LE Add Device To White List",
"LE Remove Device From White List",
"LE Connection Update",
"LE Set Host Channel Classification",
"LE Read Channel Map",
"LE Read Remote Used Features",
"LE Encrypt",
"LE Rand",
"LE Start Encryption",
"LE Long Term Key Request Reply",
"LE Long Term Key Request Negative Reply",
"LE Read Supported States",
"LE Receiver Test",
"LE Transmitter Test",
"LE Test End",
};
static char *opcode2str(uint16_t opcode)
{
uint16_t ogf = cmd_opcode_ogf(opcode);
uint16_t ocf = cmd_opcode_ocf(opcode);
char *cmd;
switch (ogf) {
case OGF_INFO_PARAM:
if (ocf <= CMD_INFO_NUM)
cmd = cmd_info_str[ocf];
else
cmd = "Unknown";
break;
case OGF_HOST_CTL:
if (ocf <= CMD_HOSTCTL_NUM)
cmd = cmd_hostctl_str[ocf];
else
cmd = "Unknown";
break;
case OGF_LINK_CTL:
if (ocf <= CMD_LINKCTL_NUM)
cmd = cmd_linkctl_str[ocf];
else
cmd = "Unknown";
break;
case OGF_LINK_POLICY:
if (ocf <= CMD_LINKPOL_NUM)
cmd = cmd_linkpol_str[ocf];
else
cmd = "Unknown";
break;
case OGF_STATUS_PARAM:
if (ocf <= CMD_STATUS_NUM)
cmd = cmd_status_str[ocf];
else
cmd = "Unknown";
break;
case OGF_TESTING_CMD:
if (ocf <= CMD_TESTING_NUM)
cmd = cmd_testing_str[ocf];
else
cmd = "Unknown";
break;
case OGF_LE_CTL:
if (ocf <= CMD_LE_NUM)
cmd = cmd_le_str[ocf];
else
cmd = "Unknown";
break;
case OGF_VENDOR_CMD:
cmd = "Vendor";
break;
default:
cmd = "Unknown";
break;
}
return cmd;
}
pybluez-0.23/bluez/btmodule.h 0000664 0000000 0000000 00000002362 13601523637 0016246 0 ustar 00root root 0000000 0000000 #ifndef __btmodule_h__
#define __btmodule_h__
#include "Python.h"
#include
#include
#include
#include
#ifdef __cplusplus
extern "C" {
#endif
/* The object holding a socket. It holds some extra information,
like the address family, which is used to decode socket address
arguments properly. */
typedef struct {
PyObject_HEAD
int sock_fd; /* Socket file descriptor */
int sock_family; /* Address family, always AF_BLUETOOTH */
int sock_type; /* Socket type, e.g., SOCK_STREAM */
int sock_proto; /* Protocol type, e.g., BTPROTO_L2CAP */
PyObject *(*errorhandler)(void); /* Error handler; checks
errno, returns NULL and
sets a Python exception */
double sock_timeout; /* Operation timeout in seconds;
0.0 means non-blocking */
int is_listening_socket; // XXX this is a hack to make
// sdp_advertise_service easier
uint32_t sdp_record_handle; // if it's a listening socket and advertised
// via SDP, this is the SDP handle
sdp_session_t *sdp_session;
} PySocketSockObject;
#ifdef __cplusplus
}
#endif
extern PyObject *bluetooth_error;
#endif // __btmodule_h__
pybluez-0.23/bluez/btsdp.c 0000664 0000000 0000000 00000033146 13601523637 0015546 0 ustar 00root root 0000000 0000000 #include "Python.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "btmodule.h"
#include "btsdp.h"
extern PyTypeObject sock_type;
extern int getsockaddrlen(PySocketSockObject *s, socklen_t *len_ret);
extern PyObject *set_error(void);
extern int str2uuid( const char *uuid_str, uuid_t *uuid );
extern void uuid2str( const uuid_t *uuid, char *dest );
// =================== utility functions =====================
static void
dict_set_strings(PyObject *dict, const char *key, const char *val)
{
PyObject *valobj;
valobj = PyString_FromString( val );
PyDict_SetItemString( dict, key, valobj );
Py_DECREF( valobj );
}
static void
dict_set_str_long(PyObject *dict, const char *key, long val)
{
PyObject *valobj;
valobj = PyInt_FromLong(val);
PyDict_SetItemString( dict, key, valobj );
Py_DECREF( valobj );
}
PyDoc_STRVAR(sess_doc,
"SDPSession()\n\
\n\
TODO\n\
");
/*
* utility function to perform an SDP search on a connected session. Builds
* and returns a python list of dictionaries. Each dictionary represents a
* service record match
*/
static PyObject *
do_search( sdp_session_t *sess, uuid_t *uuid )
{
sdp_list_t *response_list = NULL, *attrid_list, *search_list, *r;
uint32_t range = 0x0000ffff;
char buf[1024] = { 0 };
int err = 0;
PyObject *result = 0;
PyObject *rtn_list = PyList_New(0);
if( ! rtn_list ) return 0;
search_list = sdp_list_append( 0, uuid );
attrid_list = sdp_list_append( 0, &range );
// perform the search
Py_BEGIN_ALLOW_THREADS
err = sdp_service_search_attr_req( sess, search_list, \
SDP_ATTR_REQ_RANGE, attrid_list, &response_list);
Py_END_ALLOW_THREADS
if( err ) {
PyErr_SetFromErrno( bluetooth_error );
result = 0;
goto cleanup;
}
// parse the results (ewww....)
// go through each of the service records
for (r = response_list; r; r = r->next ) {
PyObject *dict = PyDict_New();
sdp_record_t *rec = (sdp_record_t*) r->data;
sdp_list_t *proto_list = NULL,
*svc_class_list = NULL,
*profile_list = NULL;
PyObject *py_class_list = NULL, *py_profile_list = NULL;
uuid_t service_id = { 0 };
if( ! dict ) return 0;
// initialize service class list
py_class_list = PyList_New(0);
if( ! py_class_list ) return 0;
PyDict_SetItemString( dict, "service-classes", py_class_list );
Py_DECREF( py_class_list );
// initialize profile list
py_profile_list = PyList_New(0);
if( ! py_profile_list ) return 0;
PyDict_SetItemString( dict, "profiles", py_profile_list );
Py_DECREF( py_profile_list );
// set service name
if( ! sdp_get_service_name( rec, buf, sizeof(buf) ) ) {
dict_set_strings( dict, "name", buf );
memset(buf, 0, sizeof( buf ) );
} else {
PyDict_SetItemString( dict, "name", Py_None );
}
// set service description
if( ! sdp_get_service_desc( rec, buf, sizeof(buf) ) ) {
dict_set_strings( dict, "description", buf );
memset(buf, 0, sizeof( buf ) );
} else {
PyDict_SetItemString( dict, "description", Py_None );
}
// set service provider name
if( ! sdp_get_provider_name( rec, buf, sizeof(buf) ) ) {
dict_set_strings( dict, "provider", buf );
memset(buf, 0, sizeof( buf ) );
} else {
PyDict_SetItemString( dict, "provider", Py_None );
}
// set service id
if( ! sdp_get_service_id( rec, &service_id ) ) {
uuid2str( &service_id, buf );
dict_set_strings( dict, "service-id", buf );
memset(buf, 0, sizeof( buf ) );
} else {
PyDict_SetItemString( dict, "service-id", Py_None );
}
// get a list of the protocol sequences
if( sdp_get_access_protos( rec, &proto_list ) == 0 ) {
sdp_list_t *p = proto_list;
int port;
if( ( port = sdp_get_proto_port( p, RFCOMM_UUID ) ) != 0 ) {
dict_set_strings( dict, "protocol", "RFCOMM" );
dict_set_str_long( dict, "port", port );
} else if ( (port = sdp_get_proto_port( p, L2CAP_UUID ) ) != 0 ) {
dict_set_strings( dict, "protocol", "L2CAP" );
dict_set_str_long( dict, "port", port );
} else {
dict_set_strings( dict, "protocol", "UNKNOWN" );
PyDict_SetItemString( dict, "port", Py_None );
}
// sdp_get_access_protos allocates data on the heap for the
// protocol list, so we need to free the results...
for( ; p ; p = p->next ) {
sdp_list_free( (sdp_list_t*)p->data, 0 );
}
sdp_list_free( proto_list, 0 );
} else {
PyDict_SetItemString( dict, "protocol", Py_None );
PyDict_SetItemString( dict, "port", Py_None );
}
// get a list of the service classes
if( sdp_get_service_classes( rec, &svc_class_list ) == 0 ) {
sdp_list_t *iter;
for( iter = svc_class_list; iter != NULL; iter = iter->next ) {
PyObject *pystr;
char uuid_str[40] = { 0 };
uuid2str( (uuid_t*)iter->data, uuid_str );
pystr = PyString_FromString( uuid_str );
PyList_Append( py_class_list, pystr );
Py_DECREF( pystr );
}
sdp_list_free( svc_class_list, free );
}
// get a list of the profiles
if( sdp_get_profile_descs( rec, &profile_list ) == 0 ) {
sdp_list_t *iter;
for( iter = profile_list; iter != NULL; iter = iter->next ) {
PyObject *tuple, *py_uuid, *py_version;
sdp_profile_desc_t *desc = (sdp_profile_desc_t*)iter->data;
char uuid_str[40] = { 0 };
uuid2str( &desc->uuid, uuid_str );
py_uuid = PyString_FromString( uuid_str );
py_version = PyInt_FromLong( desc->version );
tuple = PyTuple_New( 2 );
PyList_Append( py_profile_list, tuple );
Py_DECREF( tuple );
PyTuple_SetItem( tuple, 0, py_uuid );
PyTuple_SetItem( tuple, 1, py_version );
// Py_DECREF( py_uuid );
// Py_DECREF( py_version );
}
sdp_list_free( profile_list, free );
}
PyList_Append( rtn_list, dict );
Py_DECREF( dict );
sdp_record_free( rec );
}
result = rtn_list;
cleanup:
sdp_list_free( response_list, 0 );
sdp_list_free( search_list, 0 );
sdp_list_free( attrid_list, 0 );
return result;
}
// ==================== SDPSession methods ===========================
// connect
static PyObject *
sess_connect(PySDPSessionObject *s, PyObject *args, PyObject *kwds)
{
bdaddr_t src;
bdaddr_t dst;
char *dst_buf = "localhost";
uint32_t flags = SDP_RETRY_IF_BUSY;
static char *keywords[] = {"target", 0};
bacpy( &src, BDADDR_ANY );
bacpy( &dst, BDADDR_LOCAL );
if( s->session != NULL ) {
sdp_close( s->session );
}
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s", keywords, &dst_buf))
return NULL;
if( strncmp( dst_buf, "localhost", 18 ) != 0 ) {
str2ba( dst_buf, &dst );
} else {
// XXX
}
Py_BEGIN_ALLOW_THREADS
s->session = sdp_connect( &src, &dst, flags );
Py_END_ALLOW_THREADS
if( s->session == NULL )
return PyErr_SetFromErrno( bluetooth_error );
Py_RETURN_NONE;
}
PyDoc_STRVAR(sess_connect_doc,
"connect( dest = \"localhost\" )\n\
\n\
Connects the SDP session to the SDP server specified by dest. If the\n\
session was already connected, it's closed first.\n\
\n\
dest specifies the bluetooth address of the server to connect to. Special\n\
case is \"localhost\"\n\
\n\
Raises _bluetooth.error if something goes wrong");
// close
static PyObject *
sess_close(PySDPSessionObject *s)
{
if( s->session != NULL ) {
Py_BEGIN_ALLOW_THREADS
sdp_close( s->session );
Py_END_ALLOW_THREADS
s->session = NULL;
}
Py_RETURN_NONE;
}
PyDoc_STRVAR(sess_close_doc,
"close()\n\
\n\
Closes the connection with the SDP server. No effect if a session is not open.");
// fileno
static PyObject *
sess_fileno(PySDPSessionObject *s)
{
return PyInt_FromLong((long) s->session->sock);
}
PyDoc_STRVAR(sess_fileno_doc,
"fileno() -> integer\n\
\n\
Return the integer file descriptor of the socket.\n\
You can use this for direct communication with the SDP server.");
// search
static PyObject *
sess_search(PySDPSessionObject *s, PyObject *args, PyObject *kwds)
{
char *uuid_str = 0;
uuid_t uuid = { 0 };
PyObject *result = 0;
if (!PyArg_ParseTuple(args, "s", &uuid_str)) return NULL;
// convert the UUID string into a uuid_t
if( ! str2uuid( uuid_str, &uuid ) ) {
PyErr_SetString(PyExc_ValueError, "invalid UUID!");
return NULL;
}
// make sure the SDP session is open
if( ! s->session ) {
PyErr_SetString( bluetooth_error, "SDP session is not active!" );
return 0;
}
// perform the search
result = do_search( s->session, &uuid );
return result;
}
PyDoc_STRVAR(sess_search_doc,
"search( UUID )\n\
\n\
Searches for a service record with the specified UUID. If no match is found,\n\
returns None. Otherwise, returns a dictionary\n\
\n\
UUID must be in the form \"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX\", \n\
where each X is a hexadecimal digit.");
// browse
static PyObject *
sess_browse(PySDPSessionObject *s)
{
uuid_t uuid = { 0 };
PyObject *result = 0;
// convert the UUID string into a uuid_t
sdp_uuid16_create(&uuid, PUBLIC_BROWSE_GROUP);
// make sure the SDP session is open
if( ! s->session ) {
PyErr_SetString( bluetooth_error, "SDP session is not active!" );
return 0;
}
// perform the search
result = do_search( s->session, &uuid );
return result;
}
PyDoc_STRVAR(sess_browse_doc,
"browse()\n\
\n\
Browses all services advertised by connected SDP session");
static PyMethodDef sess_methods[] = {
{ "search", (PyCFunction) sess_search, METH_VARARGS,
sess_search_doc },
{ "browse", (PyCFunction) sess_browse, METH_NOARGS,
sess_browse_doc },
{ "fileno", (PyCFunction)sess_fileno, METH_NOARGS,
sess_fileno_doc },
{ "connect", (PyCFunction) sess_connect, METH_VARARGS | METH_KEYWORDS,
sess_connect_doc },
{ "close", (PyCFunction)sess_close, METH_NOARGS,
sess_close_doc },
{NULL, NULL}
};
/* =============== object maintenance =============== */
/* Deallocate a socket object in response to the last Py_DECREF().
First close the file description. */
static void
sess_dealloc(PySDPSessionObject *s)
{
if(s->session != NULL) {
sdp_close( s->session );
s->session = NULL;
}
Py_TYPE(s)->tp_free((PyObject *)s);
}
static PyObject *
sess_repr(PySDPSessionObject *s)
{
char buf[512];
if (s->session != NULL) {
PyOS_snprintf( buf, sizeof(buf), "");
} else {
PyOS_snprintf( buf, sizeof(buf), "");
}
return PyString_FromString(buf);
}
/* Create a new, uninitialized socket object. */
static PyObject *
sess_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
PyObject *newsess;
newsess = type->tp_alloc(type, 0);
if (newsess != NULL) {
((PySDPSessionObject *)newsess)->session = NULL;
}
return newsess;
}
/* Initialize a new socket object. */
/*ARGSUSED*/
static int
sess_initobj(PyObject *self, PyObject *args, PyObject *kwds)
{
PySDPSessionObject *s = (PySDPSessionObject *)self;
s->errorhandler = &set_error;
/* From now on, ignore SIGPIPE and let the error checking
do the work. */
#ifdef SIGPIPE
(void) signal(SIGPIPE, SIG_IGN);
#endif
return 0;
}
/* Type object for socket objects. */
PyTypeObject sdp_session_type = {
#if PY_MAJOR_VERSION < 3
PyObject_HEAD_INIT(0) /* Must fill in type value later */
0, /* ob_size */
#else
PyVarObject_HEAD_INIT(NULL, 0) /* Must fill in type value later */
#endif
"_bluetooth.SDPSession", /* tp_name */
sizeof(PySDPSessionObject), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)sess_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
(reprfunc)sess_repr, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
PyObject_GenericGetAttr, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
sess_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
sess_methods, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
0, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
sess_initobj, /* tp_init */
PyType_GenericAlloc, /* tp_alloc */
sess_new, /* tp_new */
PyObject_Del, /* tp_free */
};
pybluez-0.23/bluez/btsdp.h 0000664 0000000 0000000 00000000565 13601523637 0015552 0 ustar 00root root 0000000 0000000 #ifndef __pybluez_sdp_h__
#define __pybluez_sdp_h__
#include
#include
typedef struct {
PyObject_HEAD
sdp_session_t *session;
PyObject *(*errorhandler)(void); /* Error handler; checks
errno, returns NULL and
sets a Python exception */
} PySDPSessionObject;
extern PyTypeObject sdp_session_type;
#endif
pybluez-0.23/docs/ 0000775 0000000 0000000 00000000000 13601523637 0014066 5 ustar 00root root 0000000 0000000 pybluez-0.23/docs/Makefile 0000664 0000000 0000000 00000016760 13601523637 0015540 0 ustar 00root root 0000000 0000000 ## Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = sphinx-build
PAPER =
BUILDDIR = _build
# User-friendly check for sphinx-build
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/)
endif
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help
help:
@echo "Please use \`make ' where is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " singlehtml to make a single large HTML file"
@echo " pickle to make pickle files"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " applehelp to make an Apple Help Book"
@echo " devhelp to make HTML files and a Devhelp project"
@echo " epub to make an epub"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " latexpdf to make LaTeX files and run them through pdflatex"
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
@echo " text to make text files"
@echo " man to make manual pages"
@echo " texinfo to make Texinfo files"
@echo " info to make Texinfo files and run them through makeinfo"
@echo " gettext to make PO message catalogs"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " xml to make Docutils-native XML files"
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
@echo " coverage to run coverage check of the documentation (if enabled)"
.PHONY: clean
clean:
rm -rf $(BUILDDIR)/*
.PHONY: html
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
.PHONY: dirhtml
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
.PHONY: singlehtml
singlehtml:
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
.PHONY: pickle
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
.PHONY: json
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
.PHONY: htmlhelp
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILDDIR)/htmlhelp."
.PHONY: qthelp
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Requests.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Requests.qhc"
.PHONY: applehelp
applehelp:
$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILDDIR)/applehelp
@echo
@echo "Build finished. The help book is in $(BUILDDIR)/applehelp."
@echo "N.B. You won't be able to view it unless you put it in" \
"~/Library/Documentation/Help or install it in your application" \
"bundle."
.PHONY: devhelp
devhelp:
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
@echo
@echo "Build finished."
@echo "To view the help file:"
@echo "# mkdir -p $$HOME/.local/share/devhelp/Requests"
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Requests"
@echo "# devhelp"
.PHONY: epub
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
.PHONY: latex
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
@echo "Run \`make' in that directory to run these through (pdf)latex" \
"(use \`make latexpdf' here to do that automatically)."
.PHONY: latexpdf
latexpdf:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
.PHONY: latexpdfja
latexpdfja:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
@echo "Running LaTeX files through platex and dvipdfmx..."
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
.PHONY: text
text:
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
@echo
@echo "Build finished. The text files are in $(BUILDDIR)/text."
.PHONY: man
man:
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
.PHONY: texinfo
texinfo:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
@echo "Run \`make' in that directory to run these through makeinfo" \
"(use \`make info' here to do that automatically)."
.PHONY: info
info:
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILDDIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
.PHONY: gettext
gettext:
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
.PHONY: changes
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
@echo
@echo "The overview file is in $(BUILDDIR)/changes."
.PHONY: linkcheck
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILDDIR)/linkcheck/output.txt."
.PHONY: doctest
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILDDIR)/doctest/output.txt."
.PHONY: coverage
coverage:
$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILDDIR)/coverage
@echo "Testing of coverage in the sources finished, look at the " \
"results in $(BUILDDIR)/coverage/python.txt."
.PHONY: xml
xml:
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
@echo
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
.PHONY: pseudoxml
pseudoxml:
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
@echo
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." pybluez-0.23/docs/_static/ 0000775 0000000 0000000 00000000000 13601523637 0015514 5 ustar 00root root 0000000 0000000 pybluez-0.23/docs/_static/.nofile 0000664 0000000 0000000 00000000000 13601523637 0016757 0 ustar 00root root 0000000 0000000 pybluez-0.23/docs/_templates/ 0000775 0000000 0000000 00000000000 13601523637 0016223 5 ustar 00root root 0000000 0000000 pybluez-0.23/docs/_templates/.nofile 0000664 0000000 0000000 00000000000 13601523637 0017466 0 ustar 00root root 0000000 0000000 pybluez-0.23/docs/api/ 0000775 0000000 0000000 00000000000 13601523637 0014637 5 ustar 00root root 0000000 0000000 pybluez-0.23/docs/api/advertise_service.rst 0000664 0000000 0000000 00000000145 13601523637 0021077 0 ustar 00root root 0000000 0000000 advertise_service
-----------------
.. currentmodule:: bluetooth
.. autofunction:: advertise_service pybluez-0.23/docs/api/bluetooth_socket.rst 0000664 0000000 0000000 00000000316 13601523637 0020746 0 ustar 00root root 0000000 0000000 BluetoothSocket
---------------
.. todo:: Add documentation for the BluetoothSocket methods.
.. currentmodule:: bluetooth
.. autoclass:: BluetoothSocket
:show-inheritance:
:members:
:undoc-members: pybluez-0.23/docs/api/device_discoverer.rst 0000664 0000000 0000000 00000000336 13601523637 0021057 0 ustar 00root root 0000000 0000000 DeviceDiscoverer
----------------
.. todo:: Add documentation for the DeviceDiscover class and its methods.
.. currentmodule:: bluetooth
.. autoclass:: DeviceDiscoverer
:show-inheritance:
:members:
:undoc-members: pybluez-0.23/docs/api/discover_devices.rst 0000664 0000000 0000000 00000000142 13601523637 0020706 0 ustar 00root root 0000000 0000000 discover_devices
----------------
.. currentmodule:: bluetooth
.. autofunction:: discover_devices pybluez-0.23/docs/api/find_service.rst 0000664 0000000 0000000 00000000126 13601523637 0020030 0 ustar 00root root 0000000 0000000 find_service
------------
.. currentmodule:: bluetooth
.. autofunction:: find_service pybluez-0.23/docs/api/index.rst 0000664 0000000 0000000 00000000723 13601523637 0016502 0 ustar 00root root 0000000 0000000 .. _api:
PyBluez API
===========
The Pybluez API provides a suite of classes and functions.
Classes
-------
.. toctree::
:maxdepth: 1
bluetooth_socket
device_discoverer
Functions
---------
.. toctree::
:maxdepth: 1
advertise_service
discover_devices
find_service
lookup_name
stop_advertising
Exceptions
----------
BluetoothError
""""""""""""""
.. currentmodule:: bluetooth
.. autoexception:: BluetoothError
:show-inheritance:
pybluez-0.23/docs/api/lookup_name.rst 0000664 0000000 0000000 00000000123 13601523637 0017676 0 ustar 00root root 0000000 0000000 lookup_name
-----------
.. currentmodule:: bluetooth
.. autofunction:: lookup_name pybluez-0.23/docs/api/stop_advertising.rst 0000664 0000000 0000000 00000000142 13601523637 0020752 0 ustar 00root root 0000000 0000000 stop_advertising
----------------
.. currentmodule:: bluetooth
.. autofunction:: stop_advertising pybluez-0.23/docs/conf.py 0000664 0000000 0000000 00000007355 13601523637 0015377 0 ustar 00root root 0000000 0000000 # Configuration file for the Sphinx documentation builder.
#
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# http://www.sphinx-doc.org/en/master/config
# -- Path setup --------------------------------------------------------------
# If extensions (or modules to document with autodoc) are in another directory,
# add these directories to sys.path here. If the directory is relative to the
# documentation root, use os.path.abspath to make it absolute, like shown here.
#
import os
import sys
sys.path.insert(0, os.path.abspath('../'))
# -- Project information -----------------------------------------------------
project = 'PyBluez'
copyright = '2004 - 2019, Albert Haung & contributors'
author = 'Albert Haung & contributors'
# The full version, including alpha/beta/rc tags
release = 'master'
# -- General configuration ---------------------------------------------------
master_doc = 'index'
# Add any Sphinx extension module names here, as strings. They can be
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
# ones.
extensions = [
'sphinx.ext.autodoc',
'sphinx.ext.coverage',
'sphinx.ext.napoleon',
'sphinx.ext.intersphinx',
'sphinx.ext.todo',
'recommonmark'
]
todo_include_todos = True
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = []
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinx_rtd_theme'
html_theme_options = {
'canonical_url': '',
'analytics_id': '', # Provided by Google in your dashboard
'logo_only': False,
'display_version': True,
'prev_next_buttons_location': 'bottom',
'style_external_links': False,
# Toc options
'collapse_navigation': True,
'sticky_navigation': True,
'navigation_depth': 4,
'includehidden': True,
'titles_only': False
}
#enables the edit on github link
html_context = {
"display_github": True, # Integrate GitHub
"github_user": "pybluez", # Username
"github_repo": "pybluez", # Repo name
"github_version": "master", # Version
"conf_py_path": "/docs/", # Path in the checkout to the docs root
}
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']
# Sphinx needs to import modules to read their docstrings and follows imports
# within files. Pybluez docs are built and published by CI on a linux box.
# So windows and macos specific modules may need to be mocked.
autodoc_mock_imports = [
'bluetooth._bluetooth',
'bluetooth._msbt',
]
# Napoleon is a sphinx extension allowing autodoc to parse docstrings which don't follow
# restructured text formatting rules. It will currently attempt to parse google and numpy
# styles.
#
# Napoleon settings
napoleon_google_docstring = True
napoleon_numpy_docstring = True
napoleon_include_init_with_doc = False
napoleon_include_private_with_doc = False
napoleon_include_special_with_doc = True
napoleon_use_admonition_for_examples = False
napoleon_use_admonition_for_notes = False
napoleon_use_admonition_for_references = False
napoleon_use_ivar = False
napoleon_use_param = True
napoleon_use_rtype = True
# intersphinx
intersphinx_mapping = {
'python': ('https://docs.python.org/3', None)
} pybluez-0.23/docs/contributing.rst 0000664 0000000 0000000 00000004156 13601523637 0017335 0 ustar 00root root 0000000 0000000 =======================
Contributing to PyBluez
=======================
**This project is not currently under active development**.
Contributions are strongly desired to resolve compatibility problems on newer systems, address bugs, and improve platform support for
various features. Here are some guidelines to follow.
Compatibility Issues
====================
Please submit compatiblity issues by opening an `issue`_ explaining the problem clearly
and providing information necessary to reproduce the issue, including sample
code and logs.
If you have long logs, please post them on https://gist.github.com and link to
the Gist in your issue.
Bugs
====
Please submit bug reports by opening an `issue`_ explaining the problem clearly
using code examples.
Coding
======
.. todo:: Develop PyBluez coding standards and style guides.
Documentation
=============
The documentation source lives in the `docs`_ folder. Contributions to the
documentation are welcome but should be easy to read and understand.
All source documents are in restructured text format.
.. todo:: Develop PyBluez documentation standards and style guides.
Commit messages and pull requests
=================================
Commit messages should be concise but descriptive, and in the form of an instructional
patch description (e.g., "Add macOS support" not "Added macOS support").
Commits which close, or intend to close, an issue should include the phrase
"fix #234" or "close #234" where ``#234`` is the issue number, as well a short description,
for example: "Add logic to support Win10, fix #234". Pull requests should aim to match or closely match
the corresponding issue title.
Copyrights
==========
By submitting to this project you agree to your code or documentation being
released under the projects :doc:`license `. Copyrights on submissions are
owned by their authors. Feel free to append your name to the list of contributors
in :file:`contributors.rst` found in the projects `docs`_ folder as part of your pull request!
.. _docs: https://github.com/pybluez/pybluez/tree/master/docs
.. _issue: https://github.com/pybluez/pybluez/issues pybluez-0.23/docs/contributors.rst 0000664 0000000 0000000 00000003327 13601523637 0017362 0 ustar 00root root 0000000 0000000 ============
Contributors
============
Original Author - `Albert Huang`_.
Maintainers:
- `Ryan Govostes`_
- `Piotr Karulis`_
Other contributors:
- `Travis Peters`_
- `Michal Maruska`_
- `Young-Bo`_
- `Thomas Leveil`_
- `Yurii Shevchuk`_
- `Hugo Sales`_
- `kedos`_
- `Chad Spensky`_
- `clach04`_
- `Boris Belousov`_
- `Ratmir Karabut`_
- `zeripath`_
- `Brennan Ashton`_
- `Haim Daniel`_
- `demanbart`_
- `Clemens Wolff`_
- `Arusekk`_
- `Colin Atkinson`_
- `Vitali Lovich`_
- `bbregeault`_
- `Eduardo Marossi`_
- `Bill Crawford`_
- `Christian Clauss`_
.. _Albert Huang: https://github.com/ashuang
.. _Ryan Govostes: https://github.com/rgov
.. _Piotr Karulis: https://github.com/karulis
.. _Travis Peters: https://github.com/traviswpeters
.. _Michal Maruska: https://github.com/mmaruska
.. _Young-Bo: https://github.com/KHU-YoungBo
.. _Thomas Leveil: https://github.com/thomasleveil
.. _Yurii Shevchuk: https://github.com/itdxer
.. _Hugo Sales: https://github.com/someonewithpc
.. _kedos: https://github.com/kedos
.. _Chad Spensky: https://github.com/cspensky
.. _clach04: https://github.com/clach04
.. _Boris Belousov: https://github.com/b4be1
.. _Ratmir Karabut: https://github.com/rkarabut
.. _zeripath: https://github.com/zeripath
.. _Brennan Ashton: https://github.com/btashton
.. _Haim Daniel: https://github.com/haim0n
.. _demanbart: https://github.com/demanbart
.. _Clemens Wolff: https://github.com/c-w
.. _Arusekk: https://github.com/Arusekk
.. _Colin Atkinson: https://github.com/colatkinson
.. _Vitali Lovich: https://github.com/vlovich
.. _bbregeault: https://github.com/bbregeault
.. _Eduardo Marossi: https://github.com/eduardomarossi
.. _Bill Crawford: https://github.com/beadysea
.. _Christian Clauss: https://github.com/cclauss
pybluez-0.23/docs/index.rst 0000664 0000000 0000000 00000001521 13601523637 0015726 0 ustar 00root root 0000000 0000000 =======
PyBluez
=======
|versions| |wheel| |build status| |license|
.. |build status| image:: https://travis-ci.org/pybluez/pybluez.svg?branch=master
:target: https://travis-ci.org/pybluez/pybluez
.. |license| image:: https://img.shields.io/pypi/l/pybluez.svg
:target: https://pypi.org/project/pybluez/
.. |wheel| image:: https://img.shields.io/pypi/wheel/pybluez.svg
:target: https://pypi.org/project/pybluez/
.. |versions| image:: https://img.shields.io/pypi/pyversions/pybluez.svg
:target: https://pypi.org/project/pybluez/
Python extension module allowing access to system Bluetooth resources.
Table of contents
=================
.. toctree::
:maxdepth: 1
:numbered:
install
contributors
contributing
api/index
license
**Indices and tables:**
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`
pybluez-0.23/docs/install.rst 0000664 0000000 0000000 00000005135 13601523637 0016272 0 ustar 00root root 0000000 0000000 .. _installing:
Installing PyBluez
==================
PyBluez can be installed on GNU/Linux, Windows and macOS systems and is compatible
with Python 2.7 and 3.
.. note:: Before you install **PyBluez** please install the dependencies required for
your system as described in the sections below.
**Installing PyBluez using pip**
Open a terminal (command prompt on Windows) and enter
::
pip install pybluez
(there are also binaries for Windows platform on PyPI or here - `Unofficial Windows Binaries for Python Extension Packages `_)
For experimental Bluetooth Low Energy support (only for Linux platform -
for additional dependencies please take look at:
`ble-dependencies `_)
::
pip install pybluez\[ble\]
**Installing PyBluez from source**
Download a stable release from ``_
or download the latest version using the links below.
+------+------+----------------+
| master.zip_ | master.tar.gz_ |
+------+------+----------------+
.. _master.zip: https://github.com/pybluez/pybluez/archive/master.zip
.. _master.tar.gz: https://github.com/pybluez/pybluez/archive/master.tar.gz
Extract the zip or tar and cd to the extracted file directory, then:
::
python setup.py install
for Bluetooth Low Energy support (GNU/Linux only):
::
pip install -e .\[ble\]
GNU/Linux Dependencies
""""""""""""""""""""""
- Python 2.7 or more recent version
- Python distutils (standard in most Python distros, separate package python-dev in Debian)
- BlueZ libraries and header files
Windows Dependencies
""""""""""""""""""""
- Windows 7/8/8.1/10
- Python 3.5 or more recent version
PyBluez requires a C++ compiler installed on your system to build CPython modules.
For Python 3.5 or higher
- Microsoft Visual C++ 14.0 standalone: Build Tools for Visual Studio 2017 (x86, x64, ARM, ARM64)
- Microsoft Visual C++ 14.0 with Visual Studio 2017 (x86, x64, ARM, ARM64)
- Microsoft Visual C++ 14.0 standalone: Visual C++ Build Tools 2015 (x86, x64, ARM)
- Microsoft Visual C++ 14.0 with Visual Studio 2015 (x86, x64, ARM)
.. note:: Windows 10 users need to download and install the `Windows 10 SDK `_
`More details here `_
- Widcomm BTW development kit 5.0 or later (Optional)
macOS Dependencies
""""""""""""""""""
- Xcode
- PyObjc 3.1b or later (https://pythonhosted.org/pyobjc/install.html#manual-installation)
pybluez-0.23/docs/license.rst 0000664 0000000 0000000 00000001541 13601523637 0016243 0 ustar 00root root 0000000 0000000 =======
License
=======
Copyright |copy| 2004-2019 Albert Haung and contributors; see :doc:`contributors`
for current list.
PyBluez is free software; you can redistribute it and/or modify it under the
terms of the GNU General Public License as published by the Free Software
Foundation; either version 2 of the License, or (at your option) any later
version.
PyBluez is distributed in the hope that it will be useful, but WITHOUT ANY
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
PyBluez; if not, write to the Free Software Foundation, Inc., 51 Franklin St,
Fifth Floor, Boston, MA 02110-1301 USA
.. literalinclude:: ../COPYING
.. |copy| unicode:: U+000A9 .. COPYRIGHT SIGN pybluez-0.23/docs/make.bat 0000664 0000000 0000000 00000015515 13601523637 0015502 0 ustar 00root root 0000000 0000000 @ECHO OFF
REM Command file for Sphinx documentation
if "%SPHINXBUILD%" == "" (
set SPHINXBUILD=sphinx-build
)
set BUILDDIR=_build
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
set I18NSPHINXOPTS=%SPHINXOPTS% .
if NOT "%PAPER%" == "" (
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
)
if "%1" == "" goto help
if "%1" == "help" (
:help
echo.Please use `make ^` where ^ is one of
echo. html to make standalone HTML files
echo. dirhtml to make HTML files named index.html in directories
echo. singlehtml to make a single large HTML file
echo. pickle to make pickle files
echo. json to make JSON files
echo. htmlhelp to make HTML files and a HTML help project
echo. qthelp to make HTML files and a qthelp project
echo. devhelp to make HTML files and a Devhelp project
echo. epub to make an epub
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
echo. text to make text files
echo. man to make manual pages
echo. texinfo to make Texinfo files
echo. gettext to make PO message catalogs
echo. changes to make an overview over all changed/added/deprecated items
echo. xml to make Docutils-native XML files
echo. pseudoxml to make pseudoxml-XML files for display purposes
echo. linkcheck to check all external links for integrity
echo. doctest to run all doctests embedded in the documentation if enabled
echo. coverage to run coverage check of the documentation if enabled
goto end
)
if "%1" == "clean" (
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
del /q /s %BUILDDIR%\*
goto end
)
REM Check if sphinx-build is available and fallback to Python version if any
%SPHINXBUILD% 1>NUL 2>NUL
if errorlevel 9009 goto sphinx_python
goto sphinx_ok
:sphinx_python
set SPHINXBUILD=python -m sphinx.__init__
%SPHINXBUILD% 2> nul
if errorlevel 9009 (
echo.
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
echo.installed, then set the SPHINXBUILD environment variable to point
echo.to the full path of the 'sphinx-build' executable. Alternatively you
echo.may add the Sphinx directory to PATH.
echo.
echo.If you don't have Sphinx installed, grab it from
echo.http://sphinx-doc.org/
exit /b 1
)
:sphinx_ok
if "%1" == "html" (
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
goto end
)
if "%1" == "dirhtml" (
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
goto end
)
if "%1" == "singlehtml" (
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
goto end
)
if "%1" == "pickle" (
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the pickle files.
goto end
)
if "%1" == "json" (
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can process the JSON files.
goto end
)
if "%1" == "htmlhelp" (
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run HTML Help Workshop with the ^
.hhp project file in %BUILDDIR%/htmlhelp.
goto end
)
if "%1" == "qthelp" (
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished; now you can run "qcollectiongenerator" with the ^
.qhcp project file in %BUILDDIR%/qthelp, like this:
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Requests.qhcp
echo.To view the help file:
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Requests.ghc
goto end
)
if "%1" == "devhelp" (
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
if errorlevel 1 exit /b 1
echo.
echo.Build finished.
goto end
)
if "%1" == "epub" (
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The epub file is in %BUILDDIR%/epub.
goto end
)
if "%1" == "latex" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
if errorlevel 1 exit /b 1
echo.
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdf" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf
cd %~dp0
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "latexpdfja" (
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
cd %BUILDDIR%/latex
make all-pdf-ja
cd %~dp0
echo.
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
goto end
)
if "%1" == "text" (
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The text files are in %BUILDDIR%/text.
goto end
)
if "%1" == "man" (
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The manual pages are in %BUILDDIR%/man.
goto end
)
if "%1" == "texinfo" (
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
goto end
)
if "%1" == "gettext" (
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
goto end
)
if "%1" == "changes" (
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
if errorlevel 1 exit /b 1
echo.
echo.The overview file is in %BUILDDIR%/changes.
goto end
)
if "%1" == "linkcheck" (
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
if errorlevel 1 exit /b 1
echo.
echo.Link check complete; look for any errors in the above output ^
or in %BUILDDIR%/linkcheck/output.txt.
goto end
)
if "%1" == "doctest" (
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
if errorlevel 1 exit /b 1
echo.
echo.Testing of doctests in the sources finished, look at the ^
results in %BUILDDIR%/doctest/output.txt.
goto end
)
if "%1" == "coverage" (
%SPHINXBUILD% -b coverage %ALLSPHINXOPTS% %BUILDDIR%/coverage
if errorlevel 1 exit /b 1
echo.
echo.Testing of coverage in the sources finished, look at the ^
results in %BUILDDIR%/coverage/python.txt.
goto end
)
if "%1" == "xml" (
%SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The XML files are in %BUILDDIR%/xml.
goto end
)
if "%1" == "pseudoxml" (
%SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
if errorlevel 1 exit /b 1
echo.
echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
goto end
)
:end pybluez-0.23/docs/requirements.txt 0000664 0000000 0000000 00000000054 13601523637 0017351 0 ustar 00root root 0000000 0000000 sphinx
recommonmark
sphinx_rtd_theme
easydev pybluez-0.23/docs/user/ 0000775 0000000 0000000 00000000000 13601523637 0015044 5 ustar 00root root 0000000 0000000 pybluez-0.23/docs/user/intro.rst 0000664 0000000 0000000 00000000202 13601523637 0016723 0 ustar 00root root 0000000 0000000 .. orphan page while we develop it. This stops sphinx raising a toctree warning.
:orphan:
************
Introduction
************ pybluez-0.23/examples/ 0000775 0000000 0000000 00000000000 13601523637 0014754 5 ustar 00root root 0000000 0000000 pybluez-0.23/examples/advanced/ 0000775 0000000 0000000 00000000000 13601523637 0016521 5 ustar 00root root 0000000 0000000 pybluez-0.23/examples/advanced/inquiry-with-rssi.py 0000664 0000000 0000000 00000012255 13601523637 0022527 0 ustar 00root root 0000000 0000000 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""PyBluez advanced example inquiry-with-rssi.py
Perform a simple device inquiry, followed by a remote name request of each
discovered device
"""
import struct
import sys
import bluetooth
import bluetooth._bluetooth as bluez # low level bluetooth wrappers
def printpacket(pkt):
for c in pkt:
sys.stdout.write("{%02x} ".format(struct.unpack("B", c)[0]))
def read_inquiry_mode(sock):
"""returns the current mode, or -1 on failure"""
# save current filter
old_filter = sock.getsockopt(bluez.SOL_HCI, bluez.HCI_FILTER, 14)
# Setup socket filter to receive only events related to the
# read_inquiry_mode command
flt = bluez.hci_filter_new()
opcode = bluez.cmd_opcode_pack(bluez.OGF_HOST_CTL,
bluez.OCF_READ_INQUIRY_MODE)
bluez.hci_filter_set_ptype(flt, bluez.HCI_EVENT_PKT)
bluez.hci_filter_set_event(flt, bluez.EVT_CMD_COMPLETE)
bluez.hci_filter_set_opcode(flt, opcode)
sock.setsockopt(bluez.SOL_HCI, bluez.HCI_FILTER, flt)
# first read the current inquiry mode.
bluez.hci_send_cmd(sock, bluez.OGF_HOST_CTL,
bluez.OCF_READ_INQUIRY_MODE)
pkt = sock.recv(255)
status, mode = struct.unpack("xxxxxxBB", pkt)
# restore old filter
sock.setsockopt(bluez.SOL_HCI, bluez.HCI_FILTER, old_filter)
return mode
def write_inquiry_mode(sock, mode):
"""returns 0 on success, -1 on failure"""
# save current filter
old_filter = sock.getsockopt(bluez.SOL_HCI, bluez.HCI_FILTER, 14)
# Setup socket filter to receive only events related to the
# write_inquiry_mode command
flt = bluez.hci_filter_new()
opcode = bluez.cmd_opcode_pack(bluez.OGF_HOST_CTL,
bluez.OCF_WRITE_INQUIRY_MODE)
bluez.hci_filter_set_ptype(flt, bluez.HCI_EVENT_PKT)
bluez.hci_filter_set_event(flt, bluez.EVT_CMD_COMPLETE)
bluez.hci_filter_set_opcode(flt, opcode)
sock.setsockopt(bluez.SOL_HCI, bluez.HCI_FILTER, flt)
# send the command!
bluez.hci_send_cmd(sock, bluez.OGF_HOST_CTL,
bluez.OCF_WRITE_INQUIRY_MODE,
struct.pack("B", mode))
pkt = sock.recv(255)
status = struct.unpack("xxxxxxB", pkt)[0]
# restore old filter
sock.setsockopt(bluez.SOL_HCI, bluez.HCI_FILTER, old_filter)
if not status:
return -1
return 0
def device_inquiry_with_with_rssi(sock):
# save current filter
old_filter = sock.getsockopt(bluez.SOL_HCI, bluez.HCI_FILTER, 14)
# perform a device inquiry on bluetooth device #0
# The inquiry should last 8 * 1.28 = 10.24 seconds
# before the inquiry is performed, bluez should flush its cache of
# previously discovered devices
flt = bluez.hci_filter_new()
bluez.hci_filter_all_events(flt)
bluez.hci_filter_set_ptype(flt, bluez.HCI_EVENT_PKT)
sock.setsockopt(bluez.SOL_HCI, bluez.HCI_FILTER, flt)
duration = 4
max_responses = 255
cmd_pkt = struct.pack("BBBBB", 0x33, 0x8b, 0x9e, duration, max_responses)
bluez.hci_send_cmd(sock, bluez.OGF_LINK_CTL, bluez.OCF_INQUIRY, cmd_pkt)
results = []
while True:
pkt = sock.recv(255)
ptype, event, plen = struct.unpack("BBB", pkt[:3])
print("Event: {}".format(event))
if event == bluez.EVT_INQUIRY_RESULT_WITH_RSSI:
pkt = pkt[3:]
nrsp = bluetooth.get_byte(pkt[0])
for i in range(nrsp):
addr = bluez.ba2str(pkt[1+6*i:1+6*i+6])
rssi = bluetooth.byte_to_signed_int(
bluetooth.get_byte(pkt[1 + 13 * nrsp + i]))
results.append((addr, rssi))
print("[{}] RSSI: {}".format(addr, rssi))
elif event == bluez.EVT_INQUIRY_COMPLETE:
break
elif event == bluez.EVT_CMD_STATUS:
status, ncmd, opcode = struct.unpack("BBH", pkt[3:7])
if status:
print("Uh oh...")
printpacket(pkt[3:7])
break
elif event == bluez.EVT_INQUIRY_RESULT:
pkt = pkt[3:]
nrsp = bluetooth.get_byte(pkt[0])
for i in range(nrsp):
addr = bluez.ba2str(pkt[1+6*i:1+6*i+6])
results.append((addr, -1))
print("[{}] (no RRSI)".format(addr))
else:
print("Unrecognized packet type 0x{:02x}.".format(ptype))
# restore old filter
sock.setsockopt(bluez.SOL_HCI, bluez.HCI_FILTER, old_filter)
return results
dev_id = 0
try:
sock = bluez.hci_open_dev(dev_id)
except:
print("Error accessing bluetooth device.")
sys.exit(1)
try:
mode = read_inquiry_mode(sock)
except Exception as e:
print("Error reading inquiry mode.")
print("Are you sure this a bluetooth 1.2 device?")
print(e)
sys.exit(1)
print("Current inquiry mode is", mode)
if mode != 1:
print("Writing inquiry mode...")
try:
result = write_inquiry_mode(sock, 1)
except Exception as e:
print("Error writing inquiry mode. Are you sure you're root?")
print(e)
sys.exit(1)
if result:
print("Error while setting inquiry mode")
print("Result:", result)
device_inquiry_with_with_rssi(sock)
pybluez-0.23/examples/advanced/l2-mtu.py 0000664 0000000 0000000 00000003270 13601523637 0020215 0 ustar 00root root 0000000 0000000 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""PyBluez advanced example l2-mtu.py"""
import sys
import bluetooth
def usage():
print("Usage: l2-mtu.py < server | client > [options]")
print(" l2-mtu.py server - to start in server mode")
print(" l2-mtu.py client - to start in client mode and connect to addr")
sys.exit(2)
if len(sys.argv) < 2:
usage()
mode = sys.argv[1]
if mode not in ["client", "server"]:
usage()
if mode == "server":
server_sock = bluetooth.BluetoothSocket(bluetooth.L2CAP)
server_sock.bind(("", 0x1001))
bluetooth.set_l2cap_mtu(server_sock, 65535)
server_sock.listen(1)
while True:
print("Waiting for incoming connection...")
client_sock, address = server_sock.accept()
print("Accepted connection from", str(address))
print("Waiting for data...")
total = 0
while True:
try:
data = client_sock.recv(65535)
except bluetooth.BluetoothError as e:
break
if not data:
break
print("Received packet of size", len(data))
client_sock.close()
print("Connection closed.")
server_sock.close()
else:
sock = bluetooth.BluetoothSocket(bluetooth.L2CAP)
print("Connected. Adjusting link parameters.")
bluetooth.set_l2cap_mtu(sock, 65535)
bt_addr = sys.argv[2]
print("Trying to connect to {}:1001...".format(bt_addr))
port = 0x1001
sock.connect((bt_addr, port))
totalsent = 0
for i in range(1, 65535, 100):
pkt = "0" * i
sent = sock.send(pkt)
print("Sent packet of size {} (tried {}).".format(sent, len(pkt)))
sock.close()
pybluez-0.23/examples/advanced/l2-unreliable-client.py 0000664 0000000 0000000 00000002535 13601523637 0023011 0 ustar 00root root 0000000 0000000 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""PyBluez advanced example l2-unreliable-client.py"""
import sys
import bluetooth
import bluetooth._bluetooth as bluez # low level bluetooth wrappers
# Create the client socket
sock = bluetooth.BluetoothSocket(bluetooth.L2CAP)
if len(sys.argv) < 4:
print("Usage: l2-unreliable-client.py ")
print(" address - device that l2-unreliable-server is running on")
print(" timeout - wait timeout * 0.625ms before dropping unACK'd packets")
print(" num_packets - number of 627-byte packets to send on connect")
sys.exit(2)
bt_addr = sys.argv[1]
timeout = int(sys.argv[2])
num_packets = int(sys.argv[3])
print("Trying to connect to {}:1001...".format(bt_addr))
port = 0x1001
sock.connect((bt_addr, port))
print("Connected. Adjusting link parameters.")
print("Current flush timeout is {} ms.".format(
bluetooth.read_flush_timeout(bt_addr)))
try:
bluetooth.write_flush_timeout(bt_addr, timeout)
except bluez.error as e:
print("Error setting flush timeout. Are you sure you're superuser?")
print(e)
sys.exit(1)
print("New flush timeout is {} ms.".format(
bluetooth.read_flush_timeout(bt_addr)))
totalsent = 0
for i in range(num_packets):
pkt = "0" * 672
totalsent += sock.send(pkt)
print("Sent {} bytes total.".format(totalsent))
sock.close()
pybluez-0.23/examples/advanced/l2-unreliable-server.py 0000664 0000000 0000000 00000001367 13601523637 0023043 0 ustar 00root root 0000000 0000000 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""PyBluez advanced example l2-unreliable-server.py"""
import bluetooth
server_sock = bluetooth.BluetoothSocket(bluetooth.L2CAP)
server_sock.bind(("", 0x1001))
server_sock.listen(1)
while True:
print("Waiting for incoming connection...")
client_sock, address = server_sock.accept()
print("Accepted connection from", str(address))
print("Waiting for data...")
total = 0
while True:
try:
data = client_sock.recv(1024)
except bluetooth.BluetoothError as e:
break
if not data:
break
total += len(data)
print("Total byte read:", total)
client_sock.close()
print("Connection closed")
server_sock.close()
pybluez-0.23/examples/advanced/read-local-bdaddr.py 0000664 0000000 0000000 00000000344 13601523637 0022315 0 ustar 00root root 0000000 0000000 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""PyBluez advanced example read-local-bdaddr.py
Read the local Bluetooth device address
"""
import bluetooth
if __name__ == "__main__":
print(bluetooth.read_local_bdaddr())
pybluez-0.23/examples/advanced/write-inquiry-scan.py 0000664 0000000 0000000 00000006231 13601523637 0022647 0 ustar 00root root 0000000 0000000 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""PyBluez advanced example write-inquiry-scan.py"""
import struct
import sys
import bluetooth._bluetooth as bluez # low level bluetooth wrappers
def read_inquiry_scan_activity(sock):
"""returns the current inquiry scan interval and window,
or -1 on failure"""
# save current filter
old_filter = sock.getsockopt(bluez.SOL_HCI, bluez.HCI_FILTER, 14)
# Setup socket filter to receive only events related to the
# read_inquiry_mode command
flt = bluez.hci_filter_new()
opcode = bluez.cmd_opcode_pack(bluez.OGF_HOST_CTL,
bluez.OCF_READ_INQ_ACTIVITY)
bluez.hci_filter_set_ptype(flt, bluez.HCI_EVENT_PKT)
bluez.hci_filter_set_event(flt, bluez.EVT_CMD_COMPLETE)
bluez.hci_filter_set_opcode(flt, opcode)
sock.setsockopt(bluez.SOL_HCI, bluez.HCI_FILTER, flt)
# first read the current inquiry mode.
bluez.hci_send_cmd(sock, bluez.OGF_HOST_CTL, bluez.OCF_READ_INQ_ACTIVITY)
pkt = sock.recv(255)
status, interval, window = struct.unpack("!xxxxxxBHH", pkt)
interval = bluez.btohs(interval)
interval = (interval >> 8) | ((interval & 0xFF) << 8)
window = (window >> 8) | ((window & 0xFF) << 8)
# restore old filter
sock.setsockopt(bluez.SOL_HCI, bluez.HCI_FILTER, old_filter)
return interval, window
def write_inquiry_scan_activity(sock, interval, window):
"""returns 0 on success, -1 on failure"""
# save current filter
old_filter = sock.getsockopt(bluez.SOL_HCI, bluez.HCI_FILTER, 14)
# Setup socket filter to receive only events related to the
# write_inquiry_mode command
flt = bluez.hci_filter_new()
opcode = bluez.cmd_opcode_pack(bluez.OGF_HOST_CTL,
bluez.OCF_WRITE_INQ_ACTIVITY)
bluez.hci_filter_set_ptype(flt, bluez.HCI_EVENT_PKT)
bluez.hci_filter_set_event(flt, bluez.EVT_CMD_COMPLETE)
bluez.hci_filter_set_opcode(flt, opcode)
sock.setsockopt(bluez.SOL_HCI, bluez.HCI_FILTER, flt)
# send the command
bluez.hci_send_cmd(sock, bluez.OGF_HOST_CTL, bluez.OCF_WRITE_INQ_ACTIVITY,
struct.pack("HH", interval, window))
pkt = sock.recv(255)
status = struct.unpack("xxxxxxB", pkt)[0]
# restore old filter
sock.setsockopt(bluez.SOL_HCI, bluez.HCI_FILTER, old_filter)
if status:
return -1
return 0
dev_id = 0
try:
sock = bluez.hci_open_dev(dev_id)
except:
print("Error accessing bluetooth device.")
sys.exit(1)
try:
interval, window = read_inquiry_scan_activity(sock)
except Exception as e:
print("Error reading inquiry scan activity.")
print(e)
sys.exit(1)
print("Current inquiry scan interval: {} (0x{:02x}) window: {} (0x{:02x})"
.format(interval, interval, window, window))
if len(sys.argv) == 3:
interval = int(sys.argv[1])
window = int(sys.argv[2])
print("Target interval: {} window {}".format(interval, window))
write_inquiry_scan_activity(sock, interval, window)
interval, window = read_inquiry_scan_activity(sock)
print("Current inquiry scan interval: {} (0x{:02x}) window: {} (0x{:02x})"
.format(interval, interval, window, window))
pybluez-0.23/examples/ble/ 0000775 0000000 0000000 00000000000 13601523637 0015516 5 ustar 00root root 0000000 0000000 pybluez-0.23/examples/ble/beacon.py 0000664 0000000 0000000 00000000630 13601523637 0017316 0 ustar 00root root 0000000 0000000 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""PyBluez ble example beacon.py
Advertises a bluethooth low energy beacon for 15 seconds.
"""
import time
from bluetooth.ble import BeaconService
service = BeaconService()
service.start_advertising("11111111-2222-3333-4444-555555555555",
1, 1, 1, 200)
time.sleep(15)
service.stop_advertising()
print("Done.")
pybluez-0.23/examples/ble/beacon_scan.py 0000664 0000000 0000000 00000001572 13601523637 0020330 0 ustar 00root root 0000000 0000000 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""PyBluez ble example beacon_scan.py"""
from bluetooth.ble import BeaconService
class Beacon(object):
def __init__(self, data, address):
self._uuid = data[0]
self._major = data[1]
self._minor = data[2]
self._power = data[3]
self._rssi = data[4]
self._address = address
def __str__(self):
ret = "Beacon: address:{ADDR} uuid:{UUID} major:{MAJOR} " \
"minor:{MINOR} txpower:{POWER} rssi:{RSSI}" \
.format(ADDR=self._address, UUID=self._uuid, MAJOR=self._major,
MINOR=self._minor, POWER=self._power, RSSI=self._rssi)
return ret
service = BeaconService()
devices = service.scan(2)
for address, data in list(devices.items()):
b = Beacon(data, address)
print(b)
print("Done.")
pybluez-0.23/examples/ble/read_name.py 0000664 0000000 0000000 00000002047 13601523637 0020006 0 ustar 00root root 0000000 0000000 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""PyBluez example read_name.py
Copyright (C) 2014, Oscar Acena
This software is under the terms of GPLv3 or later.
"""
from __future__ import print_function # Python 2 compatibility
import sys
from bluetooth.ble import GATTRequester
class Reader(object):
def __init__(self, address):
self.requester = GATTRequester(address, False)
self.connect()
self.request_data()
def connect(self):
print("Connecting...", end=" ")
sys.stdout.flush()
self.requester.connect(True)
print("OK.")
def request_data(self):
data = self.requester.read_by_uuid(
"00002a00-0000-1000-8000-00805f9b34fb")[0]
try:
print("Device name:", data.decode("utf-8"))
except AttributeError:
print("Device name:", data)
if __name__ == "__main__":
if len(sys.argv) < 2:
print("Usage: {} ".format(sys.argv[0]))
sys.exit(1)
Reader(sys.argv[1])
print("Done.")
pybluez-0.23/examples/ble/scan.py 0000664 0000000 0000000 00000000431 13601523637 0017012 0 ustar 00root root 0000000 0000000 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""PyBluez ble example scan.py"""
from bluetooth.ble import DiscoveryService
service = DiscoveryService()
devices = service.discover(2)
for address, name in devices.items():
print("Name: {}, address: {}".format(name, address))
pybluez-0.23/examples/bluezchat/ 0000775 0000000 0000000 00000000000 13601523637 0016735 5 ustar 00root root 0000000 0000000 pybluez-0.23/examples/bluezchat/bluezchat.glade 0000664 0000000 0000000 00000013505 13601523637 0021720 0 ustar 00root root 0000000 0000000
Truebluez chat240320TrueTrueTrueTrueGTK_SHADOW_INTrueTrueFalseTrueTrueTrue_QuitTrueTrueTrueS_canTrue1TrueTrue_ChatTrue21TrueTrueGTK_SHADOW_INTrueTrue1TrueTruetext:FalseFalseTrueTrue*31TrueTrue_SendTrueFalseFalse22
pybluez-0.23/examples/bluezchat/bluezchat.gladep 0000664 0000000 0000000 00000000427 13601523637 0022077 0 ustar 00root root 0000000 0000000
BluezchatbluezchatFALSE
pybluez-0.23/examples/bluezchat/bluezchat.py 0000775 0000000 0000000 00000013665 13601523637 0021306 0 ustar 00root root 0000000 0000000 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""PyBluez example bluezchat.py
A simple graphical chat client to demonstrate the use of pybluez.
Opens a l2cap socket and listens on PSM 0x1001.
Provides the ability to scan for nearby bluetooth devices and establish chat
sessions with them.
"""
import gtk
import gobject
import gtk.glade
import bluetooth
import bluetooth._bluetooth as bluez
GLADEFILE = "bluezchat.glade"
# *****************
def alert(text, buttons=gtk.BUTTONS_NONE, type=gtk.MESSAGE_INFO):
md = gtk.MessageDialog(buttons=buttons, type=type)
md.label.set_text(text)
md.run()
md.destroy()
class BluezChatGui:
def __init__(self):
self.main_window_xml = gtk.glade.XML(GLADEFILE, "bluezchat_window")
# connect our signal handlers
dic = {"on_quit_button_clicked": self.quit_button_clicked,
"on_send_button_clicked": self.send_button_clicked,
"on_chat_button_clicked": self.chat_button_clicked,
"on_scan_button_clicked": self.scan_button_clicked,
"on_devices_tv_cursor_changed": self.devices_tv_cursor_changed}
self.main_window_xml.signal_autoconnect(dic)
# prepare the floor listbox
self.devices_tv = self.main_window_xml.get_widget("devices_tv")
self.discovered = gtk.ListStore(gobject.TYPE_STRING,
gobject.TYPE_STRING)
self.devices_tv.set_model(self.discovered)
renderer = gtk.CellRendererText()
column1 = gtk.TreeViewColumn("addr", renderer, text=0)
column2 = gtk.TreeViewColumn("name", renderer, text=1)
self.devices_tv.append_column(column1)
self.devices_tv.append_column(column2)
self.quit_button = self.main_window_xml.get_widget("quit_button")
self.scan_button = self.main_window_xml.get_widget("scan_button")
self.chat_button = self.main_window_xml.get_widget("chat_button")
self.send_button = self.main_window_xml.get_widget("send_button")
self.main_text = self.main_window_xml.get_widget("main_text")
self.input_tb = self.main_window_xml.get_widget("input_tb")
self.text_buffer = self.main_text.get_buffer()
self.chat_button.set_sensitive(False)
self.listed_devs = []
self.peers = {}
self.sources = {}
self.addresses = {}
# the listening sockets
self.server_sock = None
# --- gui signal handlers
def quit_button_clicked(self, widget):
gtk.main_quit()
def scan_button_clicked(self, widget):
self.quit_button.set_sensitive(False)
self.scan_button.set_sensitive(False)
# self.chat_button.set_sensitive(False)
self.discovered.clear()
for addr, name in bluetooth.discover_devices(lookup_names=True):
self.discovered.append((addr, name))
self.quit_button.set_sensitive(True)
self.scan_button.set_sensitive(True)
# self.chat_button.set_sensitive(True)
def send_button_clicked(self, widget):
text = self.input_tb.get_text()
if not text:
return
for addr, sock in list(self.peers.items()):
sock.send(text)
self.input_tb.set_text("")
self.add_text("\nme - " + text)
def chat_button_clicked(self, widget):
(model, iter) = self.devices_tv.get_selection().get_selected()
if iter is not None:
addr = model.get_value(iter, 0)
if addr not in self.peers:
self.add_text("\nconnecting to " + addr)
self.connect(addr)
else:
self.add_text("\nAlready connected to " + addr)
def devices_tv_cursor_changed(self, widget):
(model, iter) = self.devices_tv.get_selection().get_selected()
if iter is not None:
self.chat_button.set_sensitive(True)
else:
self.chat_button.set_sensitive(False)
# --- network events
def incoming_connection(self, source, condition):
sock, info = self.server_sock.accept()
address, psm = info
self.add_text("\naccepted connection from " + str(address))
# add new connection to list of peers
self.peers[address] = sock
self.addresses[sock] = address
source = gobject.io_add_watch(sock, gobject.IO_IN, self.data_ready)
self.sources[address] = source
return True
def data_ready(self, sock, condition):
address = self.addresses[sock]
data = sock.recv(1024)
if not data:
self.add_text("\nlost connection with " + address)
gobject.source_remove(self.sources[address])
del self.sources[address]
del self.peers[address]
del self.addresses[sock]
sock.close()
else:
self.add_text("\n{} - {}".format(address, str(data)))
return True
# --- other stuff
def cleanup(self):
self.hci_sock.close()
def connect(self, addr):
sock = bluetooth.BluetoothSocket(bluetooth.L2CAP)
try:
sock.connect((addr, 0x1001))
except bluez.error as e:
self.add_text("\n" + str(e))
sock.close()
return
self.peers[addr] = sock
source = gobject.io_add_watch(sock, gobject.IO_IN, self.data_ready)
self.sources[addr] = source
self.addresses[sock] = addr
def add_text(self, text):
self.text_buffer.insert(self.text_buffer.get_end_iter(), text)
def start_server(self):
self.server_sock = bluetooth.BluetoothSocket(bluetooth.L2CAP)
self.server_sock.bind(("", 0x1001))
self.server_sock.listen(1)
gobject.io_add_watch(self.server_sock, gobject.IO_IN,
self.incoming_connection)
def run(self):
self.text_buffer.insert(self.text_buffer.get_end_iter(), "loading...")
self.start_server()
gtk.main()
if __name__ == "__main__":
gui = BluezChatGui()
gui.run()
pybluez-0.23/examples/simple/ 0000775 0000000 0000000 00000000000 13601523637 0016245 5 ustar 00root root 0000000 0000000 pybluez-0.23/examples/simple/asynchronous-inquiry.py 0000664 0000000 0000000 00000004024 13601523637 0023050 0 ustar 00root root 0000000 0000000 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""PyBluez simple example asyncronous-inquiry.py
Demonstration of how to do asynchronous device discovery by subclassing
the DeviceDiscoverer class
Linux only (5/5/2006)
Author: Albert Huang
$Id: asynchronous-inquiry.py 405 2006-05-06 00:39:50Z albert $
"""
import select
import bluetooth
class MyDiscoverer(bluetooth.DeviceDiscoverer):
def pre_inquiry(self):
self.done = False
def device_discovered(self, address, device_class, rssi, name):
print("{} - {}".format(address, name))
# get some information out of the device class and display it.
# voodoo magic specified at:
# https://www.bluetooth.org/foundry/assignnumb/document/baseband
major_classes = ("Miscellaneous",
"Computer",
"Phone",
"LAN/Network Access Point",
"Audio/Video",
"Peripheral",
"Imaging")
major_class = (device_class >> 8) & 0xf
if major_class < 7:
print(" " + major_classes[major_class])
else:
print(" Uncategorized")
print(" Services:")
service_classes = ((16, "positioning"),
(17, "networking"),
(18, "rendering"),
(19, "capturing"),
(20, "object transfer"),
(21, "audio"),
(22, "telephony"),
(23, "information"))
for bitpos, classname in service_classes:
if device_class & (1 << (bitpos-1)):
print(" ", classname)
print(" RSSI:", rssi)
def inquiry_complete(self):
self.done = True
d = MyDiscoverer()
d.find_devices(lookup_names=True)
readfiles = [d, ]
while True:
rfds = select.select(readfiles, [], [])[0]
if d in rfds:
d.process_event()
if d.done:
break
pybluez-0.23/examples/simple/inquiry.py 0000664 0000000 0000000 00000001340 13601523637 0020315 0 ustar 00root root 0000000 0000000 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""PyBluez simple example inquiry.py
Performs a simple device inquiry followed by a remote name request of each
discovered device
Author: Albert Huang
$Id: inquiry.py 401 2006-05-05 19:07:48Z albert $
"""
import bluetooth
print("Performing inquiry...")
nearby_devices = bluetooth.discover_devices(duration=8, lookup_names=True,
flush_cache=True, lookup_class=False)
print("Found {} devices".format(len(nearby_devices)))
for addr, name in nearby_devices:
try:
print(" {} - {}".format(addr, name))
except UnicodeEncodeError:
print(" {} - {}".format(addr, name.encode("utf-8", "replace")))
pybluez-0.23/examples/simple/l2capclient.py 0000664 0000000 0000000 00000001416 13601523637 0021021 0 ustar 00root root 0000000 0000000 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""PyBluez simple example l2capclient.py
Demo L2CAP client for bluetooth module.
$Id: l2capclient.py 524 2007-08-15 04:04:52Z albert $
"""
import sys
import bluetooth
# Python 2 compatibility
try:
input = raw_input
except NameError:
pass # Python 3
sock = bluetooth.BluetoothSocket(bluetooth.L2CAP)
if len(sys.argv) < 2:
print("Usage: l2capclient.py ")
sys.exit(2)
bt_addr = sys.argv[1]
port = 0x1001
print("Trying to connect to {} on PSM 0x{}...".format(bt_addr, port))
sock.connect((bt_addr, port))
print("Connected. Type something...")
while True:
data = input()
if not data:
break
sock.send(data)
data = sock.recv(1024)
print("Data received:", str(data))
sock.close()
pybluez-0.23/examples/simple/l2capserver.py 0000664 0000000 0000000 00000001475 13601523637 0021056 0 ustar 00root root 0000000 0000000 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""PyBluez simple example l2capserver.py
Demo L2CAP server for pybluez.
$Id: l2capserver.py 524 2007-08-15 04:04:52Z albert $
"""
import bluetooth
server_sock = bluetooth.BluetoothSocket(bluetooth.L2CAP)
port = 0x1001
server_sock.bind(("", port))
server_sock.listen(1)
#uuid = "94f39d29-7d6d-437d-973b-fba39e49d4ef"
#bluetooth.advertise_service(server_sock, "SampleServerL2CAP",
# service_id=uuid, service_classes = [uuid])
client_sock, address = server_sock.accept()
print("Accepted connection from", address)
data = client_sock.recv(1024)
print("Data received:", str(data))
while data:
client_sock.send("Echo =>", str(data))
data = client_sock.recv(1024)
print("Data received:", str(data))
client_sock.close()
server_sock.close()
pybluez-0.23/examples/simple/rfcomm-client.py 0000664 0000000 0000000 00000002465 13601523637 0021365 0 ustar 00root root 0000000 0000000 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""PyBluez simple example rfcomm-client.py
Simple demonstration of a client application that uses RFCOMM sockets intended
for use with rfcomm-server.
Author: Albert Huang
$Id: rfcomm-client.py 424 2006-08-24 03:35:54Z albert $
"""
import sys
import bluetooth
# Python 2 compatibility
try:
input = raw_input
except NameError:
pass # Python 3
addr = None
if len(sys.argv) < 2:
print("No device specified. Searching all nearby bluetooth devices for "
"the SampleServer service...")
else:
addr = sys.argv[1]
print("Searching for SampleServer on {}...".format(addr))
# search for the SampleServer service
uuid = "94f39d29-7d6d-437d-973b-fba39e49d4ee"
service_matches = bluetooth.find_service(uuid=uuid, address=addr)
if len(service_matches) == 0:
print("Couldn't find the SampleServer service.")
sys.exit(0)
first_match = service_matches[0]
port = first_match["port"]
name = first_match["name"]
host = first_match["host"]
print("Connecting to \"{}\" on {}".format(name, host))
# Create the client socket
sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
sock.connect((host, port))
print("Connected. Type something...")
while True:
data = input()
if not data:
break
sock.send(data)
sock.close()
pybluez-0.23/examples/simple/rfcomm-server.py 0000664 0000000 0000000 00000002264 13601523637 0021412 0 ustar 00root root 0000000 0000000 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""PyBluez simple example rfcomm-server.py
Simple demonstration of a server application that uses RFCOMM sockets.
Author: Albert Huang
$Id: rfcomm-server.py 518 2007-08-10 07:20:07Z albert $
"""
import bluetooth
server_sock = bluetooth.BluetoothSocket(bluetooth.RFCOMM)
server_sock.bind(("", bluetooth.PORT_ANY))
server_sock.listen(1)
port = server_sock.getsockname()[1]
uuid = "94f39d29-7d6d-437d-973b-fba39e49d4ee"
bluetooth.advertise_service(server_sock, "SampleServer", service_id=uuid,
service_classes=[uuid, bluetooth.SERIAL_PORT_CLASS],
profiles=[bluetooth.SERIAL_PORT_PROFILE],
# protocols=[bluetooth.OBEX_UUID]
)
print("Waiting for connection on RFCOMM channel", port)
client_sock, client_info = server_sock.accept()
print("Accepted connection from", client_info)
try:
while True:
data = client_sock.recv(1024)
if not data:
break
print("Received", data)
except IOError:
pass
print("Disconnected.")
client_sock.close()
server_sock.close()
print("All done.")
pybluez-0.23/examples/simple/sdp-browse.py 0000664 0000000 0000000 00000002156 13601523637 0020710 0 ustar 00root root 0000000 0000000 #!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""PyBluez simple example sdp-browse.py
Displays services being advertised on a specified bluetooth device.
Author: Albert Huang
$Id: sdp-browse.py 393 2006-02-24 20:30:15Z albert $
"""
import sys
import bluetooth
if len(sys.argv) < 2:
print("Usage: sdp-browse.py ")
print(" addr - can be a bluetooth address, \"localhost\", or \"all\"")
sys.exit(2)
target = sys.argv[1]
if target == "all":
target = None
services = bluetooth.find_service(address=target)
if len(services) > 0:
print("Found {} services on {}.".format(len(services), sys.argv[1]))
else:
print("No services found.")
for svc in services:
print("\nService Name:", svc["name"])
print(" Host: ", svc["host"])
print(" Description:", svc["description"])
print(" Provided By:", svc["provider"])
print(" Protocol: ", svc["protocol"])
print(" channel/PSM:", svc["port"])
print(" svc classes:", svc["service-classes"])
print(" profiles: ", svc["profiles"])
print(" service id: ", svc["service-id"])
pybluez-0.23/legacy_docs/ 0000775 0000000 0000000 00000000000 13601523637 0015412 5 ustar 00root root 0000000 0000000 pybluez-0.23/legacy_docs/epydoc.css 0000664 0000000 0000000 00000010456 13601523637 0017415 0 ustar 00root root 0000000 0000000
/* Body color */
body { background: #ffffff; color: #000000; }
/* Tables */
table.summary, table.details, table.index
{ background: #e8f0f8; color: #000000; }
tr.summary, tr.details, tr.index
{ background: #70b0f0; color: #000000;
text-align: left; font-size: 120%; }
tr.group { background: #c0e0f8; color: #000000;
text-align: left; font-size: 120%;
font-style: italic; }
/* Documentation page titles */
h2.module { margin-top: 0.2em; }
h2.class { margin-top: 0.2em; }
/* Headings */
h1.heading { font-size: +140%; font-style: italic;
font-weight: bold; }
h2.heading { font-size: +125%; font-style: italic;
font-weight: bold; }
h3.heading { font-size: +110%; font-style: italic;
font-weight: normal; }
/* Base tree */
pre.base-tree { font-size: 80%; margin: 0; }
/* Details Sections */
table.func-details { background: #e8f0f8; color: #000000;
border: 2px groove #c0d0d0;
padding: 0 1em 0 1em; margin: 0.4em 0 0 0; }
h3.func-detail { background: transparent; color: #000000;
margin: 0 0 1em 0; }
table.var-details { background: #e8f0f8; color: #000000;
border: 2px groove #c0d0d0;
padding: 0 1em 0 1em; margin: 0.4em 0 0 0; }
h3.var-details { background: transparent; color: #000000;
margin: 0 0 1em 0; }
/* Function signatures */
.sig { background: transparent; color: #000000;
font-weight: bold; }
.sig-name { background: transparent; color: #006080; }
.sig-arg, .sig-kwarg, .sig-vararg
{ background: transparent; color: #008060; }
.sig-default { background: transparent; color: #602000; }
.summary-sig { background: transparent; color: #000000; }
.summary-sig-name { background: transparent; color: #204080; }
.summary-sig-arg, .summary-sig-kwarg, .summary-sig-vararg
{ background: transparent; color: #008060; }
/* Doctest blocks */
.py-src { background: transparent; color: #000000; }
.py-prompt { background: transparent; color: #005050;
font-weight: bold;}
.py-string { background: transparent; color: #006030; }
.py-comment { background: transparent; color: #003060; }
.py-keyword { background: transparent; color: #600000; }
.py-output { background: transparent; color: #404040; }
pre.doctestblock { background: #f4faff; color: #000000;
padding: .5em; margin: 1em;
border: 1px solid #708890; }
table pre.doctestblock
{ background: #dce4ec; color: #000000;
padding: .5em; margin: 1em;
border: 1px solid #708890; }
/* Variable values */
pre.variable { background: #dce4ec; color: #000000;
padding: .5em; margin: 0;
border: 1px solid #708890; }
.variable-linewrap { background: transparent; color: #604000; }
.variable-ellipsis { background: transparent; color: #604000; }
.variable-quote { background: transparent; color: #604000; }
.re { background: transparent; color: #000000; }
.re-char { background: transparent; color: #006030; }
.re-op { background: transparent; color: #600000; }
.re-group { background: transparent; color: #003060; }
.re-ref { background: transparent; color: #404040; }
/* Navigation bar */
table.navbar { background: #a0c0ff; color: #0000ff;
border: 2px groove #c0d0d0; }
th.navbar { background: #a0c0ff; color: #0000ff; }
th.navselect { background: #70b0ff; color: #000000; }
.nomargin { margin: 0; }
/* Links */
a:link { background: transparent; color: #0000ff; }
a:visited { background: transparent; color: #204080; }
a.navbar:link { background: transparent; color: #0000ff;
text-decoration: none; }
a.navbar:visited { background: transparent; color: #204080;
text-decoration: none; }
/* Lists */
ul { margin-top: 0; }
pybluez-0.23/legacy_docs/index.html 0000664 0000000 0000000 00000000606 13601523637 0017411 0 ustar 00root root 0000000 0000000
API Documentation
pybluez-0.23/legacy_docs/private/ 0000775 0000000 0000000 00000000000 13601523637 0017064 5 ustar 00root root 0000000 0000000 pybluez-0.23/legacy_docs/private/bluetooth-module.html 0000664 0000000 0000000 00000367012 13601523637 0023253 0 ustar 00root root 0000000 0000000
bluetooth
advertise_service(sock,
name,
service_id,
service_classes,
profiles,
provider,
description)
Advertises a service with the local SDP server.
discover_devices(duration,
flush_cache,
lookup_names)
discover_devices( duration=8, flush_cache=True, lookup_names=False ) -> results
availability: GNU/Linux, Windows XP
performs a bluetooth device discovery using the first available bluetooth
resource.
find_service(name,
uuid,
address)
find_service( name = None, uuid = None, address = None )
Searches for SDP services that match the specified criteria and returns
the search results.
is_valid_address(address)
is_valid_address(address) -> bool
availability: GNU/Linux, Windows XP
returns True if address is a valid bluetooth address
valid address are always strings of the form XX:XX:XX:XX:XX:XX
where X is a hexadecimal character.
is_valid_uuid(uuid)
is_valid_uuid(uuid) -> bool
availability: GNU/Linux, Windows XP
returns True if uuid is a valid UUID.
lookup_name(address,
timeout)
lookup_name( address, timeout=10 ) -> name
Advertises a service with the local SDP server. sock must be a bound,
listening socket. name should be the name of the service, and service_id
(if specified) should be a string of the form
"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", where each 'X' is a hexadecimal digit.
service_classes is a list of service classes whose this service belongs to.
Each class service is a 16-bit UUID in the form "XXXX", where each 'X' is a
hexadecimal digit, or a 128-bit UUID in the form
"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX". There are some constants for
standard services, e.g. SERIAL_PORT_CLASS that equals to "1101". Some class
constants:
SERIAL_PORT_CLASS LAN_ACCESS_CLASS DIALUP_NET_CLASS
HEADSET_CLASS CORDLESS_TELEPHONY_CLASS AUDIO_SOURCE_CLASS
AUDIO_SINK_CLASS PANU_CLASS NAP_CLASS
GN_CLASS
profiles is a list of service profiles that thie service fulfills. Each
profile is a tuple with ( uuid, version ). Most standard profiles use
standard classes as UUIDs. PyBluez offers a list of standard profiles,
for example SERIAL_PORT_PROFILE. All standard profiles have the same
name as the classes, except that _CLASS suffix is replaced by _PROFILE.
provider is a text string specifying the provider of the service
description is a text string describing the service
A note on working with Symbian smartphones:
bt_discover in Python for Series 60 will only detect service records
with service class SERIAL_PORT_CLASS and profile SERIAL_PORT_PROFILE
discover_devices( duration=8, flush_cache=True, lookup_names=False ) -> results
availability: GNU/Linux, Windows XP
performs a bluetooth device discovery using the first available bluetooth
resource.
if lookup_names is False, returns a list of bluetooth addresses.
if lookup_names is True, returns a list of (address, name) tuples
duration=8
how long, in units of 1.28 seconds, to search for devices. To find as
many devices as possible, you should set this to at least 8.
This parameter only works with GNU/Linux systems
flush_cache=True
if set to False, then discover_devices may return devices found during
previous discoveries.
lookup_names=False
if set to True, then discover_devices also attempts to lookup the
display name of each detected device.
find_service(name=None,
uuid=None,
address=None)
find_service( name = None, uuid = None, address = None )
Searches for SDP services that match the specified criteria and returns
the search results. If no criteria are specified, then returns a list of
all nearby services detected. If more than one is specified, then
the search results will match all the criteria specified. If uuid is
specified, it must be either a 16-bit UUID in the form "XXXX", where each
'X' is a hexadecimal digit, or as a 128-bit UUID in the form
"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX". A special case of address is
"localhost", which will search for services on the local machine.
The search results will be a list of dictionaries. Each dictionary
represents a search match and will have the following key/value pairs:
host - the bluetooth address of the device advertising the
service
name - the name of the service being advertised
description - a description of the service being advertised
provider - the name of the person/organization providing the service
protocol - either 'RFCOMM', 'L2CAP', None if the protocol was not
specified, or 'UNKNOWN' if the protocol was specified but
unrecognized
port - the L2CAP PSM # if the protocol is 'L2CAP', the RFCOMM
channel # if the protocol is 'RFCOMM', or None if it
wasn't specified
service-classes - a list of service class IDs (UUID strings). possibly
empty
profiles - a list of profiles - (UUID, version) pairs - the
service claims to support. possibly empty.
service-id - the Service ID of the service. None if it wasn't set
See the Bluetooth spec for the difference between
Service ID and Service Class ID List
get_available_port(protocol)
deprecated. bind to port zero instead.
is_valid_address(address)
is_valid_address(address) -> bool
availability: GNU/Linux, Windows XP
returns True if address is a valid bluetooth address
valid address are always strings of the form XX:XX:XX:XX:XX:XX
where X is a hexadecimal character. For example,
01:23:45:67:89:AB is a valid address, but
IN:VA:LI:DA:DD:RE is not
is_valid_uuid(uuid)
is_valid_uuid(uuid) -> bool
availability: GNU/Linux, Windows XP
returns True if uuid is a valid UUID.
valid UUIDs are always strings taking one of the following forms:
XXXX
XXXXXXXX
XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
where each X is a hexadecimal digit (case insensitive)
lookup_name(address,
timeout=10)
lookup_name( address, timeout=10 ) -> name
availability: GNU/Linux
Tries to determine the friendly name (human readable) of the device
with the specified bluetooth address. Returns the name on success, and
None on failure.
timeout=10 how many seconds to search before giving up.
set_l2cap_mtu(sock,
mtu)
set_l2cap_mtu( sock, mtu )
availability: GNU/Linux
Adjusts the MTU for the specified L2CAP socket. This method needs to
be invoked on both sides of the connection for it to work! The default
mtu that all L2CAP connections start with is 672 bytes.
mtu must be between 48 and 65535, inclusive.
set_packet_timeout(address,
timeout)
set_packet_timeout( address, timeout )
Availability: GNU/Linux
Adjusts the ACL flush timeout for the ACL connection to the
specified device. This means that all L2CAP and RFCOMM data being sent
to that device will be dropped if not acknowledged in timeout
milliseconds (maximum 1280). A timeout of 0 means to never drop
packets.
Since this affects all Bluetooth connections to that device, and not
just those initiated by this process or PyBluez, a call to this method
requires superuser privileges.
You must have an active connection to the specified device before
invoking this method
stop_advertising(sock)
Instructs the local SDP server to stop advertising the service
associated with sock. You should typically call this right before you
close sock.
Create a new Bluetooth socket that uses the specified transport
protocol.
proto can be one of RFCOMM, L2CAP, HCI, or SCO
HCI, L2CAP, and SCO sockets are only available in GNU/Linux
accept(self)
accept() -> (BluetoothSocket, addrport)
availability: GNU/Linux, Windows XP
Wait for an incoming connection. Return a new socket representing
the connection, and the address/port of the client. For L2CAP sockets,
addport is a (host, psm) tuple. For RFCOMM sockets, addport is a (host,
channel) tuple. For SCO sockets, addrport is just a Bluetooth
address.
bind(self,
addrport)
bind(addrport)
availability: GNU/Linux, Windows XP
Bind the socket to a local adapter and port. addrport must always be a tuple.
HCI sockets: ( device number, )
device number should be 0, 1, 2, etc.
L2CAP sockets: ( host, psm )
host should be an address e.g. "01:23:45:67:89:ab"
psm should be an unsigned integer
RFCOMM sockets: ( host, channel )
SCO sockets: ( host )
close(self)
close()
availability: GNU/Linux, Windows XP
Close the socket. It cannot be used after this call.
connect(self,
addrport)
connect(addrport)
availability: GNU/Linux, Windows XP
Connect the socket to a remote device. For L2CAP sockets, addrport
is a (host,psm) tuple. For RFCOMM sockets, addrport is a (host,channel)
tuple. For SCO sockets, addrport is just the host.
dup(self)
dup() -> socket object
availability: GNU/Linux
Return a new socket object connected to the same system
resource.
fileno(self)
fileno() -> integer
availability: GNU/Linux, Windows XP
Return the integer file descriptor of the socket.
getpeername(self)
getpeername() -> address info
availability: GNU/Linux
Return the address of the remote endpoint. For HCI sockets, the
address is a device number (0, 1, 2, etc). For L2CAP sockets, the
address is a (host,psm) tuple. For RFCOMM sockets, the address is a
(host,channel) tuple. For SCO sockets, the address is just the
host.
getsockname(self)
getsockname() -> address info
availability: GNU/Linux, Windows XP Return the address of the local
endpoint.
getsockopt(self,
level,
option,
buffersize)
getsockopt(level, option[, buffersize]) -> value
availability: GNU/Linux
Get a socket option. See the Unix manual for level and option. If a
nonzero buffersize argument is given, the return value is a string of
that length; otherwise it is an integer.
gettimouet(self,
timeout)
gettimeout() -> timeout
availability: GNU/Linux
Returns the timeout in floating seconds associated with socket
operations. A timeout of None indicates that timeouts on socket
operations are disabled.
listen(self,
backlog)
listen(backlog)
availability: GNU/Linux, Windows XP
Enable a server to accept connections. The backlog argument must be
at least 1; it specifies the number of unaccepted connection that the
system will allow before refusing new connections.
makefile(self)
makefile([mode[, buffersize]]) -> file object
availability: GNU/Linux
Return a regular file object corresponding to the socket. The mode
and buffersize arguments are as for the built-in open() function.
recv(self,
buffersize,
flags=None)
recv(buffersize[, flags]) -> data
availability: GNU/Linux, Windows XP
Receive up to buffersize bytes from the socket. For the optional
flags argument, see the Unix manual. When no data is available, block
until at least one byte is available or until the remote end is closed.
When the remote end is closed and all data is read, return the empty
string.
send(self,
data,
flags=None)
send(data[, flags]) -> count
availability: GNU/Linux, Windows XP
Send a data string to the socket. For the optional flags argument,
see the Unix manual. Return the number of bytes sent; this may be less
than len(data) if the network is busy.
sendall(self,
data,
flags=None)
sendall(data[, flags])
availability: GNU/Linux
Send a data string to the socket. For the optional flags argument,
see the Unix manual. This calls send() repeatedly until all data is
sent. If an error occurs, it's impossible to tell how much data has
been sent.
setblocking(self,
blocking)
setblocking(flag)
availability: GNU/Linux
Set the socket to blocking (flag is true) or non-blocking (false).
setblocking(True) is equivalent to settimeout(None); setblocking(False)
is equivalent to settimeout(0.0).
setsockopt(self,
level,
option,
value)
setsockopt(level, option, value)
availability: GNU/Linux
Set a socket option. See the Unix manual for level and option. The
value argument can either be an integer or a string.
settimeout(self,
timeout)
settimeout(timeout)
availability: GNU/Linux
Set a timeout on socket operations. 'timeout' can be a float, giving
in seconds, or None. Setting a timeout of None disables the timeout
feature and is equivalent to setblocking(1). Setting a timeout of zero
is the same as setblocking(0).
shutdown(self,
flag)
shutdown(flag)
availability: GNU/Linux
Shut down the reading side of the socket (flag == 0), the writing
side of the socket (flag == 1), or both ends (flag == 2).
Skeleton class for finer control of the device discovery process.
To implement asynchronous device discovery (e.g. if you want to do
something *as soon as* a device is discovered), subclass DeviceDiscoverer
and override device_discovered() and inquiry_complete()
cancel_inquiry(self)
Call this method to cancel an inquiry in process.
device_discovered(self,
address,
device_class,
name)
Called when a bluetooth device is discovered.
fileno(self)
find_devices(self,
lookup_names,
duration,
flush_cache)
find_devices( lookup_names=True, service_name=None,
duration=8, flush_cache=True )
Call this method to initiate the device discovery process
lookup_names - set to True if you want to lookup the user-friendly
names for each device found.
inquiry_complete(self)
Called when an inquiry started by find_devices has completed.
pre_inquiry(self)
Called just after find_devices is invoked, but just before the inquiry
is started.
process_event(self)
Waits for one event to happen, and proceses it.
process_inquiry(self)
Repeatedly calls process_event() until the device inquiry has
completed.
Method Details
__init__(self) (Constructor)
TODO
cancel_inquiry(self)
Call this method to cancel an inquiry in process. inquiry_complete
will still be called.
Called when a bluetooth device is discovered.
address is the bluetooth address of the device
device_class is the Class of Device, as specified in [1]
passed in as a 3-byte string
name is the user-friendly name of the device if lookup_names was set
when the inquiry was started. otherwise None
This method exists to be overriden.
[1] https://www.bluetooth.org/foundry/assignnumb/document/baseband
find_devices( lookup_names=True, service_name=None,
duration=8, flush_cache=True )
Call this method to initiate the device discovery process
lookup_names - set to True if you want to lookup the user-friendly
names for each device found.
service_name - set to the name of a service you're looking for.
only devices with a service of this name will be
returned in device_discovered() NOT YET IMPLEMENTED
ADVANCED PARAMETERS: (don't change these unless you know what
you're doing)
duration - the number of 1.2 second units to spend searching for
bluetooth devices. If lookup_names is True, then the
inquiry process can take a lot longer.
flush_cache - return devices discovered in previous inquiries
inquiry_complete(self)
Called when an inquiry started by find_devices has completed.
pre_inquiry(self)
Called just after find_devices is invoked, but just before the
inquiry is started.
This method exists to be overriden
process_event(self)
Waits for one event to happen, and proceses it. The event will be
either a device discovery, or an inquiry completion.
process_inquiry(self)
Repeatedly calls process_event() until the device inquiry has
completed.
This document contains the API (Application Programming Interface)
documentation for this project. Documentation for the Python
objects defined by the project is divided into separate pages for each
package, module, and class. The API documentation also includes two
pages containing information about the project as a whole: a trees
page, and an index page.
Object Documentation
Each Package Documentation page contains:
A description of the package.
A list of the modules and sub-packages contained by the
package.
A summary of the classes defined by the package.
A summary of the functions defined by the package.
A summary of the variables defined by the package.
A detailed description of each function defined by the
package.
A detailed description of each variable defined by the
package.
Each Module Documentation page contains:
A description of the module.
A summary of the classes defined by the module.
A summary of the functions defined by the module.
A summary of the variables defined by the module.
A detailed description of each function defined by the
module.
A detailed description of each variable defined by the
module.
Each Class Documentation page contains:
A class inheritance diagram.
A list of known subclasses.
A description of the class.
A summary of the methods defined by the class.
A summary of the instance variables defined by the class.
A summary of the class (static) variables defined by the
class.
A detailed description of each method defined by the
class.
A detailed description of each instance variable defined by the
class.
A detailed description of each class (static) variable defined
by the class.
Project Documentation
The Trees page contains the module and class hierarchies:
The module hierarchy lists every package and module, with
modules grouped into packages. At the top level, and within each
package, modules and sub-packages are listed alphabetically.
The class hierarchy lists every class, grouped by base
class. If a class has more than one base class, then it will be
listed under each base class. At the top level, and under each base
class, classes are listed alphabetically.
The Index page contains indices of terms and
identifiers:
The term index lists every term indexed by any object's
documentation. For each term, the index provides links to each
place where the term is indexed.
The identifier index lists the (short) name of every package,
module, class, method, function, variable, and parameter. For each
identifier, the index provides a short description, and a link to
its documentation.
The Table of Contents
The table of contents occupies the two frames on the left side of
the window. The upper-left frame displays the project
contents, and the lower-left frame displays the module
contents:
Project Contents...
API Documentation Frame
Module Contents ...
The project contents frame contains a list of all packages
and modules that are defined by the project. Clicking on an entry
will display its contents in the module contents frame. Clicking on a
special entry, labeled "Everything," will display the contents of
the entire project.
The module contents frame contains a list of every
submodule, class, type, exception, function, and variable defined by a
module or package. Clicking on an entry will display its
documentation in the API documentation frame. Clicking on the name of
the module, at the top of the frame, will display the documentation
for the module itself.
The "frames" and "no frames" buttons below the top
navigation bar can be used to control whether the table of contents is
displayed or not.
The Navigation Bar
A navigation bar is located at the top and bottom of every page.
It indicates what type of page you are currently viewing, and allows
you to go to related pages. The following table describes the labels
on the navigation bar. Note that not some labels (such as
[Parent]) are not displayed on all pages.
Label
Highlighted when...
Links to...
[Parent]
(never highlighted)
the parent of the current package
[Package]
viewing a package
the package containing the current object
[Module]
viewing a module
the module containing the current object
[Class]
viewing a class
the class containing the current object
[Trees]
viewing the trees page
the trees page
[Index]
viewing the index page
the index page
[Help]
viewing the help page
the help page
The "show private" and "hide private" buttons below
the top navigation bar can be used to control whether documentation
for private objects is displayed. Private objects are usually defined
as objects whose (short) names begin with a single underscore, but do
not end with an underscore. For example, "_x",
"__pprint", and "epydoc.epytext._tokenize"
are private objects; but "re.sub",
"__init__", and "type_" are not. However,
if a module defines the "__all__" variable, then its
contents are used to decide which objects are private.
A timestamp below the bottom navigation bar indicates when each
page was last updated.
advertise_service(sock,
name,
service_id,
service_classes,
profiles,
provider,
description)
Advertises a service with the local SDP server.
discover_devices(duration,
flush_cache,
lookup_names)
discover_devices( duration=8, flush_cache=True, lookup_names=False ) -> results
availability: GNU/Linux, Windows XP
performs a bluetooth device discovery using the first available bluetooth
resource.
find_service(name,
uuid,
address)
find_service( name = None, uuid = None, address = None )
Searches for SDP services that match the specified criteria and returns
the search results.
is_valid_address(address)
is_valid_address(address) -> bool
availability: GNU/Linux, Windows XP
returns True if address is a valid bluetooth address
valid address are always strings of the form XX:XX:XX:XX:XX:XX
where X is a hexadecimal character.
is_valid_uuid(uuid)
is_valid_uuid(uuid) -> bool
availability: GNU/Linux, Windows XP
returns True if uuid is a valid UUID.
lookup_name(address,
timeout)
lookup_name( address, timeout=10 ) -> name
Advertises a service with the local SDP server. sock must be a bound,
listening socket. name should be the name of the service, and service_id
(if specified) should be a string of the form
"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX", where each 'X' is a hexadecimal digit.
service_classes is a list of service classes whose this service belongs to.
Each class service is a 16-bit UUID in the form "XXXX", where each 'X' is a
hexadecimal digit, or a 128-bit UUID in the form
"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX". There are some constants for
standard services, e.g. SERIAL_PORT_CLASS that equals to "1101". Some class
constants:
SERIAL_PORT_CLASS LAN_ACCESS_CLASS DIALUP_NET_CLASS
HEADSET_CLASS CORDLESS_TELEPHONY_CLASS AUDIO_SOURCE_CLASS
AUDIO_SINK_CLASS PANU_CLASS NAP_CLASS
GN_CLASS
profiles is a list of service profiles that thie service fulfills. Each
profile is a tuple with ( uuid, version ). Most standard profiles use
standard classes as UUIDs. PyBluez offers a list of standard profiles,
for example SERIAL_PORT_PROFILE. All standard profiles have the same
name as the classes, except that _CLASS suffix is replaced by _PROFILE.
provider is a text string specifying the provider of the service
description is a text string describing the service
A note on working with Symbian smartphones:
bt_discover in Python for Series 60 will only detect service records
with service class SERIAL_PORT_CLASS and profile SERIAL_PORT_PROFILE
discover_devices( duration=8, flush_cache=True, lookup_names=False ) -> results
availability: GNU/Linux, Windows XP
performs a bluetooth device discovery using the first available bluetooth
resource.
if lookup_names is False, returns a list of bluetooth addresses.
if lookup_names is True, returns a list of (address, name) tuples
duration=8
how long, in units of 1.28 seconds, to search for devices. To find as
many devices as possible, you should set this to at least 8.
This parameter only works with GNU/Linux systems
flush_cache=True
if set to False, then discover_devices may return devices found during
previous discoveries.
lookup_names=False
if set to True, then discover_devices also attempts to lookup the
display name of each detected device.
find_service(name=None,
uuid=None,
address=None)
find_service( name = None, uuid = None, address = None )
Searches for SDP services that match the specified criteria and returns
the search results. If no criteria are specified, then returns a list of
all nearby services detected. If more than one is specified, then
the search results will match all the criteria specified. If uuid is
specified, it must be either a 16-bit UUID in the form "XXXX", where each
'X' is a hexadecimal digit, or as a 128-bit UUID in the form
"XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX". A special case of address is
"localhost", which will search for services on the local machine.
The search results will be a list of dictionaries. Each dictionary
represents a search match and will have the following key/value pairs:
host - the bluetooth address of the device advertising the
service
name - the name of the service being advertised
description - a description of the service being advertised
provider - the name of the person/organization providing the service
protocol - either 'RFCOMM', 'L2CAP', None if the protocol was not
specified, or 'UNKNOWN' if the protocol was specified but
unrecognized
port - the L2CAP PSM # if the protocol is 'L2CAP', the RFCOMM
channel # if the protocol is 'RFCOMM', or None if it
wasn't specified
service-classes - a list of service class IDs (UUID strings). possibly
empty
profiles - a list of profiles - (UUID, version) pairs - the
service claims to support. possibly empty.
service-id - the Service ID of the service. None if it wasn't set
See the Bluetooth spec for the difference between
Service ID and Service Class ID List
get_available_port(protocol)
deprecated. bind to port zero instead.
is_valid_address(address)
is_valid_address(address) -> bool
availability: GNU/Linux, Windows XP
returns True if address is a valid bluetooth address
valid address are always strings of the form XX:XX:XX:XX:XX:XX
where X is a hexadecimal character. For example,
01:23:45:67:89:AB is a valid address, but
IN:VA:LI:DA:DD:RE is not
is_valid_uuid(uuid)
is_valid_uuid(uuid) -> bool
availability: GNU/Linux, Windows XP
returns True if uuid is a valid UUID.
valid UUIDs are always strings taking one of the following forms:
XXXX
XXXXXXXX
XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
where each X is a hexadecimal digit (case insensitive)
lookup_name(address,
timeout=10)
lookup_name( address, timeout=10 ) -> name
availability: GNU/Linux
Tries to determine the friendly name (human readable) of the device
with the specified bluetooth address. Returns the name on success, and
None on failure.
timeout=10 how many seconds to search before giving up.
set_l2cap_mtu(sock,
mtu)
set_l2cap_mtu( sock, mtu )
availability: GNU/Linux
Adjusts the MTU for the specified L2CAP socket. This method needs to
be invoked on both sides of the connection for it to work! The default
mtu that all L2CAP connections start with is 672 bytes.
mtu must be between 48 and 65535, inclusive.
set_packet_timeout(address,
timeout)
set_packet_timeout( address, timeout )
Availability: GNU/Linux
Adjusts the ACL flush timeout for the ACL connection to the
specified device. This means that all L2CAP and RFCOMM data being sent
to that device will be dropped if not acknowledged in timeout
milliseconds (maximum 1280). A timeout of 0 means to never drop
packets.
Since this affects all Bluetooth connections to that device, and not
just those initiated by this process or PyBluez, a call to this method
requires superuser privileges.
You must have an active connection to the specified device before
invoking this method
stop_advertising(sock)
Instructs the local SDP server to stop advertising the service
associated with sock. You should typically call this right before you
close sock.
Create a new Bluetooth socket that uses the specified transport
protocol.
proto can be one of RFCOMM, L2CAP, HCI, or SCO
HCI, L2CAP, and SCO sockets are only available in GNU/Linux
accept(self)
accept() -> (BluetoothSocket, addrport)
availability: GNU/Linux, Windows XP
Wait for an incoming connection. Return a new socket representing
the connection, and the address/port of the client. For L2CAP sockets,
addport is a (host, psm) tuple. For RFCOMM sockets, addport is a (host,
channel) tuple. For SCO sockets, addrport is just a Bluetooth
address.
bind(self,
addrport)
bind(addrport)
availability: GNU/Linux, Windows XP
Bind the socket to a local adapter and port. addrport must always be a tuple.
HCI sockets: ( device number, )
device number should be 0, 1, 2, etc.
L2CAP sockets: ( host, psm )
host should be an address e.g. "01:23:45:67:89:ab"
psm should be an unsigned integer
RFCOMM sockets: ( host, channel )
SCO sockets: ( host )
close(self)
close()
availability: GNU/Linux, Windows XP
Close the socket. It cannot be used after this call.
connect(self,
addrport)
connect(addrport)
availability: GNU/Linux, Windows XP
Connect the socket to a remote device. For L2CAP sockets, addrport
is a (host,psm) tuple. For RFCOMM sockets, addrport is a (host,channel)
tuple. For SCO sockets, addrport is just the host.
dup(self)
dup() -> socket object
availability: GNU/Linux
Return a new socket object connected to the same system
resource.
fileno(self)
fileno() -> integer
availability: GNU/Linux, Windows XP
Return the integer file descriptor of the socket.
getpeername(self)
getpeername() -> address info
availability: GNU/Linux
Return the address of the remote endpoint. For HCI sockets, the
address is a device number (0, 1, 2, etc). For L2CAP sockets, the
address is a (host,psm) tuple. For RFCOMM sockets, the address is a
(host,channel) tuple. For SCO sockets, the address is just the
host.
getsockname(self)
getsockname() -> address info
availability: GNU/Linux, Windows XP Return the address of the local
endpoint.
getsockopt(self,
level,
option,
buffersize)
getsockopt(level, option[, buffersize]) -> value
availability: GNU/Linux
Get a socket option. See the Unix manual for level and option. If a
nonzero buffersize argument is given, the return value is a string of
that length; otherwise it is an integer.
gettimouet(self,
timeout)
gettimeout() -> timeout
availability: GNU/Linux
Returns the timeout in floating seconds associated with socket
operations. A timeout of None indicates that timeouts on socket
operations are disabled.
listen(self,
backlog)
listen(backlog)
availability: GNU/Linux, Windows XP
Enable a server to accept connections. The backlog argument must be
at least 1; it specifies the number of unaccepted connection that the
system will allow before refusing new connections.
makefile(self)
makefile([mode[, buffersize]]) -> file object
availability: GNU/Linux
Return a regular file object corresponding to the socket. The mode
and buffersize arguments are as for the built-in open() function.
recv(self,
buffersize,
flags=None)
recv(buffersize[, flags]) -> data
availability: GNU/Linux, Windows XP
Receive up to buffersize bytes from the socket. For the optional
flags argument, see the Unix manual. When no data is available, block
until at least one byte is available or until the remote end is closed.
When the remote end is closed and all data is read, return the empty
string.
send(self,
data,
flags=None)
send(data[, flags]) -> count
availability: GNU/Linux, Windows XP
Send a data string to the socket. For the optional flags argument,
see the Unix manual. Return the number of bytes sent; this may be less
than len(data) if the network is busy.
sendall(self,
data,
flags=None)
sendall(data[, flags])
availability: GNU/Linux
Send a data string to the socket. For the optional flags argument,
see the Unix manual. This calls send() repeatedly until all data is
sent. If an error occurs, it's impossible to tell how much data has
been sent.
setblocking(self,
blocking)
setblocking(flag)
availability: GNU/Linux
Set the socket to blocking (flag is true) or non-blocking (false).
setblocking(True) is equivalent to settimeout(None); setblocking(False)
is equivalent to settimeout(0.0).
setsockopt(self,
level,
option,
value)
setsockopt(level, option, value)
availability: GNU/Linux
Set a socket option. See the Unix manual for level and option. The
value argument can either be an integer or a string.
settimeout(self,
timeout)
settimeout(timeout)
availability: GNU/Linux
Set a timeout on socket operations. 'timeout' can be a float, giving
in seconds, or None. Setting a timeout of None disables the timeout
feature and is equivalent to setblocking(1). Setting a timeout of zero
is the same as setblocking(0).
shutdown(self,
flag)
shutdown(flag)
availability: GNU/Linux
Shut down the reading side of the socket (flag == 0), the writing
side of the socket (flag == 1), or both ends (flag == 2).
Skeleton class for finer control of the device discovery process.
To implement asynchronous device discovery (e.g. if you want to do
something *as soon as* a device is discovered), subclass DeviceDiscoverer
and override device_discovered() and inquiry_complete()
cancel_inquiry(self)
Call this method to cancel an inquiry in process.
device_discovered(self,
address,
device_class,
name)
Called when a bluetooth device is discovered.
fileno(self)
find_devices(self,
lookup_names,
duration,
flush_cache)
find_devices( lookup_names=True, service_name=None,
duration=8, flush_cache=True )
Call this method to initiate the device discovery process
lookup_names - set to True if you want to lookup the user-friendly
names for each device found.
inquiry_complete(self)
Called when an inquiry started by find_devices has completed.
pre_inquiry(self)
Called just after find_devices is invoked, but just before the inquiry
is started.
process_event(self)
Waits for one event to happen, and proceses it.
process_inquiry(self)
Repeatedly calls process_event() until the device inquiry has
completed.
Method Details
__init__(self) (Constructor)
TODO
cancel_inquiry(self)
Call this method to cancel an inquiry in process. inquiry_complete
will still be called.
Called when a bluetooth device is discovered.
address is the bluetooth address of the device
device_class is the Class of Device, as specified in [1]
passed in as a 3-byte string
name is the user-friendly name of the device if lookup_names was set
when the inquiry was started. otherwise None
This method exists to be overriden.
[1] https://www.bluetooth.org/foundry/assignnumb/document/baseband
find_devices( lookup_names=True, service_name=None,
duration=8, flush_cache=True )
Call this method to initiate the device discovery process
lookup_names - set to True if you want to lookup the user-friendly
names for each device found.
service_name - set to the name of a service you're looking for.
only devices with a service of this name will be
returned in device_discovered() NOT YET IMPLEMENTED
ADVANCED PARAMETERS: (don't change these unless you know what
you're doing)
duration - the number of 1.2 second units to spend searching for
bluetooth devices. If lookup_names is True, then the
inquiry process can take a lot longer.
flush_cache - return devices discovered in previous inquiries
inquiry_complete(self)
Called when an inquiry started by find_devices has completed.
pre_inquiry(self)
Called just after find_devices is invoked, but just before the
inquiry is started.
This method exists to be overriden
process_event(self)
Waits for one event to happen, and proceses it. The event will be
either a device discovery, or an inquiry completion.
process_inquiry(self)
Repeatedly calls process_event() until the device inquiry has
completed.
This document contains the API (Application Programming Interface)
documentation for this project. Documentation for the Python
objects defined by the project is divided into separate pages for each
package, module, and class. The API documentation also includes two
pages containing information about the project as a whole: a trees
page, and an index page.
Object Documentation
Each Package Documentation page contains:
A description of the package.
A list of the modules and sub-packages contained by the
package.
A summary of the classes defined by the package.
A summary of the functions defined by the package.
A summary of the variables defined by the package.
A detailed description of each function defined by the
package.
A detailed description of each variable defined by the
package.
Each Module Documentation page contains:
A description of the module.
A summary of the classes defined by the module.
A summary of the functions defined by the module.
A summary of the variables defined by the module.
A detailed description of each function defined by the
module.
A detailed description of each variable defined by the
module.
Each Class Documentation page contains:
A class inheritance diagram.
A list of known subclasses.
A description of the class.
A summary of the methods defined by the class.
A summary of the instance variables defined by the class.
A summary of the class (static) variables defined by the
class.
A detailed description of each method defined by the
class.
A detailed description of each instance variable defined by the
class.
A detailed description of each class (static) variable defined
by the class.
Project Documentation
The Trees page contains the module and class hierarchies:
The module hierarchy lists every package and module, with
modules grouped into packages. At the top level, and within each
package, modules and sub-packages are listed alphabetically.
The class hierarchy lists every class, grouped by base
class. If a class has more than one base class, then it will be
listed under each base class. At the top level, and under each base
class, classes are listed alphabetically.
The Index page contains indices of terms and
identifiers:
The term index lists every term indexed by any object's
documentation. For each term, the index provides links to each
place where the term is indexed.
The identifier index lists the (short) name of every package,
module, class, method, function, variable, and parameter. For each
identifier, the index provides a short description, and a link to
its documentation.
The Table of Contents
The table of contents occupies the two frames on the left side of
the window. The upper-left frame displays the project
contents, and the lower-left frame displays the module
contents:
Project Contents...
API Documentation Frame
Module Contents ...
The project contents frame contains a list of all packages
and modules that are defined by the project. Clicking on an entry
will display its contents in the module contents frame. Clicking on a
special entry, labeled "Everything," will display the contents of
the entire project.
The module contents frame contains a list of every
submodule, class, type, exception, function, and variable defined by a
module or package. Clicking on an entry will display its
documentation in the API documentation frame. Clicking on the name of
the module, at the top of the frame, will display the documentation
for the module itself.
The "frames" and "no frames" buttons below the top
navigation bar can be used to control whether the table of contents is
displayed or not.
The Navigation Bar
A navigation bar is located at the top and bottom of every page.
It indicates what type of page you are currently viewing, and allows
you to go to related pages. The following table describes the labels
on the navigation bar. Note that not some labels (such as
[Parent]) are not displayed on all pages.
Label
Highlighted when...
Links to...
[Parent]
(never highlighted)
the parent of the current package
[Package]
viewing a package
the package containing the current object
[Module]
viewing a module
the module containing the current object
[Class]
viewing a class
the class containing the current object
[Trees]
viewing the trees page
the trees page
[Index]
viewing the index page
the index page
[Help]
viewing the help page
the help page
The "show private" and "hide private" buttons below
the top navigation bar can be used to control whether documentation
for private objects is displayed. Private objects are usually defined
as objects whose (short) names begin with a single underscore, but do
not end with an underscore. For example, "_x",
"__pprint", and "epydoc.epytext._tokenize"
are private objects; but "re.sub",
"__init__", and "type_" are not. However,
if a module defines the "__all__" variable, then its
contents are used to decide which objects are private.
A timestamp below the bottom navigation bar indicates when each
page was last updated.
pybluez-0.23/macos/ 0000775 0000000 0000000 00000000000 13601523637 0014240 5 ustar 00root root 0000000 0000000 pybluez-0.23/macos/LightAquaBlue/ 0000775 0000000 0000000 00000000000 13601523637 0016727 5 ustar 00root root 0000000 0000000 pybluez-0.23/macos/LightAquaBlue/BBBluetoothChannelDelegate.h 0000664 0000000 0000000 00000003166 13601523637 0024203 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2009 Bea Lam. All rights reserved.
*
* This file is part of LightBlue.
*
* LightBlue is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LightBlue is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LightBlue. If not, see .
*/
//
// BBBluetoothChannelDelegate.h
// LightAquaBlue
//
// Provides a delegate for RFCOMM and L2CAP channels. This is only intended
// for use from the LightBlue library.
//
#include
@class IOBluetoothRFCOMMChannel;
@class IOBluetoothL2CAPChannel;
@interface BBBluetoothChannelDelegate : NSObject {
id m_delegate;
}
- (id)initWithDelegate:(id)delegate;
+ (IOReturn)synchronouslyWriteData:(NSData *)data
toRFCOMMChannel:(IOBluetoothRFCOMMChannel *)channel;
+ (IOReturn)synchronouslyWriteData:(NSData *)data
toL2CAPChannel:(IOBluetoothL2CAPChannel *)channel;
@end
/*
* These are the methods that should be implemented by the delegate of this
* delegate (very awkward, but that's what it is).
*/
@protocol BBBluetoothChannelDelegateObserver
- (void)channelData:(id)channel data:(NSData *)data;
- (void)channelClosed:(id)channel;
@end
pybluez-0.23/macos/LightAquaBlue/BBBluetoothChannelDelegate.m 0000664 0000000 0000000 00000005472 13601523637 0024212 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2009 Bea Lam. All rights reserved.
*
* This file is part of LightBlue.
*
* LightBlue is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LightBlue is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LightBlue. If not, see .
*/
//
// BBBluetoothChannelDelegate.m
// LightAquaBlue
//
#import "BBBluetoothChannelDelegate.h"
#import
#import
static SEL channelDataSelector;
static SEL channelClosedSelector;
@implementation BBBluetoothChannelDelegate
+ (void)initialize
{
channelDataSelector = @selector(channelData:data:);
channelClosedSelector = @selector(channelClosed:);
}
- (id)initWithDelegate:(id)delegate
{
self = [super init];
m_delegate = delegate;
return self;
}
- (void)rfcommChannelData:(IOBluetoothRFCOMMChannel *)rfcommChannel
data:(void *)dataPointer
length:(size_t)dataLength
{
if (m_delegate && [m_delegate respondsToSelector:channelDataSelector]) {
[m_delegate channelData:rfcommChannel
data:[NSData dataWithBytes:dataPointer length:dataLength]];
}
}
- (void)rfcommChannelClosed:(IOBluetoothRFCOMMChannel *)rfcommChannel
{
if (m_delegate && [m_delegate respondsToSelector:channelClosedSelector]) {
[m_delegate channelClosed:rfcommChannel];
}
}
- (void)l2capChannelData:(IOBluetoothL2CAPChannel *)l2capChannel
data:(void *)dataPointer
length:(size_t)dataLength
{
if (m_delegate && [m_delegate respondsToSelector:channelDataSelector]) {
[m_delegate channelData:l2capChannel
data:[NSData dataWithBytes:dataPointer length:dataLength]];
}
}
- (void)l2capChannelClosed:(IOBluetoothL2CAPChannel *)l2capChannel
{
if (m_delegate && [m_delegate respondsToSelector:channelClosedSelector]) {
[m_delegate channelClosed:l2capChannel];
}
}
+ (IOReturn)synchronouslyWriteData:(NSData *)data
toRFCOMMChannel:(IOBluetoothRFCOMMChannel *)channel
{
return [channel writeSync:(void *)[data bytes] length:[data length]];
}
+ (IOReturn)synchronouslyWriteData:(NSData *)data
toL2CAPChannel:(IOBluetoothL2CAPChannel *)channel
{
return [channel writeSync:(void *)[data bytes] length:[data length]];
}
@end
pybluez-0.23/macos/LightAquaBlue/BBBluetoothOBEXClient.h 0000664 0000000 0000000 00000030044 13601523637 0023067 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2009 Bea Lam. All rights reserved.
*
* This file is part of LightBlue.
*
* LightBlue is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LightBlue is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LightBlue. If not, see .
*/
//
// BBBluetoothOBEXClient.h
// LightAquaBlue
//
// Implements the client side of an OBEX session over a Bluetooth transport.
//
// There is an example in examples/LightAquaBlue/SimpleOBEXClient that shows
// how to use this class to connect to and send files to an OBEX server.
//
#import
#import
#import
@class OBEXSession;
@class BBOBEXHeaderSet;
@class BBOBEXRequest;
@class IOBluetoothDevice;
@class BBOBEXResponse;
@class IOBluetoothRFCOMMChannel;
@interface BBBluetoothOBEXClient : NSObject {
OBEXSession* mSession;
id mDelegate;
OBEXMaxPacketLength mMaxPacketLength;
int mLastServerResponse;
uint32_t mConnectionID;
BOOL mHasConnectionID;
BOOL mAborting;
BBOBEXRequest *mCurrentRequest;
}
/*
* Creates a BBBluetoothOBEXClient with the given . The client will
* connect to the OBEX server on the given and .
*/
- (id)initWithRemoteDeviceAddress:(const BluetoothDeviceAddress *)deviceAddress
channelID:(BluetoothRFCOMMChannelID)channelID
delegate:(id)delegate;
/*
* Sends a Connect request with the given .
*
* Returns kOBEXSuccess if the request was sent, or some other OBEXError value
* from if there was an error. The delegate is informed
* through client:didFinishConnectRequestWithError:responseCode:responseHeaders:
* when the request is finished.
*/
- (OBEXError)sendConnectRequestWithHeaders:(BBOBEXHeaderSet *)headers;
/*
* Sends a Disconnect request with the given .
*
* Returns kOBEXSuccess if the request was sent, or some other OBEXError value
* from if there was an error. The delegate is informed
* through client:didFinishDisconnectRequestWithError:responseCode:responseHeaders:
* when the request is finished.
*
* You must have already sent a Connect request; otherwise, this fails and
* return kOBEXSessionNotConnectedError.
*
* Note the Connection ID is automatically sent in the request headers if one
* was provided by the server in a previous Connect response.
*/
- (OBEXError)sendDisconnectRequestWithHeaders:(BBOBEXHeaderSet *)headers;
/*
* Sends a Put request with the given that will send the data from
* the given . (The stream must be already open, or the request
* will fail!) To send a Put-Delete request, set to nil.
*
* Returns kOBEXSuccess if the request was sent, or some other OBEXError value
* from if there was an error. The delegate is informed
* through client:didFinishPutRequestForStream:error:responseCode:responseHeaders:
* when the request is finished.
*
* You must have already sent a Connect request; otherwise, this fails and
* return kOBEXSessionNotConnectedError.
*
* Note the Connection ID is automatically sent in the request headers if one
* was provided by the server in a previous Connect response.
*/
- (OBEXError)sendPutRequestWithHeaders:(BBOBEXHeaderSet *)headers
readFromStream:(NSInputStream *)inputStream;
/*
* Sends a Get request with the given that will write received data
* to the given . (The stream must be already open, or the request
* will fail!)
*
* Returns kOBEXSuccess if the request was sent, or some other OBEXError value
* from if there was an error. The delegate is informed
* through client:didFinishGetRequestForStream:error:responseCode:responseHeaders:
* when the request is finished.
*
* You must have already sent a Connect request; otherwise, this fails and
* return kOBEXSessionNotConnectedError.
*
* Note the Connection ID is automatically sent in the request headers if one
* was provided by the server in a previous Connect response.
*/
- (OBEXError)sendGetRequestWithHeaders:(BBOBEXHeaderSet *)headers
writeToStream:(NSOutputStream *)outputStream;
/*
* Sends a SetPath request with the given . Set
* to YES if you want to move up one directory
* (i.e. "..") before changing to the directory specified in the headers. Set
* to YES if you want to create a directory
* (instead of receiving an error response) if it does not currently exist.
*
* Returns kOBEXSuccess if the request was sent, or some other OBEXError value
* from if there was an error. The delegate is informed
* through client:didFinishSetPathRequestWithError:responseCode:responseHeaders:
* when the request is finished.
*
* You must have already sent a Connect request; otherwise, this fails and
* return kOBEXSessionNotConnectedError.
*
* Note the Connection ID is automatically sent in the request headers if one
* was provided by the server in a previous Connect response.
*/
- (OBEXError)sendSetPathRequestWithHeaders:(BBOBEXHeaderSet *)headers
changeToParentDirectoryFirst:(BOOL)changeToParentDirectoryFirst
createDirectoriesIfNeeded:(BOOL)createDirectoriesIfNeeded;
/*
* Aborts the current request if a Put or Get request is currently in progress.
*
* This schedules an Abort request to be sent when possible (i.e. when the
* client next receives a server response).
*
* Returns kOBEXSuccess if the request was sent, or some other OBEXError value
* from if there was an error. The delegate is informed
* through client:didFinishAbortRequestWithError:responseCode:forStream:
* when the Abort request is finished.
*/
- (void)abortCurrentRequest;
/*
* Returns whether the OBEX session is connected (i.e. whether a Connect
* request has been sent, without a following Disconnect request).
*/
- (BOOL)isConnected;
/*
* Returns the Connection ID for the OBEX session, if one was received in a
* response to a previous Connect request.
*
* This is automatically sent by the client for each request; you do not need
* to add it to the request headers yourself.
*/
- (uint32_t)connectionID;
/*
* Returns the RFCOMM channel for the client.
*/
- (IOBluetoothRFCOMMChannel *)RFCOMMChannel;
/*
* Returns whether this client has a Connection ID.
*/
- (BOOL)hasConnectionID;
/*
* Returns the maximum packet length for the OBEX session.
*/
- (OBEXMaxPacketLength)maximumPacketLength;
/*
* Sets the client delegate to .
*/
- (void)setDelegate:(id)delegate;
/*
* Returns the delegate for this client.
*/
- (id)delegate;
/*
* Sets whether debug messages should be displayed (default is NO).
*/
+ (void)setDebug:(BOOL)debug;
@end
/*
* This informal protocol describes the methods that can be implemented for a
* BBBluetoothOBEXClient delegate.
*/
@protocol BBBluetoothOBEXClientDelegate
/*
* Called when a Connect request is completed. is set to kOBEXSuccess
* if the request finished without an error, or some other OBEXError value
* from if an error occured. contains the
* response code and headers.
*
* The only indicates whether the request was processed successfully;
* use the response code in to see whether the request was actually
* accepted by the OBEX server.
*/
- (void)client:(BBBluetoothOBEXClient *)client
didFinishConnectRequestWithError:(OBEXError)error
response:(BBOBEXResponse *)response;
/*
* Called when a Disconnect request is completed. is set to kOBEXSuccess
* if the request finished without an error, or some other OBEXError value
* from if an error occured. contains the
* response code and headers.
*
* The only indicates whether the request was processed successfully;
* use the response code in to see whether the request was actually
* accepted by the OBEX server.
*/
- (void)client:(BBBluetoothOBEXClient *)client
didFinishDisconnectRequestWithError:(OBEXError)error
response:(BBOBEXResponse *)response;
/*
* Called when a Put request is completed. is set to kOBEXSuccess
* if the request finished without an error, or some other OBEXError value
* from if an error occured. The is the
* stream originally passed to sendPutRequestWithHeaders:readFromStream:, and
* contains the response code and headers.
*
* The only indicates whether the request was processed successfully;
* use the response code in to see whether the request was actually
* accepted by the OBEX server.
*/
- (void)client:(BBBluetoothOBEXClient *)client
didFinishPutRequestForStream:(NSInputStream *)inputStream
error:(OBEXError)error
response:(BBOBEXResponse *)response;
/*
* Called each time the client sends another chunk of data to the OBEX server
* during a Put request. is the number of bytes sent.
*/
- (void)client:(BBBluetoothOBEXClient *)client
didSendDataOfLength:(NSUInteger)length;
/*
* Called each time the client receives another chunk of data from the OBEX
* server during a Get request. is the number of bytes received, and
* is the total number of bytes the client expects to receive
* for the request. is zero if the total length is unknown.
*/
- (void)client:(BBBluetoothOBEXClient *)session
didReceiveDataOfLength:(unsigned)length
ofTotalLength:(unsigned)totalLength;
/*
* Called when a Get request is completed. is set to kOBEXSuccess
* if the request finished without an error, or some other OBEXError value
* from if an error occured. The is the
* stream originally passed to sendGetRequestWithHeaders:writeToStream:, and
* contains the response code and headers.
*
* The only indicates whether the request was processed successfully;
* use the response code in to see whether the request was actually
* accepted by the OBEX server.
*/
- (void)client:(BBBluetoothOBEXClient *)client
didFinishGetRequestForStream:(NSOutputStream *)outputStream
error:(OBEXError)error
response:(BBOBEXResponse *)response;
/*
* Called when a SetPath request is completed. is set to kOBEXSuccess
* if the request finished without an error, or some other OBEXError value
* from if an error occured. contains the
* response code and headers.
*
* The only indicates whether the request was processed successfully;
* use the response code in to see whether the request was actually
* accepted by the OBEX server.
*/
- (void)client:(BBBluetoothOBEXClient *)client
didFinishSetPathRequestWithError:(OBEXError)error
response:(BBOBEXResponse *)response;
/*
* Called when an Abort request is completed following a call to
* abortCurrentRequest:. is set to kOBEXSuccess
* if the request finished without an error, or some other OBEXError value
* from if an error occured. The is the
* stream originally passed to sendPutRequestWithHeaders:readFromStream: or
* sendGetRequestWithHeaders:writeToStream:, and contains the
* response code and headers.
*
* The only indicates whether the request was processed successfully;
* use the response code in to see whether the request was actually
* accepted by the OBEX server.
*/
- (void)client:(BBBluetoothOBEXClient *)session
didAbortRequestWithStream:(NSStream *)stream
error:(OBEXError)error
response:(BBOBEXResponse *)response;
@end
pybluez-0.23/macos/LightAquaBlue/BBBluetoothOBEXClient.m 0000664 0000000 0000000 00000027636 13601523637 0023111 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2009 Bea Lam. All rights reserved.
*
* This file is part of LightBlue.
*
* LightBlue is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LightBlue is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LightBlue. If not, see .
*/
//
// BBBluetoothOBEXClient.m
// LightAquaBlue
//
#import "BBBluetoothOBEXClient.h"
#import "BBMutableOBEXHeaderSet.h"
#import "BBOBEXRequest.h"
#import
#import
#import
#import
#define DEBUG_NAME @"[BBBluetoothOBEXClient] "
static BOOL _debug = NO;
@implementation BBBluetoothOBEXClient
- (id)initWithRemoteDeviceAddress:(const BluetoothDeviceAddress *)deviceAddress
channelID:(BluetoothRFCOMMChannelID)channelID
delegate:(id)delegate;
{
self = [super init];
mSession = [[IOBluetoothOBEXSession alloc] initWithDevice:[IOBluetoothDevice deviceWithAddress:deviceAddress]
channelID:channelID];
mDelegate = delegate;
mMaxPacketLength = 0x2000;
mLastServerResponse = kOBEXResponseCodeSuccessWithFinalBit;
mConnectionID = 0;
mHasConnectionID = NO;
mAborting = NO;
mCurrentRequest = nil;
return self;
}
- (BBOBEXHeaderSet *)addConnectionIDToHeaders:(BBOBEXHeaderSet *)headers
{
if (!mHasConnectionID)
return headers;
BBMutableOBEXHeaderSet *modifiedHeaders = [BBMutableOBEXHeaderSet headerSet];
[modifiedHeaders addHeadersFromHeaderSet:headers];
[modifiedHeaders setValueForConnectionIDHeader:mConnectionID];
return modifiedHeaders;
}
- (OBEXError)sendConnectRequestWithHeaders:(BBOBEXHeaderSet *)headers
{
if (mCurrentRequest && ![mCurrentRequest isFinished])
return kOBEXSessionBusyError;
BBOBEXConnectRequest *request =
[[BBOBEXConnectRequest alloc] initWithClient:self
eventSelector:@selector(handleSessionEvent:)
session:mSession];
OBEXError status = [request beginWithHeaders:headers];
if (status == kOBEXSuccess) {
[mCurrentRequest release];
mCurrentRequest = request;
} else {
[request release];
}
return status;
}
- (OBEXError)sendDisconnectRequestWithHeaders:(BBOBEXHeaderSet *)headers
{
if (mCurrentRequest && ![mCurrentRequest isFinished])
return kOBEXSessionBusyError;
BBOBEXDisconnectRequest *request =
[[BBOBEXDisconnectRequest alloc] initWithClient:self
eventSelector:@selector(handleSessionEvent:)
session:mSession];
BBOBEXHeaderSet *realHeaders = (mHasConnectionID ?
[self addConnectionIDToHeaders:headers] : headers);
OBEXError status = [request beginWithHeaders:realHeaders];
if (status == kOBEXSuccess) {
[mCurrentRequest release];
mCurrentRequest = request;
} else {
[request release];
}
return status;
}
- (OBEXError)sendPutRequestWithHeaders:(BBOBEXHeaderSet *)headers
readFromStream:(NSInputStream *)inputStream
{
if (mCurrentRequest && ![mCurrentRequest isFinished])
return kOBEXSessionBusyError;
BBOBEXPutRequest *request =
[[BBOBEXPutRequest alloc] initWithClient:self
eventSelector:@selector(handleSessionEvent:)
session:mSession
inputStream:inputStream];
BBOBEXHeaderSet *realHeaders = (mHasConnectionID ?
[self addConnectionIDToHeaders:headers] : headers);
OBEXError status = [request beginWithHeaders:realHeaders];
if (status == kOBEXSuccess) {
[mCurrentRequest release];
mCurrentRequest = request;
} else {
[request release];
}
return status;
}
- (OBEXError)sendGetRequestWithHeaders:(BBOBEXHeaderSet *)headers
writeToStream:(NSOutputStream *)outputStream
{
if (mCurrentRequest && ![mCurrentRequest isFinished])
return kOBEXSessionBusyError;
BBOBEXGetRequest *request =
[[BBOBEXGetRequest alloc] initWithClient:self
eventSelector:@selector(handleSessionEvent:)
session:mSession
outputStream:outputStream];
BBOBEXHeaderSet *realHeaders = (mHasConnectionID ?
[self addConnectionIDToHeaders:headers] : headers);
OBEXError status = [request beginWithHeaders:realHeaders];
if (status == kOBEXSuccess) {
[mCurrentRequest release];
mCurrentRequest = request;
} else {
[request release];
}
return status;
}
- (OBEXError)sendSetPathRequestWithHeaders:(BBOBEXHeaderSet *)headers
changeToParentDirectoryFirst:(BOOL)changeToParentDirectoryFirst
createDirectoriesIfNeeded:(BOOL)createDirectoriesIfNeeded
{
if (mCurrentRequest && ![mCurrentRequest isFinished])
return kOBEXSessionBusyError;
BBOBEXSetPathRequest *request =
[[BBOBEXSetPathRequest alloc] initWithClient:self
eventSelector:@selector(handleSessionEvent:)
session:mSession
changeToParentDirectoryFirst:changeToParentDirectoryFirst
createDirectoriesIfNeeded:createDirectoriesIfNeeded];
BBOBEXHeaderSet *realHeaders = (mHasConnectionID ?
[self addConnectionIDToHeaders:headers] : headers);
OBEXError status = [request beginWithHeaders:realHeaders];
if (status == kOBEXSuccess) {
[mCurrentRequest release];
mCurrentRequest = request;
} else {
[request release];
}
return status;
}
- (void)abortCurrentRequest
{
if (_debug) NSLog(DEBUG_NAME @"[abortCurrentRequest]");
if (!mCurrentRequest || [mCurrentRequest isFinished] || mAborting)
return;
if (_debug) NSLog(DEBUG_NAME @"Aborting later...");
// Just set an abort flag -- can't send OBEXAbort right away because we
// might be in the middle of a transaction, and we must wait our turn to
// send the abort (i.e. wait until after we've received a server response)
mAborting = YES;
}
#pragma mark -
- (void)finishedCurrentRequestWithError:(OBEXError)error responseCode:(int)responseCode
{
if (_debug) NSLog(DEBUG_NAME @"[finishedCurrentRequestWithError] %d 0x%02x", error, responseCode);
mAborting = NO;
[mCurrentRequest finishedWithError:error responseCode:responseCode];
[mCurrentRequest release];
mCurrentRequest = nil;
}
- (void)performAbort
{
if (_debug) NSLog(DEBUG_NAME @"[performAbort]");
[mCurrentRequest release];
mCurrentRequest = [[BBOBEXAbortRequest alloc] initWithClient:self
eventSelector:@selector(handleSessionEvent:)
session:mSession];
OBEXError status = [mCurrentRequest beginWithHeaders:nil];
if (status != kOBEXSuccess)
[self finishedCurrentRequestWithError:status responseCode:0];
}
- (void)processResponseWithHeaders:(BBMutableOBEXHeaderSet *)responseHeaders
responseCode:(int)responseCode
{
if (_debug) NSLog(DEBUG_NAME @"processResponseWithHeaders 0x%x", responseCode);
if (responseCode == kOBEXResponseCodeContinueWithFinalBit) {
if (mAborting) {
[self performAbort];
return;
}
[mCurrentRequest receivedResponseWithHeaders:responseHeaders];
OBEXError status = [mCurrentRequest sendNextRequestPacket];
if (status != kOBEXSuccess) {
[self finishedCurrentRequestWithError:status responseCode:responseCode];
return;
}
} else {
[mCurrentRequest receivedResponseWithHeaders:responseHeaders];
mLastServerResponse = responseCode;
[self finishedCurrentRequestWithError:kOBEXSuccess responseCode:responseCode];
}
}
- (void)handleSessionEvent:(const OBEXSessionEvent *)event
{
if (_debug) NSLog(DEBUG_NAME @"[handleSessionEvent] event %d (current request=%@)",
event->type, mCurrentRequest);
if (mCurrentRequest) {
if (event->type == kOBEXSessionEventTypeError) {
if (_debug) NSLog(DEBUG_NAME @"[handleSessionEvent] error occurred %d", event->u.errorData.error);
[self finishedCurrentRequestWithError:event->u.errorData.error
responseCode:0];
return;
}
int responseCode;
BBMutableOBEXHeaderSet *responseHeaders = nil;
if ([mCurrentRequest readOBEXResponseHeaders:&responseHeaders
andResponseCode:&responseCode
fromSessionEvent:event]) {
if (!responseHeaders)
responseHeaders = [BBMutableOBEXHeaderSet headerSet];
if (event->type == kOBEXSessionEventTypeConnectCommandResponseReceived) {
// note any received connection id so it can be sent with later
// requests
if ([responseHeaders containsValueForHeader:kOBEXHeaderIDConnectionID]) {
mConnectionID = [responseHeaders valueForConnectionIDHeader];
mHasConnectionID = YES;
}
} else if (event->type == kOBEXSessionEventTypeDisconnectCommandResponseReceived) {
// disconnected, can clear connection id now
mConnectionID = 0;
mHasConnectionID = NO;
}
[self processResponseWithHeaders:responseHeaders
responseCode:responseCode];
} else {
// unable to read response / response didn't match current request
if (_debug) NSLog(DEBUG_NAME @"[handleSessionEvent] can't parse event!");
[self finishedCurrentRequestWithError:kOBEXSessionBadResponseError
responseCode:0];
}
} else {
if (_debug) NSLog(DEBUG_NAME @"ignoring event received while idle: %d",
event->type);
}
}
- (int)serverResponseForLastRequest
{
return mLastServerResponse;
}
// for internal testing
- (void)setOBEXSession:(OBEXSession *)session
{
[session retain];
[mSession release];
mSession = session;
}
- (BOOL)isConnected
{
if (mSession)
return [mSession hasOpenOBEXConnection];
return NO;
}
- (IOBluetoothRFCOMMChannel *)RFCOMMChannel
{
if (mSession && [mSession isKindOfClass:[IOBluetoothOBEXSession class]]) {
IOBluetoothOBEXSession *session = (IOBluetoothOBEXSession *)mSession;
return [session getRFCOMMChannel];
}
return nil;
}
- (uint32_t)connectionID
{
return mConnectionID;
}
- (BOOL)hasConnectionID
{
return mHasConnectionID;
}
- (OBEXMaxPacketLength)maximumPacketLength
{
return mMaxPacketLength;
}
- (void)setDelegate:(id)delegate
{
mDelegate = delegate;
}
- (id)delegate
{
return mDelegate;
}
+ (void)setDebug:(BOOL)debug
{
_debug = debug;
[BBOBEXRequest setDebug:debug];
}
- (void)dealloc
{
[mSession setEventSelector:NULL target:nil refCon:NULL];
[mCurrentRequest release];
mCurrentRequest = nil; // if client is deleted during a delegate callback
[mSession closeTransportConnection];
[mSession release];
mSession = nil;
[super dealloc];
}
@end
pybluez-0.23/macos/LightAquaBlue/BBBluetoothOBEXServer.h 0000664 0000000 0000000 00000023353 13601523637 0023124 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2009 Bea Lam. All rights reserved.
*
* This file is part of LightBlue.
*
* LightBlue is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LightBlue is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LightBlue. If not, see .
*/
//
// BBBluetoothOBEXServer.h
// LightAquaBlue
//
// Implements the server side of an OBEX session over a Bluetooth transport.
//
// Generally you will use BBBluetoothOBEXServer like this:
// 1. Call registerForChannelOpenNotifications:selector:withChannelID:direction:
// in the IOBluetoothRFCOMMChannel class in order be notified whenever
// you receive a client connection on a particular RFCOMM channel ID.
// 2. When you are notified that a client has connected, use the provided
// IOBluetoothRFCOMMChannel to create a a BBBluetoothOBEXServer
// object, and then call run: on the object to start the server.
//
// There is an example in examples/LightAquaBlue/SimpleOBEXServer that shows
// how to use this class to run a basic OBEX server session.
//
#import
#import
@class OBEXSession;
@class BBOBEXHeaderSet;
@class BBMutableOBEXHeaderSet;
@class BBOBEXRequestHandler;
@class IOBluetoothRFCOMMChannel;
@class IOBluetoothUserNotification;
@interface BBBluetoothOBEXServer : NSObject {
IOBluetoothRFCOMMChannel *mChannel;
OBEXSession *mSession;
id mDelegate;
BBOBEXRequestHandler *mCurrentRequestHandler;
IOBluetoothUserNotification *mChannelNotif;
}
/*
* Creates and returns a BBBluetoothOBEXServer.
*/
+ (id)serverWithIncomingRFCOMMChannel:(IOBluetoothRFCOMMChannel *)channel
delegate:(id)delegate;
/*
* Initialises a BBBluetoothOBEXServer that will run on the given .
* The will be notified when events occur on the server.
*/
- (id)initWithIncomingRFCOMMChannel:(IOBluetoothRFCOMMChannel *)channel
delegate:(id)delegate;
/*
* Starts the server. The server will now receive and process client requests.
*/
- (void)run;
/*
* Closes the server. It cannot be started again after this.
*/
- (void)close;
/*
* Sets to be the next response code to be sent for the current
* request.
*
* Available response codes are listed in the OBEXOpCodeResponseValues enum in
* . (Use the codes that end with "WithFinalBit".) For
* example, you could set the response code to
* kOBEXResponseCodeNotFoundWithFinalBit if a client requests a non-existent
* file.
*/
- (void)setResponseCodeForCurrentRequest:(int)responseCode;
/*
* Adds to the next response headers to be sent for the
* current request.
*
* For example, OBEX servers commonly include a "Length" header when
* responding to a Get request to indicate the size of the file to be
* transferred.
*/
- (void)addResponseHeadersForCurrentRequest:(BBOBEXHeaderSet *)responseHeaders;
/*
* Sets the server's delegate to .
*/
- (void)setDelegate:(id)delegate;
/*
* Returns the delegate for this server.
*/
- (id)delegate;
/*
* Sets whether debug messages should be displayed (default is NO).
*/
+ (void)setDebug:(BOOL)debug;
@end
/*
* This informal protocol describes the methods that can be implemented for a
* BBBluetoothOBEXServer delegate.
*
* For each type of client request, there is a "...shouldHandle..." method
* (e.g. server:shouldHandleConnectRequest:) that is called when the request
* is received. If the delegate does not implement this method for a
* particular type of request, the server will automatically refuse all
* requests of this type with a "Not Implemented" response.
*/
@protocol BBBluetoothOBEXServerDelegate
/*
* Called when an error occurs on the server. is an error code from
* and is a description of the error.
*/
- (void)server:(BBBluetoothOBEXServer *)server
errorOccurred:(OBEXError)error
description:(NSString *)description;
/*
* Called when a Connect request is received with the specified .
*
* This should return YES if the request should be allowed to continue, or NO
* if the request should be refused. (By default, a request will be refused
* with a 'Forbidden' response; call setResponseCodeForCurrentRequest: to set
* a more specific response.)
*/
- (BOOL)server:(BBBluetoothOBEXServer *)server
shouldHandleConnectRequest:(BBOBEXHeaderSet *)requestHeaders;
/*
* Called when the server finishes processing of a Connect request.
*/
- (void)serverDidHandleConnectRequest:(BBBluetoothOBEXServer *)server;
/*
* Called when a Disconnect request is received with the specified .
*
* This should return YES if the request should be allowed to continue, or NO
* if the request should be refused. (By default, a request will be refused
* with a 'Forbidden' response; call setResponseCodeForCurrentRequest: to set
* a more specific response.)
*/
- (BOOL)server:(BBBluetoothOBEXServer *)server
shouldHandleDisconnectRequest:(BBOBEXHeaderSet *)requestHeaders;
/*
* Called when the server finishes processing of a Disconnect request.
*/
- (void)serverDidHandleDisconnectRequest:(BBBluetoothOBEXServer *)server;
/*
* Called when a Put request is received with the specified .
*
* This should return an opened NSOutputStream if the request should be allowed
* to continue, or nil if the request should be refused. (By default, a request
* will be refused with a 'Forbidden' response; call
* setResponseCodeForCurrentRequest: to set a more specific response.)
*
* Note the returned stream *must* be open, or the request will fail.
*/
- (NSOutputStream *)server:(BBBluetoothOBEXServer *)server
shouldHandlePutRequest:(BBOBEXHeaderSet *)requestHeaders;
/*
* Called each time a chunk of data is received during a Put request.
* The indicates the number of bytes received, and is
* set to YES if all the data has now been received and the server is about to
* send the final response for the request.
*/
- (void)server:(BBBluetoothOBEXServer *)server
didReceiveDataOfLength:(unsigned)length
isLastPacket:(BOOL)isLastPacket;
/*
* Called when the server finishes processing of a Put request. The
* is the stream originally provided from
* server:shouldHandlePutRequest: and is set to YES if the client
* sent an Abort request to cancel the Put request before it was completed.
*/
- (void)server:(BBBluetoothOBEXServer *)server
didHandlePutRequestForStream:(NSOutputStream *)outputStream
requestWasAborted:(BOOL)aborted;
/*
* Called when a Put-Delete request is received with the specified .
*
* This should return YES if the request should be allowed to continue, or NO
* if the request should be refused. (By default, a request will be refused
* with a 'Forbidden' response; call setResponseCodeForCurrentRequest: to set
* a more specific response.)
*/
- (BOOL)server:(BBBluetoothOBEXServer *)server
shouldHandlePutDeleteRequest:(BBOBEXHeaderSet *)requestHeaders;
/*
* Called when the server finishes processing of a Put-Delete request.
*/
- (void)serverDidHandlePutDeleteRequest:(BBBluetoothOBEXServer *)server;
/*
* Called when a Get request is received with the specified .
*
* This should return an opened NSInputStream if the request should be allowed
* to continue, or nil if the request should be refused. (By default, a request
* will be refused with a 'Forbidden' response; call
* setResponseCodeForCurrentRequest: to set a more specific response.)
*
* Note the returned stream *must* be open, or the request will fail.
*/
- (NSInputStream *)server:(BBBluetoothOBEXServer *)server
shouldHandleGetRequest:(BBOBEXHeaderSet *)requestHeaders;
/*
* Called each time a chunk of data is sent during a Get request.
* The indicates the number of bytes sent.
*/
- (void)server:(BBBluetoothOBEXServer *)server
didSendDataOfLength:(NSUInteger)length;
/*
* Called when the server finishes processing of a Get request. The
* is the stream originally provided from
* server:shouldHandleGetRequest: and is set to YES if the client
* sent an Abort request to cancel the Get request before it was completed.
*/
- (void)server:(BBBluetoothOBEXServer *)server
didHandleGetRequestForStream:(NSInputStream *)inputStream
requestWasAborted:(BOOL)aborted;
/*
* Called when a SetPath request is received with the specified
* and SetPath . The first two bits of the flags are significant
* for the SetPath operation:
* - Bit 0 is set if the server should back up one level (i.e. "..")
* before applying the requested path name
* - Bit 1 is set if the server should respond with an error instead of
* creating a directory if the specified directory does not exist
*
* This should return YES if the request should be allowed to continue, or NO
* if the request should be refused. (By default, a request will be refused
* with a 'Forbidden' response; call setResponseCodeForCurrentRequest: to set
* a more specific response.)
*/
- (BOOL)server:(BBBluetoothOBEXServer *)server
shouldHandleSetPathRequest:(BBOBEXHeaderSet *)requestHeaders
withFlags:(OBEXFlags)flags;
/*
* Called when the server finishes processing of a SetPath request.
*/
- (void)serverDidHandleSetPathRequest:(BBBluetoothOBEXServer *)server;
@end
pybluez-0.23/macos/LightAquaBlue/BBBluetoothOBEXServer.m 0000664 0000000 0000000 00000020560 13601523637 0023126 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2009 Bea Lam. All rights reserved.
*
* This file is part of LightBlue.
*
* LightBlue is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LightBlue is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LightBlue. If not, see .
*/
//
// BBBluetoothOBEXServer.m
// LightAquaBlue
//
#import "BBBluetoothOBEXServer.h"
#import "BBOBEXRequestHandler.h"
#import "BBOBEXHeaderSet.h"
#import
#import
#define DEBUG_NAME @"[BBBluetoothOBEXServer] "
static BOOL _debug = NO;
@implementation BBBluetoothOBEXServer
- (void)errorOccurred:(OBEXError)error description:(NSString *)description
{
if (_debug) NSLog(DEBUG_NAME @"errorOccurred: %d description: %@", error, description);
if ([mDelegate respondsToSelector:@selector(server:errorOccurred:description:)]) {
[mDelegate server:self
errorOccurred:error
description:description];
}
}
+ (id)serverWithIncomingRFCOMMChannel:(IOBluetoothRFCOMMChannel *)channel
delegate:(id)delegate
{
return [[[BBBluetoothOBEXServer alloc] initWithIncomingRFCOMMChannel:channel
delegate:delegate] autorelease];
}
- (id)initWithIncomingRFCOMMChannel:(IOBluetoothRFCOMMChannel *)channel
delegate:(id)delegate
{
self = [super init];
mChannel = [channel retain];
mDelegate = delegate;
return self;
}
- (BBOBEXRequestHandler *)handlerForEventType:(OBEXSessionEventType)type
{
BBOBEXRequestHandler *handler = nil;
SEL selector = @selector(handleSessionEvent:);
switch (type) {
case kOBEXSessionEventTypeConnectCommandReceived:
handler = [[BBOBEXConnectRequestHandler alloc] initWithServer:self
eventSelector:selector
session:mSession];
break;
case kOBEXSessionEventTypeDisconnectCommandReceived:
handler = [[BBOBEXDisconnectRequestHandler alloc] initWithServer:self
eventSelector:selector
session:mSession];
break;
case kOBEXSessionEventTypePutCommandReceived:
handler = [[BBOBEXPutRequestHandler alloc] initWithServer:self
eventSelector:selector
session:mSession];
break;
case kOBEXSessionEventTypeGetCommandReceived:
handler = [[BBOBEXGetRequestHandler alloc] initWithServer:self
eventSelector:selector
session:mSession];
break;
case kOBEXSessionEventTypeSetPathCommandReceived:
handler = [[BBOBEXSetPathRequestHandler alloc] initWithServer:self
eventSelector:selector
session:mSession];
break;
}
[handler autorelease];
return handler;
}
- (void)channelClosed:(IOBluetoothUserNotification *)notification
channel:(IOBluetoothRFCOMMChannel *)channel
{
if (_debug) NSLog(DEBUG_NAME @"RFCOMM channel closed!");
if (mSession) {
[self errorOccurred:kOBEXSessionTransportDiedError
description:@"Bluetooth transport connection died"];
}
if (channel == mChannel)
[self close];
}
- (void)run
{
if (mChannel) {
IOBluetoothOBEXSession *session =
[IOBluetoothOBEXSession withIncomingRFCOMMChannel:mChannel
eventSelector:@selector(handleSessionEvent:)
selectorTarget:self
refCon:NULL];
mSession = [session retain];
mChannelNotif = [mChannel registerForChannelCloseNotification:self
selector:@selector(channelClosed:channel:)];
} else if (mSession) {
// for internal testing
//NSLog(@"send dummy event");
// dummy event - event selector doesn't seem to get set otherwise if
// I just call setEventSelector:target:refCon:
[mSession OBEXConnectResponse:kOBEXResponseCodeSuccessWithFinalBit
flags:0
maxPacketLength:1024
optionalHeaders:NULL
optionalHeadersLength:0
eventSelector:@selector(handleSessionEvent:)
selectorTarget:self
refCon:NULL];
}
}
- (void)close
{
if (_debug) NSLog(DEBUG_NAME @"close");
[mChannelNotif unregister];
mChannelNotif = nil;
// must set the event selector and target to NULL, otherwise the
// OBEXSession might continue to try to send us events (e.g. if there's
// a link error)
if (mSession)
[mSession setEventSelector:NULL target:nil refCon:NULL];
[mCurrentRequestHandler release];
mCurrentRequestHandler = nil;
[mChannel release];
mChannel = nil;
[mSession release];
mSession = nil;
}
- (void)setResponseCodeForCurrentRequest:(int)responseCode
{
if (mCurrentRequestHandler)
[mCurrentRequestHandler setNextResponseCode:responseCode];
}
- (void)addResponseHeadersForCurrentRequest:(BBOBEXHeaderSet *)responseHeaders
{
if (mCurrentRequestHandler)
[mCurrentRequestHandler addResponseHeaders:responseHeaders];
}
- (void)handleSessionEvent:(const OBEXSessionEvent *)event
{
if (_debug) NSLog(DEBUG_NAME @"handleSessionEvent %d", event->type);
if (event->type == kOBEXSessionEventTypeError) {
if (mCurrentRequestHandler) {
[self errorOccurred:event->u.errorData.error
description:@"Error occurred during client request"];
} else {
[self errorOccurred:event->u.errorData.error
description:@"Error occurred while server was idle"];
}
} else if (event->type == kOBEXSessionEventTypeAbortCommandReceived) {
if (mCurrentRequestHandler) {
if (_debug) NSLog(DEBUG_NAME @"Aborting current request...");
[mCurrentRequestHandler handleRequestAborted];
} else {
if (_debug) NSLog(DEBUG_NAME @"Got Abort request, but no request to abort");
// not really an error, so errorOccurred: not called
}
} else {
if (_debug) NSLog(DEBUG_NAME @"Received client request");
if (!mCurrentRequestHandler) {
mCurrentRequestHandler = [self handlerForEventType:event->type];
if (!mCurrentRequestHandler) {
[self errorOccurred:kOBEXGeneralError
description:[NSString stringWithFormat:@"Server received unknown event: %d", event->type]];
return;
}
[mCurrentRequestHandler retain];
}
if (_debug) NSLog(DEBUG_NAME @"Found handler, %@", mCurrentRequestHandler);
BOOL requestFinished = [mCurrentRequestHandler handleRequestEvent:event];
if (requestFinished) {
if (_debug) NSLog(DEBUG_NAME @"Finished request");
[mCurrentRequestHandler release];
mCurrentRequestHandler = nil;
}
}
}
- (void)setOBEXSession:(OBEXSession *)session
{
[session retain];
[mSession release];
mSession = session;
}
- (void)setDelegate:(id)delegate
{
mDelegate = delegate;
}
- (id)delegate
{
return mDelegate;
}
+ (void)setDebug:(BOOL)debug
{
_debug = debug;
[BBOBEXRequestHandler setDebug:debug];
}
- (void)dealloc
{
[self close];
[super dealloc];
}
@end
pybluez-0.23/macos/LightAquaBlue/BBLocalDevice.h 0000664 0000000 0000000 00000002650 13601523637 0021461 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2009 Bea Lam. All rights reserved.
*
* This file is part of LightBlue.
*
* LightBlue is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LightBlue is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LightBlue. If not, see .
*/
//
// BBLocalDevice.h
// LightAquaBlue
//
// Provides information about the local Bluetooth device.
//
#import
#import
@interface BBLocalDevice : NSObject {
//
}
/*
* Returns the local device name, or nil if it can't be read.
*/
+ (NSString *)getName;
/*
* Returns the local device address as a string, or nil if it can't be read.
* The address is separated by hyphens, e.g. "00-11-22-33-44-55".
*/
+ (NSString *)getAddressString;
/*
* Returns the local device's class of device, or -1 if it can't be read.
*/
+ (BluetoothClassOfDevice)getClassOfDevice;
/*
* Returns YES if the local device is available and switched on.
*/
+ (BOOL)isPoweredOn;
@end
pybluez-0.23/macos/LightAquaBlue/BBLocalDevice.m 0000664 0000000 0000000 00000002553 13601523637 0021470 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2009 Bea Lam. All rights reserved.
*
* This file is part of LightBlue.
*
* LightBlue is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LightBlue is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LightBlue. If not, see .
*/
//
// BBLocalDevice.m
// LightAquaBlue
//
#import
#import "BBLocalDevice.h"
@implementation BBLocalDevice
+ (NSString *)getName
{
return [[IOBluetoothHostController defaultController] nameAsString];
}
+ (NSString *)getAddressString
{
return [[IOBluetoothHostController defaultController] addressAsString];
}
+ (BluetoothClassOfDevice)getClassOfDevice
{
return [[IOBluetoothHostController defaultController] classOfDevice];
}
+ (BOOL)isPoweredOn
{
BluetoothHCIPowerState powerState = [IOBluetoothHostController defaultController].powerState;
return powerState == kBluetoothHCIPowerStateON;
}
@end
pybluez-0.23/macos/LightAquaBlue/BBMutableOBEXHeaderSet.h 0000664 0000000 0000000 00000011604 13601523637 0023142 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2009 Bea Lam. All rights reserved.
*
* This file is part of LightBlue.
*
* LightBlue is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LightBlue is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LightBlue. If not, see .
*/
//
// BBMutableOBEXHeaderSet.h
// LightAquaBlue
//
// A mutable version of BBOBEXHeaderSet that allows adding and removing
// of headers.
//
#import "BBOBEXHeaderSet.h"
@interface BBMutableOBEXHeaderSet : BBOBEXHeaderSet {
CFMutableDictionaryRef mMutableDict;
}
/*
* Creates and returns an empty header set.
*/
+ (id)headerSet;
/*
* Removes the header from this header set.
*/
- (void)removeValueForHeader:(uint8_t)headerID;
/*
* Sets the value for the Name header to , overriding any existing
* value for this header.
*/
- (void)setValueForNameHeader:(NSString *)name;
/*
* Sets the value for the Type header to , overriding any existing
* value for this header.
*/
- (void)setValueForTypeHeader:(NSString *)type;
/*
* Sets the value for the Length header to , overriding any existing
* value for this header.
*/
- (void)setValueForLengthHeader:(uint32_t)length;
/*
* Sets the value for the Time (0x44) header to , overriding any
* existing value for this header. Assumes is in local time.
*/
- (void)setValueForTimeHeader:(NSDate *)date;
/*
* Sets the value for the Time (0x44) header to , overriding any
* existing value for this header. If is YES, the time value is
* marked as UTC time, otherwise it is marked as local time.
*/
- (void)setValueForTimeHeader:(NSDate *)date isUTCTime:(BOOL)isUTCTime;
/*
* Sets the value for the Description header to , overriding
* any existing value for this header.
*/
- (void)setValueForDescriptionHeader:(NSString *)description;
/*
* Sets the value for the Target header to , overriding
* any existing value for this header.
*/
- (void)setValueForTargetHeader:(NSData *)target;
/*
* Sets the value for the HTTP header to , overriding
* any existing value for this header.
*/
- (void)setValueForHTTPHeader:(NSData *)http;
/*
* Sets the value for the Who header to , overriding
* any existing value for this header.
*/
- (void)setValueForWhoHeader:(NSData *)who;
/*
* Sets the value for the Connection Id header to , overriding
* any existing value for this header.
*/
- (void)setValueForConnectionIDHeader:(uint32_t)connectionID;
/*
* Sets the value for the Application Parameters header to ,
* overriding any existing value for this header.
*/
- (void)setValueForApplicationParametersHeader:(NSData *)appParameters;
/*
* Sets the value for the Authorization Challenge header to ,
* overriding any existing value for this header.
*/
- (void)setValueForAuthorizationChallengeHeader:(NSData *)authChallenge;
/*
* Sets the value for the Authorization Response header to ,
* overriding any existing value for this header.
*/
- (void)setValueForAuthorizationResponseHeader:(NSData *)authResponse;
/*
* Sets the value for the Object Class header to ,
* overriding any existing value for this header.
*/
- (void)setValueForObjectClassHeader:(NSData *)objectClass;
/*
* Sets the value for the unicode-encoded header to ,
* overriding any existing value for this header.
*/
- (void)setValue:(NSString *)value forUnicodeHeader:(uint8_t)headerID;
/*
* Sets the value for the byte-sequence-encoded header to ,
* overriding any existing value for this header.
*/
- (void)setValue:(NSData *)value forByteSequenceHeader:(uint8_t)headerID;
/*
* Sets the value for the 4-byte-header to ,
* overriding any existing value for this header.
*/
- (void)setValue:(uint32_t)value for4ByteHeader:(uint8_t)headerID;
/*
* Sets the value for the 1-byte-encoded header to ,
* overriding any existing value for this header.
*/
- (void)setValue:(uint8_t)value for1ByteHeader:(uint8_t)headerID;
/*
* Adds the headers from to this header set.
*/
- (void)addHeadersFromHeaderSet:(BBOBEXHeaderSet *)headerSet;
/*
* Adds the headers from to this header set. specifies
* the size of .
*
* Returns NO if there was an error parsing the .
*/
- (BOOL)addHeadersFromHeadersData:(const uint8_t *)headersData
length:(size_t)length;
@end
pybluez-0.23/macos/LightAquaBlue/BBMutableOBEXHeaderSet.m 0000664 0000000 0000000 00000023042 13601523637 0023146 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2009 Bea Lam. All rights reserved.
*
* This file is part of LightBlue.
*
* LightBlue is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LightBlue is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LightBlue. If not, see .
*/
//
// BBMutableOBEXHeaderSet.m
// LightAquaBlue
//
#import "BBMutableOBEXHeaderSet.h"
enum kOBEXHeaderEncoding {
kHeaderEncodingMask = 0xc0,
kHeaderEncodingUnicode = 0x00,
kHeaderEncodingByteSequence = 0x40,
kHeaderEncoding1Byte = 0x80,
kHeaderEncoding4Byte = 0xc0
};
static NSString *LOCAL_TIME_FORMAT_STRING = @"%Y%m%dT%H%M%S";
static NSString *UTC_FORMAT_STRING = @"%Y%m%dT%H%M%SZ";
@implementation BBMutableOBEXHeaderSet
+ (id)headerSet
{
return [[[BBMutableOBEXHeaderSet alloc] init] autorelease];
}
- (void)setValueForCountHeader:(uint32_t)count
{
[self setValue:count for4ByteHeader:kOBEXHeaderIDCount];
}
- (void)setValueForNameHeader:(NSString *)name
{
[self setValue:name forUnicodeHeader:kOBEXHeaderIDName];
}
- (void)setValueForTypeHeader:(NSString *)type
{
NSMutableData *data;
if ([type length] == 0) {
data = [NSMutableData data];
} else {
const char *s = [type cStringUsingEncoding:NSASCIIStringEncoding];
if (!s) // cannot be converted to ascii
return;
// add null terminator
data = [NSMutableData dataWithBytes:s
length:[type length] + 1];
[data resetBytesInRange:NSMakeRange([type length], 1)];
}
[self setValue:data forByteSequenceHeader:kOBEXHeaderIDType];
}
- (void)setValueForLengthHeader:(uint32_t)length
{
[self setValue:length for4ByteHeader:kOBEXHeaderIDLength];
}
- (void)setValueForTimeHeader:(NSDate *)date
{
[self setValueForTimeHeader:date isUTCTime:NO];
}
- (void)setValueForTimeHeader:(NSDate *)date isUTCTime:(BOOL)isUTCTime
{
NSString *dateString =
[date descriptionWithCalendarFormat: (isUTCTime ? UTC_FORMAT_STRING : LOCAL_TIME_FORMAT_STRING)
timeZone: (isUTCTime ? [NSTimeZone timeZoneWithName:@"UTC"] : [NSTimeZone localTimeZone])
locale: nil];
[self setValue:[dateString dataUsingEncoding:NSASCIIStringEncoding]
forByteSequenceHeader:kOBEXHeaderIDTimeISO];
}
- (void)setValueForDescriptionHeader:(NSString *)description
{
[self setValue:description forUnicodeHeader:kOBEXHeaderIDDescription];
}
- (void)setValueForTargetHeader:(NSData *)target
{
[self setValue:target forByteSequenceHeader:kOBEXHeaderIDTarget];
}
- (void)setValueForHTTPHeader:(NSData *)http
{
[self setValue:http forByteSequenceHeader:kOBEXHeaderIDHTTP];
}
- (void)setValueForWhoHeader:(NSData *)who
{
[self setValue:who forByteSequenceHeader:kOBEXHeaderIDWho];
}
- (void)setValueForConnectionIDHeader:(uint32_t)connectionID
{
[self setValue:connectionID for4ByteHeader:kOBEXHeaderIDConnectionID];
}
- (void)setValueForApplicationParametersHeader:(NSData *)appParameters
{
[self setValue:appParameters forByteSequenceHeader:kOBEXHeaderIDAppParameters];
}
- (void)setValueForAuthorizationChallengeHeader:(NSData *)authChallenge
{
[self setValue:authChallenge forByteSequenceHeader:kOBEXHeaderIDAuthorizationChallenge];
}
- (void)setValueForAuthorizationResponseHeader:(NSData *)authResponse
{
[self setValue:authResponse forByteSequenceHeader:kOBEXHeaderIDAuthorizationResponse];
}
- (void)setValueForObjectClassHeader:(NSData *)objectClass
{
[self setValue:objectClass forByteSequenceHeader:0x51];
}
- (void)setValue:(NSString *)value forUnicodeHeader:(uint8_t)headerID
{
if (!value || ((headerID & kHeaderEncodingMask) != kHeaderEncodingUnicode))
return;
NSNumber *key = [NSNumber numberWithUnsignedChar:headerID];
if ([mDict objectForKey:key] == nil)
[mKeys addObject:key];
[mDict setObject:value forKey:key];
}
- (void)setValue:(NSData *)value forByteSequenceHeader:(uint8_t)headerID
{
if (!value || ((headerID & kHeaderEncodingMask) != kHeaderEncodingByteSequence))
return;
NSNumber *key = [NSNumber numberWithUnsignedChar:headerID];
if ([mDict objectForKey:key] == nil)
[mKeys addObject:key];
[mDict setObject:value forKey:key];
}
- (void)setValue:(uint32_t)value for4ByteHeader:(uint8_t)headerID
{
if ((headerID & kHeaderEncodingMask) != kHeaderEncoding4Byte)
return;
NSNumber *key = [NSNumber numberWithUnsignedChar:headerID];
if ([mDict objectForKey:key] == nil)
[mKeys addObject:key];
[mDict setObject:[NSNumber numberWithUnsignedInt:value] forKey:key];
}
- (void)setValue:(uint8_t)value for1ByteHeader:(uint8_t)headerID
{
if ((headerID & kHeaderEncodingMask) != kHeaderEncoding1Byte)
return;
NSNumber *key = [NSNumber numberWithUnsignedChar:headerID];
if ([mDict objectForKey:key] == nil)
[mKeys addObject:key];
[mDict setObject:[NSNumber numberWithUnsignedChar:value] forKey:key];
}
- (void)addHeadersFromHeaderSet:(BBOBEXHeaderSet *)headerSet
{
NSDictionary *dict = [headerSet valueForKey:@"mDict"];
[mDict addEntriesFromDictionary:dict];
NSArray *keys = [headerSet allHeaders];
int i;
for (i=0; i<[keys count]; i++) {
if (![mKeys containsObject:[keys objectAtIndex:i]]) {
[mKeys addObject:[keys objectAtIndex:i]];
}
}
}
static uint16_t parseUInt16(const uint8_t *bytes)
{
uint16_t value;
memcpy((void *)&value, bytes, sizeof(value));
return NSSwapBigShortToHost(value);
}
static uint32_t parseUInt32(const uint8_t *bytes)
{
uint32_t value;
memcpy((void *)&value, bytes, sizeof(value));
return NSSwapBigIntToHost(value);
}
static NSString *parseString(const uint8_t *bytes, unsigned int length)
{
NSString *s = [[NSString alloc] initWithBytes:bytes
length:length
encoding:NSUnicodeStringEncoding];
return [s autorelease];
}
static NSData *parseData(const uint8_t *bytes, unsigned int length)
{
return [NSData dataWithBytes:bytes length:length];
}
- (BOOL)addHeadersFromHeadersData:(const uint8_t *)headersData
length:(size_t)length
{
if (length == 0) // nothing to add
return YES;
if (length == 1) // must have at least 2 headersData
return NO;
NSNumber *hi;
uint16_t hlen;
//NSLog(@"reading %d bytes", length);
int i = 0;
while (i < length) {
hi = [NSNumber numberWithUnsignedChar:headersData[i]];
//NSLog(@"Next header: %d", headersData[i]);
switch (headersData[i] & kHeaderEncodingMask) {
case kHeaderEncoding4Byte: // ID V V V V
{
//NSLog(@"\tint:");
hlen = 5;
if (i + hlen > length)
return NO;
[self setValue:parseUInt32(&headersData[i+1]) for4ByteHeader:headersData[i]];
break;
}
case kHeaderEncoding1Byte: // ID V
{
//NSLog(@"\tbyte:");
hlen = 2;
if (i + hlen > length)
return NO;
[self setValue:headersData[i+1] for1ByteHeader:headersData[i]];
break;
}
case kHeaderEncodingUnicode: // ID L L V V .. .. O O
{
//NSLog(@"\tunicode:");
if (i + 3 > length)
return NO;
hlen = parseUInt16(&headersData[i+1]);
if (i + hlen > length)
return NO;
NSString *s = nil;
if (hlen - 3 == 0) { // empty string (3 headersData is for ID + length)
s = [NSString string];
} else {
// account for 3 headersData of ID + length
s = parseString(&headersData[i+3], (hlen - 3 - 2));
}
if (!s)
return NO;
[self setValue:s forUnicodeHeader:headersData[i]];
break;
}
case kHeaderEncodingByteSequence: // ID L L V ..
{
//NSLog(@"\tbyte stream:");
if (i + 3 > length)
return NO;
hlen = parseUInt16(&headersData[i+1]);
//NSLog(@"\tbytes length: %d", hlen);
if (i + hlen > length)
return NO;
NSData *data = nil;
if (hlen - 3 == 0) {
data = [NSData data];
} else {
// account for 3 headersData of ID + length
data = parseData(&headersData[i+3], hlen-3);
}
//NSLog(@"\tread bytes");
if (!data)
return NO;
[self setValue:data forByteSequenceHeader:headersData[i]];
break;
}
}
i += hlen;
//NSLog(@"\tRead header ok, now to index %d...", i);
}
//NSLog(@"\tFinished reading headers");
return YES;
}
- (void)removeValueForHeader:(uint8_t)headerID
{
NSNumber *number = [NSNumber numberWithUnsignedChar:headerID];
[mDict removeObjectForKey:number];
[mKeys removeObject:number];
}
@end
pybluez-0.23/macos/LightAquaBlue/BBOBEXHeaderSet.h 0000664 0000000 0000000 00000011442 13601523637 0021630 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2009 Bea Lam. All rights reserved.
*
* This file is part of LightBlue.
*
* LightBlue is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LightBlue is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LightBlue. If not, see .
*/
//
// BBOBEXHeaderSet.h
// LightAquaBlue
//
// A collection of unique OBEX headers.
//
// The mutable counterpart to this class is BBMutableOBEXHeaderSet.
//
#import
#import
#import
@interface BBOBEXHeaderSet : NSObject {
NSMutableDictionary *mDict;
NSMutableArray *mKeys;
}
/*
* Creates and returns an empty header set.
*/
+ (id)headerSet;
/*
* Returns whether this header set contains the header with .
*
* Common header IDs are defined in the OBEXHeaderIdentifiers enum in
* (for example, kOBEXHeaderIDName).
*/
- (BOOL)containsValueForHeader:(uint8_t)headerID;
/*
* Returns the number of headers in this header set.
*/
- (NSUInteger)count;
/*
* Returns the "Count" header value, or 0 if the header is not present or cannot
* be read.
*/
- (unsigned int)valueForCountHeader;
/*
* Returns the value for the Name header, or nil if the header is not present or
* cannot be read.
*/
- (NSString *)valueForNameHeader;
/*
* Returns the value for the Type header, or nil if the header is not present or
* cannot be read.
*/
- (NSString *)valueForTypeHeader;
/*
* Returns the value for the Length header, or 0 if the header is not present or
* cannot be read.
*/
- (unsigned int)valueForLengthHeader;
/*
* Returns the value for the 0x44 Time header, or the 0xC4 value if the 0x44
* header is not present, or nil if neither header is present or cannot be read.
*/
- (NSDate *)valueForTimeHeader;
/*
* Returns the value for the Description header, or nil if the header is not
* present or cannot be read.
*/
- (NSString *)valueForDescriptionHeader;
/*
* Returns the value for the Target header, or nil if the header is not present
* or cannot be read.
*/
- (NSData *)valueForTargetHeader;
/*
* Returns the value for the HTTP header, or nil if the header is not present
* or cannot be read.
*/
- (NSData *)valueForHTTPHeader;
/*
* Returns the value for the Who header, or nil if the header is not present
* or cannot be read.
*/
- (NSData *)valueForWhoHeader;
/*
* Returns the value for the Connection Id header, or 0 if the header is not
* present or cannot be read.
*/
- (uint32_t)valueForConnectionIDHeader;
/*
* Returns the value for the Application Parameters header, or nil if the
* header is not present or cannot be read.
*/
- (NSData *)valueForApplicationParametersHeader;
/*
* Returns the value for the Authorization Challenge header, or nil if the
* header is not present or cannot be read.
*/
- (NSData *)valueForAuthorizationChallengeHeader;
/*
* Returns the value for the Authorization Response header, or nil if the
* header is not present or cannot be read.
*/
- (NSData *)valueForAuthorizationResponseHeader;
/*
* Returns the value for the Object Class header, or nil if the
* header is not present or cannot be read.
*/
- (NSData *)valueForObjectClassHeader;
/*
* Returns the value for the 4-byte header , or 0 if the header is
* not present or cannot be read as a 4-byte value.
*/
- (unsigned int)valueFor4ByteHeader:(uint8_t)headerID;
/*
* Returns the value for the byte-sequence header , or nil if the
* header is not present or cannot be read as a byte-sequence value.
*/
- (NSData *)valueForByteSequenceHeader:(uint8_t)headerID;
/*
* Returns the value for the 1-byte header , or 0 if the header is
* not present or cannot be read as a 1-byte value.
*/
- (uint8_t)valueFor1ByteHeader:(uint8_t)headerID;
/*
* Returns the value for the unicode header , or nil if the
* header is not present or cannot be read as a unicode value.
*/
- (NSString *)valueForUnicodeHeader:(uint8_t)headerID;
/*
* Returns all the headers in the header set as a list of NSNumber objects.
* Each NSNumber contains an unsigned char value (the header ID).
*
* The headers are returned in the order in which they were added.
*/
- (NSArray *)allHeaders;
/*
* Returns a stream of bytes that contain the headers in this header set, as
* specified by the IrOBEX specification (section 2.1).
*/
- (NSMutableData *)toBytes;
@end
pybluez-0.23/macos/LightAquaBlue/BBOBEXHeaderSet.m 0000775 0000000 0000000 00000027764 13601523637 0021656 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2009 Bea Lam. All rights reserved.
*
* This file is part of LightBlue.
*
* LightBlue is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LightBlue is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LightBlue. If not, see .
*/
//
// BBOBEXHeaderSet.m
// LightAquaBlue
//
#import "BBOBEXHeaderSet.h"
enum kOBEXHeaderEncoding {
kHeaderEncodingMask = 0xc0,
kHeaderEncodingUnicode = 0x00,
kHeaderEncodingByteSequence = 0x40,
kHeaderEncoding1Byte = 0x80,
kHeaderEncoding4Byte = 0xc0
};
static NSString *DATE_FORMAT_STRING = @"%Y%m%dT%H%M%S"; // no 'Z' at end
static const uint8_t NULL_TERMINATORS[2] = { 0x00, 0x00 };
@implementation BBOBEXHeaderSet
+ (id)headerSet
{
return [[[BBOBEXHeaderSet alloc] init] autorelease];
}
- (id)init
{
self = [super init];
mDict = [[NSMutableDictionary alloc] initWithCapacity:0];
mKeys = [[NSMutableArray alloc] initWithCapacity:0];
return self;
}
- (BOOL)containsValueForHeader:(uint8_t)headerID
{
return ([mDict objectForKey:[NSNumber numberWithUnsignedChar:headerID]] != nil);
}
#pragma mark -
- (unsigned int)valueForCountHeader
{
return [self valueFor4ByteHeader:kOBEXHeaderIDCount];
}
- (NSString *)valueForNameHeader
{
return [self valueForUnicodeHeader:kOBEXHeaderIDName];
}
- (NSString *)valueForTypeHeader
{
NSData *data = [self valueForByteSequenceHeader:kOBEXHeaderIDType];
if (!data)
return nil;
if ([data length] == 0)
return [NSString string];
const char *s = (const char *)[data bytes];
if (s[[data length]-1] == '\0') {
return [NSString stringWithCString:(const char *)[data bytes]
encoding:NSASCIIStringEncoding];
}
return [[[NSString alloc] initWithBytes:[data bytes]
length:[data length]
encoding:NSASCIIStringEncoding] autorelease];
}
- (unsigned int)valueForLengthHeader
{
return [self valueFor4ByteHeader:kOBEXHeaderIDLength];
}
- (NSDate *)valueForTimeHeader
{
NSData *data = [self valueForByteSequenceHeader:kOBEXHeaderIDTimeISO];
if (data && [data length] > 0) {
NSString *s = [[[NSString alloc] initWithBytes:[data bytes]
length:[data length]
encoding:NSASCIIStringEncoding] autorelease];
NSCalendarDate *calendarDate = nil;
if ([s characterAtIndex:[s length]-1] == 'Z') {
calendarDate = [NSCalendarDate dateWithString:[s substringToIndex:[s length]-1]
calendarFormat:DATE_FORMAT_STRING];
[calendarDate setTimeZone:[NSTimeZone timeZoneWithName:@"UTC"]];
} else {
calendarDate = [NSCalendarDate dateWithString:s
calendarFormat:DATE_FORMAT_STRING];
[calendarDate setTimeZone:[NSTimeZone localTimeZone]];
}
return calendarDate;
} else {
uint32_t time = [self valueFor4ByteHeader:kOBEXHeaderIDTime4Byte];
return [NSDate dateWithTimeIntervalSince1970:time];
}
return nil;
}
- (NSString *)valueForDescriptionHeader
{
return [self valueForUnicodeHeader:kOBEXHeaderIDDescription];
}
- (NSData *)valueForTargetHeader
{
return [self valueForByteSequenceHeader:kOBEXHeaderIDTarget];
}
- (NSData *)valueForHTTPHeader
{
return [self valueForByteSequenceHeader:kOBEXHeaderIDHTTP];
}
- (NSData *)valueForWhoHeader
{
return [self valueForByteSequenceHeader:kOBEXHeaderIDWho];
}
- (uint32_t)valueForConnectionIDHeader
{
return [self valueFor4ByteHeader:kOBEXHeaderIDConnectionID];
}
- (NSData *)valueForApplicationParametersHeader
{
return [self valueForByteSequenceHeader:kOBEXHeaderIDAppParameters];
}
- (NSData *)valueForAuthorizationChallengeHeader
{
return [self valueForByteSequenceHeader:kOBEXHeaderIDAuthorizationChallenge];
}
- (NSData *)valueForAuthorizationResponseHeader
{
return [self valueForByteSequenceHeader:kOBEXHeaderIDAuthorizationResponse];
}
- (NSData *)valueForObjectClassHeader
{
return [self valueForByteSequenceHeader:0x51];
}
#pragma mark -
- (unsigned int)valueFor4ByteHeader:(uint8_t)headerID
{
NSNumber *number = [mDict objectForKey:[NSNumber numberWithUnsignedChar:headerID]];
if (number)
return [number unsignedIntValue];
return 0;
}
- (NSData *)valueForByteSequenceHeader:(uint8_t)headerID
{
return [mDict objectForKey:[NSNumber numberWithUnsignedChar:headerID]];
}
- (uint8_t)valueFor1ByteHeader:(uint8_t)headerID
{
NSNumber *number = [mDict objectForKey:[NSNumber numberWithUnsignedChar:headerID]];
if (number)
return [number unsignedCharValue];
return 0;
}
- (NSString *)valueForUnicodeHeader:(uint8_t)headerID
{
return [mDict objectForKey:[NSNumber numberWithUnsignedChar:headerID]];
}
- (NSArray *)allHeaders
{
return mKeys;
}
#pragma mark -
static void addUInt16Bytes(uint16_t value, NSMutableData *data)
{
uint16_t swapped = NSSwapHostShortToBig(value);
[data appendBytes:&swapped length:sizeof(swapped)];
}
static NSMutableData *stringHeaderBytes(uint8_t hid, NSString *s)
{
NSMutableData *bytes = [NSMutableData dataWithBytes:&hid length:1];
if ([s length] == 0) {
addUInt16Bytes(3, bytes); // empty string == header length of 3
return bytes;
}
CFStringEncoding encoding;
#if __BIG_ENDIAN__
encoding = kCFStringEncodingUnicode;
#elif __LITTLE_ENDIAN__
encoding = kCFStringEncodingUTF16BE; // not in 10.3
#endif
CFDataRef encodedString = CFStringCreateExternalRepresentation(NULL,
(CFStringRef)s, encoding, '?');
if (encodedString) {
// CFStringCreateExternalRepresentation() may insert 2-byte BOM
if (CFDataGetLength(encodedString) >= 2) {
const uint8_t *bytePtr = CFDataGetBytePtr(encodedString);
CFIndex length = CFDataGetLength(encodedString);
if ( (bytePtr[0] == 0xFE && bytePtr[1] == 0xFF) ||
(bytePtr[0] == 0xFF && bytePtr[1] == 0xFE) ) {
bytePtr = &CFDataGetBytePtr(encodedString)[2];
length -= 2;
}
addUInt16Bytes(length + 2 + 3, bytes);
[bytes appendBytes:bytePtr
length:length];
[bytes appendBytes:NULL_TERMINATORS length:2];
}
CFRelease(encodedString);
}
return bytes;
}
static NSData *byteSequenceHeaderBytes(uint8_t hid, NSData *data)
{
NSMutableData *headerBytes = [NSMutableData dataWithBytes:&hid length:1];
uint16_t headerLength = ([data length] + 3);
addUInt16Bytes(headerLength, headerBytes);
if ([data length] == 0)
return headerBytes;
[headerBytes appendData:data];
return headerBytes;
}
static NSData *fourByteHeaderBytes(uint8_t hid, uint32_t value)
{
NSMutableData *bytes = [NSMutableData dataWithBytes:&hid length:1];
uint32_t swapped = NSSwapHostIntToBig(value);
[bytes appendBytes:&swapped length:sizeof(swapped)];
return bytes;
}
static NSData *oneByteHeaderBytes(uint8_t hid, uint8_t value)
{
NSMutableData *bytes = [NSMutableData dataWithBytes:&hid length:1];
[bytes appendBytes:&value length:1];
return bytes;
}
- (NSMutableData *)toBytes
{
if ([mDict count] == 0)
return NULL;
NSMutableData *headerBytes = [[NSMutableData alloc] initWithLength:0];
if ([self containsValueForHeader:kOBEXHeaderIDTarget]) {
NSData *bytes = nil;
NSData *target = [self valueForTargetHeader];
if (target)
bytes = byteSequenceHeaderBytes(kOBEXHeaderIDTarget, target);
if (!bytes)
return NULL;
[headerBytes appendData:bytes];
}
if ([self containsValueForHeader:kOBEXHeaderIDConnectionID]) {
NSData *bytes = fourByteHeaderBytes(kOBEXHeaderIDConnectionID,
[self valueForConnectionIDHeader]);
if (!bytes)
return NULL;
[headerBytes appendData:bytes];
}
NSArray *headers = [self allHeaders];
uint8_t rawHeaderID;
int i;
for (i=0; i<[headers count]; i++) {
rawHeaderID = [(NSNumber *)[headers objectAtIndex:i] unsignedCharValue];
//NSLog(@"--- toBytes() writing header 0x%02x", rawHeaderID);
if (rawHeaderID == kOBEXHeaderIDTarget || rawHeaderID == kOBEXHeaderIDConnectionID)
continue; // already handled these
NSData *bytes = nil;
switch (rawHeaderID & kHeaderEncodingMask) {
case kHeaderEncodingUnicode:
{
NSString *s = [self valueForUnicodeHeader:rawHeaderID];
if (!s)
return NULL;
bytes = stringHeaderBytes(rawHeaderID, s);
break;
}
case kHeaderEncodingByteSequence:
{
NSData *data = [self valueForByteSequenceHeader:rawHeaderID];
if (!data)
return NULL;
bytes = byteSequenceHeaderBytes(rawHeaderID, data);
break;
}
case kHeaderEncoding1Byte:
{
bytes = oneByteHeaderBytes(rawHeaderID, [self valueFor1ByteHeader:rawHeaderID]);
break;
}
case kHeaderEncoding4Byte:
{
bytes = fourByteHeaderBytes(rawHeaderID, [self valueFor4ByteHeader:rawHeaderID]);
break;
}
default:
return NULL;
}
if (bytes == nil)
return NULL;
[headerBytes appendData:bytes];
}
return headerBytes;
}
- (NSUInteger)count
{
return [mDict count];
}
#pragma mark -
static NSString *getHeaderDescription(uint8_t headerID)
{
switch (headerID) {
case kOBEXHeaderIDCount:
return @"Count";
case kOBEXHeaderIDName:
return @"Name";
case kOBEXHeaderIDDescription:
return @"Description";
case kOBEXHeaderIDType:
return @"Type";
case kOBEXHeaderIDLength:
return @"Length";
case kOBEXHeaderIDTimeISO:
case kOBEXHeaderIDTime4Byte:
return @"Time";
case kOBEXHeaderIDTarget:
return @"Target";
case kOBEXHeaderIDHTTP:
return @"HTTP";
case kOBEXHeaderIDBody:
return @"Body";
case kOBEXHeaderIDEndOfBody:
return @"End of Body";
case kOBEXHeaderIDWho:
return @"Who";
case kOBEXHeaderIDConnectionID:
return @"Connection ID";
case kOBEXHeaderIDAppParameters:
return @"Application Parameters";
case kOBEXHeaderIDAuthorizationChallenge:
return @"Authorization Challenge";
case kOBEXHeaderIDAuthorizationResponse:
return @"Authorization Response";
case 0x51:
return @"Object Class";
case 0x52:
return @"Session-Parameters";
case 0x93:
return @"Session-Sequence-Number";
default:
return [NSString stringWithFormat:@"0x%02x", headerID];
}
}
- (NSString *)description
{
NSMutableString *string = [NSMutableString stringWithCapacity:0];
[string appendString:@"{"];
NSNumber *n;
int i;
for (i=0; i<[mKeys count]; i++) {
n = [mKeys objectAtIndex:i];
[string appendFormat:@"%@: %@%@",
getHeaderDescription([n unsignedCharValue]),
[mDict objectForKey:n],
(i == [mKeys count]-1 ? @"" : @", ")];
}
[string appendString:@"}"];
return string;
}
- (void)dealloc
{
[mDict release];
[mKeys release];
[super dealloc];
}
@end
pybluez-0.23/macos/LightAquaBlue/BBOBEXRequest.h 0000664 0000000 0000000 00000006662 13601523637 0021424 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2009 Bea Lam. All rights reserved.
*
* This file is part of LightBlue.
*
* LightBlue is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LightBlue is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LightBlue. If not, see .
*/
//
// BBOBEXRequest.h
// LightAquaBlue
//
// These are internal classes used by BBBluetoothOBEXClient for sending OBEX
// client requests. Each BBOBEXRequest subclass encapsulates the process
// for performing a particular type of request.
//
#import
#import
@class BBBluetoothOBEXClient;
@class BBOBEXHeaderSet;
@class BBMutableOBEXHeaderSet;
@class OBEXSession;
@interface BBOBEXRequest : NSObject
{
BBBluetoothOBEXClient *mClient;
SEL mClientEventSelector;
OBEXSession *mSession;
BOOL mFinished;
BBMutableOBEXHeaderSet *mResponseHeaders;
}
+ (void)setDebug:(BOOL)debug;
- (id)initWithClient:(BBBluetoothOBEXClient *)client
eventSelector:(SEL)selector
session:(OBEXSession *)session;
- (BOOL)isFinished;
- (OBEXError)beginWithHeaders:(BBOBEXHeaderSet *)headers;
- (void)receivedResponseWithHeaders:(BBMutableOBEXHeaderSet *)responseHeaders;
- (OBEXError)sendNextRequestPacket;
- (void)finishedWithError:(OBEXError)error responseCode:(int)responseCode;
- (BOOL)readOBEXResponseHeaders:(BBMutableOBEXHeaderSet **)responseHeaders
andResponseCode:(int *)responseCode
fromSessionEvent:(const OBEXSessionEvent *)event;
@end
@interface BBOBEXConnectRequest : BBOBEXRequest
{
CFMutableDataRef mHeadersDataRef;
}
@end
@interface BBOBEXDisconnectRequest : BBOBEXRequest
{
CFMutableDataRef mHeadersDataRef;
}
@end
@interface BBOBEXPutRequest : BBOBEXRequest
{
CFMutableDataRef mHeadersDataRef;
NSMutableData *mSentBodyData;
NSInputStream *mInputStream;
}
- (id)initWithClient:(BBBluetoothOBEXClient *)client
eventSelector:(SEL)selector
session:(OBEXSession *)session
inputStream:(NSInputStream *)inputStream;
@end
@interface BBOBEXGetRequest : BBOBEXRequest
{
CFMutableDataRef mHeadersDataRef;
NSOutputStream *mOutputStream;
unsigned int mTotalGetLength;
}
- (id)initWithClient:(BBBluetoothOBEXClient *)client
eventSelector:(SEL)selector
session:(OBEXSession *)session
outputStream:(NSOutputStream *)outputStream;
@end
@interface BBOBEXSetPathRequest : BBOBEXRequest
{
CFMutableDataRef mHeadersDataRef;
OBEXFlags mRequestFlags;
}
- (id)initWithClient:(BBBluetoothOBEXClient *)client
eventSelector:(SEL)selector
session:(OBEXSession *)session
changeToParentDirectoryFirst:(BOOL)changeToParentDirectoryFirst
createDirectoriesIfNeeded:(BOOL)createDirectoriesIfNeeded;
@end
@interface BBOBEXAbortRequest : BBOBEXRequest
{
NSStream *mStream;
}
- (id)initWithClient:(BBBluetoothOBEXClient *)client
eventSelector:(SEL)selector
session:(OBEXSession *)session
currentRequestStream:(NSStream *)stream;
@end
pybluez-0.23/macos/LightAquaBlue/BBOBEXRequest.m 0000664 0000000 0000000 00000056577 13601523637 0021443 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2009 Bea Lam. All rights reserved.
*
* This file is part of LightBlue.
*
* LightBlue is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LightBlue is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LightBlue. If not, see .
*/
//
// BBOBEXRequest.m
// LightAquaBlue
//
#import "BBOBEXRequest.h"
#import "BBBluetoothOBEXClient.h"
#import "BBMutableOBEXHeaderSet.h"
#import "BBOBEXHeaderSet.h"
#import "BBOBEXResponse.h"
#import
#import
static BOOL _debug = NO;
@implementation BBOBEXRequest
+ (void)setDebug:(BOOL)debug
{
_debug = debug;
}
- (id)initWithClient:(BBBluetoothOBEXClient *)client
eventSelector:(SEL)selector
session:(OBEXSession *)session
{
self = [super init];
mClient = client; // don't retain, avoid retaining both ways
mClientEventSelector = selector;
mSession = session; // don't retain
mFinished = NO;
return self;
}
- (BOOL)isFinished
{
return mFinished;
}
- (OBEXError)beginWithHeaders:(BBOBEXHeaderSet *)headers
{
return kOBEXSuccess;
}
- (void)receivedResponseWithHeaders:(BBMutableOBEXHeaderSet *)responseHeaders
{
if (!mResponseHeaders)
mResponseHeaders = [[BBMutableOBEXHeaderSet alloc] init];
// add to current response headers
// this way we won't lose previous response headers in multi-packet
// Put & Get requests
[mResponseHeaders addHeadersFromHeaderSet:responseHeaders];
}
- (OBEXError)sendNextRequestPacket
{
return kOBEXSuccess;
}
- (void)finishedWithError:(OBEXError)error responseCode:(int)responseCode
{
}
- (BOOL)readOBEXResponseHeaders:(BBMutableOBEXHeaderSet **)responseHeaders
andResponseCode:(int *)responseCode
fromSessionEvent:(const OBEXSessionEvent *)event
{
return YES;
}
- (void)dealloc
{
[mResponseHeaders release];
[super dealloc];
}
@end
@implementation BBOBEXConnectRequest
- (OBEXError)beginWithHeaders:(BBOBEXHeaderSet *)headers
{
if (_debug) NSLog(@"[BBOBEXConnectRequest] beginWithHeaders (%lu headers)", (unsigned long)[headers count]);
CFMutableDataRef bytes = (CFMutableDataRef)[headers toBytes];
if (!bytes && [headers count] > 0)
return kOBEXInternalError;
OBEXError status = [mSession OBEXConnect:(OBEXFlags)kOBEXConnectFlagNone
maxPacketLength:[mClient maximumPacketLength]
optionalHeaders:(bytes ? (void *)CFDataGetBytePtr(bytes) : NULL)
optionalHeadersLength:(bytes ? CFDataGetLength(bytes) : 0)
eventSelector:mClientEventSelector
selectorTarget:mClient
refCon:NULL];
if (bytes)
mHeadersDataRef = bytes;
return status;
}
- (void)finishedWithError:(OBEXError)error responseCode:(int)responseCode
{
if (_debug) NSLog(@"[BBOBEXConnectRequest] finishedWithError %@: %d", [mClient delegate], error);
mFinished = YES;
if ([[mClient delegate] respondsToSelector:@selector(client:didFinishConnectRequestWithError:response:)]) {
[[mClient delegate] client:mClient
didFinishConnectRequestWithError:error
response:[BBOBEXResponse responseWithCode:responseCode headers:mResponseHeaders]];
}
}
- (BOOL)readOBEXResponseHeaders:(BBMutableOBEXHeaderSet **)responseHeaders
andResponseCode:(int *)responseCode
fromSessionEvent:(const OBEXSessionEvent *)event
{
if (event->type != kOBEXSessionEventTypeConnectCommandResponseReceived)
return NO;
const OBEXConnectCommandResponseData *resp = &event->u.connectCommandResponseData;
*responseCode = resp->serverResponseOpCode;
BBMutableOBEXHeaderSet *headers = [BBMutableOBEXHeaderSet headerSet];
if ([headers addHeadersFromHeadersData:resp->headerDataPtr
length:resp->headerDataLength]) {
*responseHeaders = headers;
}
return YES;
}
- (void)dealloc
{
if (mHeadersDataRef)
CFRelease(mHeadersDataRef);
[super dealloc];
}
@end
@implementation BBOBEXDisconnectRequest
- (OBEXError)beginWithHeaders:(BBOBEXHeaderSet *)headers
{
if (_debug) NSLog(@"[BBOBEXDisconnectRequest] beginWithHeaders (%lu headers)", (unsigned long)[headers count]);
CFMutableDataRef bytes = (CFMutableDataRef)[headers toBytes];
if (!bytes && [headers count] > 0)
return kOBEXInternalError;
OBEXError status = [mSession OBEXDisconnect:(bytes ? (void *)CFDataGetBytePtr(bytes) : NULL)
optionalHeadersLength:(bytes ? CFDataGetLength(bytes) : 0)
eventSelector:mClientEventSelector
selectorTarget:mClient
refCon:NULL];
if (bytes)
mHeadersDataRef = bytes;
return status;
}
- (void)finishedWithError:(OBEXError)error responseCode:(int)responseCode
{
if (_debug) NSLog(@"[BBOBEXDisconnectRequest] finishedWithError: %d", error);
mFinished = YES;
if ([[mClient delegate] respondsToSelector:@selector(client:didFinishDisconnectRequestWithError:response:)]) {
[[mClient delegate] client:mClient
didFinishDisconnectRequestWithError:error
response:[BBOBEXResponse responseWithCode:responseCode headers:mResponseHeaders]];
}
}
- (BOOL)readOBEXResponseHeaders:(BBMutableOBEXHeaderSet **)responseHeaders
andResponseCode:(int *)responseCode
fromSessionEvent:(const OBEXSessionEvent *)event
{
if (event->type != kOBEXSessionEventTypeDisconnectCommandResponseReceived)
return NO;
const OBEXDisconnectCommandResponseData *resp = &event->u.disconnectCommandResponseData;
*responseCode = resp->serverResponseOpCode;
BBMutableOBEXHeaderSet *headers = [BBMutableOBEXHeaderSet headerSet];
if ([headers addHeadersFromHeadersData:resp->headerDataPtr
length:resp->headerDataLength]) {
*responseHeaders = headers;
}
return YES;
}
- (void)dealloc
{
if (mHeadersDataRef)
CFRelease(mHeadersDataRef);
[super dealloc];
}
@end
@implementation BBOBEXPutRequest
- (id)initWithClient:(BBBluetoothOBEXClient *)client
eventSelector:(SEL)selector
session:(OBEXSession *)session
inputStream:(NSInputStream *)inputStream
{
self = [super initWithClient:client eventSelector:selector session:session];
mInputStream = [inputStream retain];
return self;
}
- (NSMutableData *)readNextChunkForHeaderLength:(size_t)headersLength
isLastChunk:(BOOL *)outIsLastChunk
{
if (mInputStream == nil)
return nil;
OBEXMaxPacketLength maxPacketSize =
[mSession getAvailableCommandPayloadLength:kOBEXOpCodePut];
if (maxPacketSize == 0 || headersLength > maxPacketSize)
return nil;
OBEXMaxPacketLength maxBodySize = maxPacketSize - headersLength;
NSMutableData *data = [NSMutableData dataWithLength:maxBodySize];
NSInteger len = [mInputStream read:[data mutableBytes]
maxLength:maxBodySize];
if (_debug) NSLog(@"[BBOBEXPutRequest] read %ld bytes (maxBodySize = %d)", (long)len, maxBodySize);
// is last packet if there wasn't enough body data to fill up the packet
if (len >= 0)
*outIsLastChunk = (len < maxBodySize);
[data setLength:len];
return data;
}
+ (OBEXError)appendEmptyEndOfBodyHeaderToData:(CFMutableDataRef)headerData
{
if (!headerData)
return kOBEXInternalError;
// can't see to add the data using raw bytes, so make a dictionary
// and use OBEXHeadersToBytes() to get the end of body header bytes
CFMutableDictionaryRef mutableDict = CFDictionaryCreateMutable(NULL, 1,
&kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
OBEXError status = OBEXAddBodyHeader(NULL, 0, TRUE, mutableDict);
if (status == kOBEXSuccess) {
CFMutableDataRef bodyData = OBEXHeadersToBytes(mutableDict);
if (bodyData == NULL) {
CFRelease(mutableDict);
return kOBEXGeneralError;
}
CFDataAppendBytes(headerData, CFDataGetBytePtr(bodyData),
CFDataGetLength(bodyData));
CFRelease(bodyData);
}
CFRelease(mutableDict);
return status;
}
- (OBEXError)beginWithHeaders:(BBOBEXHeaderSet *)headers
{
if (_debug) NSLog(@"[BBOBEXPutRequest] beginWithHeaders (%lu headers)", (unsigned long)[headers count]);
// there's no stream if it's a Put-Delete
// but if there is a stream, it must be open
if (mInputStream && [mInputStream streamStatus] != NSStreamStatusOpen) {
if (_debug) NSLog(@"[BBOBEXPutRequest] given input stream not opened!");
return kOBEXBadArgumentError;
}
CFMutableDataRef bytes = (CFMutableDataRef)[headers toBytes];
if (!bytes && [headers count] > 0)
return kOBEXInternalError;
BOOL isLastChunk = YES;
NSMutableData *mutableData = nil;
if (mInputStream != nil) {
mutableData = [self readNextChunkForHeaderLength:(bytes ? CFDataGetLength(bytes) : 0)
isLastChunk:&isLastChunk];
if (!mutableData) {
if (_debug) NSLog(@"[BBOBEXPutRequest] error reading from stream!");
if (bytes)
CFRelease(bytes);
return kOBEXInternalError;
}
// If zero data read, then this must be a Create-Empty (IrOBEX 3.3.3.6)
// so add an empty End-of-Body header, because OBEXPut: won't add body
// headers if bodyDataLength is zero, in which case the server will
// think it's a Put-Delete instead of a Put.
if ([mutableData length] == 0) {
if (!bytes)
bytes = CFDataCreateMutable(NULL, 0);
OBEXError status = [BBOBEXPutRequest appendEmptyEndOfBodyHeaderToData:bytes];
if (status != kOBEXSuccess) {
if (_debug) NSLog(@"[BBOBEXPutRequest] error adding empty end of body");
CFRelease(bytes);
return status;
}
}
}
OBEXError status;
status = [mSession OBEXPut:isLastChunk
headersData:(bytes ? (void*)CFDataGetBytePtr(bytes) : NULL)
headersDataLength:(bytes ? CFDataGetLength(bytes) : 0)
bodyData:(mutableData ? [mutableData mutableBytes] : NULL)
bodyDataLength:(mutableData ? [mutableData length] : 0)
eventSelector:mClientEventSelector
selectorTarget:mClient
refCon:NULL];
if (bytes)
mHeadersDataRef = bytes;
if (mutableData) {
[mutableData retain];
[mSentBodyData release];
mSentBodyData = mutableData;
if (status == kOBEXSuccess) {
if ([[mClient delegate] respondsToSelector:@selector(client:didSendDataOfLength:)]) {
[[mClient delegate] client:mClient
didSendDataOfLength:[mutableData length]];
}
}
}
return status;
}
- (OBEXError)sendNextRequestPacket
{
if (_debug) NSLog(@"[BBOBEXPutRequest] sendNextRequestPacket");
BOOL isLastChunk;
NSMutableData *mutableData = [self readNextChunkForHeaderLength:0
isLastChunk:&isLastChunk];
if (!mutableData)
return kOBEXInternalError;
OBEXError status = [mSession OBEXPut:isLastChunk
headersData:NULL
headersDataLength:0
bodyData:[mutableData mutableBytes]
bodyDataLength:[mutableData length]
eventSelector:mClientEventSelector
selectorTarget:mClient
refCon:NULL];
[mutableData retain];
[mSentBodyData release];
mSentBodyData = mutableData;
if (status == kOBEXSuccess) {
if ([[mClient delegate] respondsToSelector:@selector(client:didSendDataOfLength:)]) {
[[mClient delegate] client:mClient
didSendDataOfLength:[mutableData length]];
}
}
return status;
}
- (void)finishedWithError:(OBEXError)error responseCode:(int)responseCode
{
if (_debug) NSLog(@"[BBOBEXPutRequest] finishedWithError: %d", error);
mFinished = YES;
if ([[mClient delegate] respondsToSelector:@selector(client:didFinishPutRequestForStream:error:response:)]) {
[[mClient delegate] client:mClient
didFinishPutRequestForStream:mInputStream
error:error
response:[BBOBEXResponse responseWithCode:responseCode headers:mResponseHeaders]];
}
}
- (BOOL)readOBEXResponseHeaders:(BBMutableOBEXHeaderSet **)responseHeaders
andResponseCode:(int *)responseCode
fromSessionEvent:(const OBEXSessionEvent *)event
{
if (event->type != kOBEXSessionEventTypePutCommandResponseReceived)
return NO;
const OBEXPutCommandResponseData *resp = &event->u.putCommandResponseData;
*responseCode = resp->serverResponseOpCode;
BBMutableOBEXHeaderSet *headers = [BBMutableOBEXHeaderSet headerSet];
if ([headers addHeadersFromHeadersData:resp->headerDataPtr
length:resp->headerDataLength]) {
*responseHeaders = headers;
}
return YES;
}
- (void)dealloc
{
if (mHeadersDataRef)
CFRelease(mHeadersDataRef);
[mSentBodyData release];
[mInputStream release];
[super dealloc];
}
@end
@implementation BBOBEXGetRequest
- (id)initWithClient:(BBBluetoothOBEXClient *)client
eventSelector:(SEL)selector
session:(OBEXSession *)session
outputStream:(NSOutputStream *)outputStream
{
self = [super initWithClient:client eventSelector:selector session:session];
mOutputStream = [outputStream retain];
return self;
}
- (OBEXError)beginWithHeaders:(BBOBEXHeaderSet *)headers
{
if (_debug) NSLog(@"[BBOBEXGetRequest] beginWithHeaders (%lu headers)", (unsigned long)[headers count]);
if (mOutputStream == nil || [mOutputStream streamStatus] != NSStreamStatusOpen)
return kOBEXBadArgumentError;
mTotalGetLength = 0;
CFMutableDataRef bytes = (CFMutableDataRef)[headers toBytes];
if (!bytes && [headers count] > 0)
return kOBEXInternalError;
OBEXError status = [mSession OBEXGet:YES
headers:(bytes ? (void *)CFDataGetBytePtr(bytes) : NULL)
headersLength:(bytes ? CFDataGetLength(bytes) : 0)
eventSelector:mClientEventSelector
selectorTarget:mClient
refCon:NULL];
if (bytes)
mHeadersDataRef = bytes;
return status;
}
- (void)receivedResponseWithHeaders:(BBMutableOBEXHeaderSet *)responseHeaders
{
if (_debug) NSLog(@"[BBOBEXGetRequest] receivedResponseWithHeaders");
// don't pass body/end-of-body headers onto client delegate
NSData *bodyData = [responseHeaders valueForByteSequenceHeader:kOBEXHeaderIDBody];
NSData *endOfBodyData = [responseHeaders valueForByteSequenceHeader:kOBEXHeaderIDEndOfBody];
[responseHeaders removeValueForHeader:kOBEXHeaderIDBody];
[responseHeaders removeValueForHeader:kOBEXHeaderIDEndOfBody];
// super impl. stores response headers to pass them onto delegate later
[super receivedResponseWithHeaders:responseHeaders];
int totalBytesReceived = 0;
if (bodyData) {
if ([mOutputStream write:[bodyData bytes] maxLength:[bodyData length]] < 0)
totalBytesReceived = -1;
else
totalBytesReceived += [bodyData length];
}
if (endOfBodyData && totalBytesReceived != -1) {
if ([mOutputStream write:[endOfBodyData bytes] maxLength:[endOfBodyData length]] < 0)
totalBytesReceived = -1;
else
totalBytesReceived += [endOfBodyData length];
}
if (totalBytesReceived < 0) {
if (_debug) NSLog(@"[BBOBEXGetRequest] error writing to output stream");
return;
}
// read length (in initial headers) - ok if zero (key not present)
mTotalGetLength = [mResponseHeaders valueForLengthHeader];
if (totalBytesReceived > 0) {
if ([[mClient delegate] respondsToSelector:@selector(client:didReceiveDataOfLength:ofTotalLength:)]) {
[[mClient delegate] client:mClient
didReceiveDataOfLength:totalBytesReceived
ofTotalLength:mTotalGetLength];
}
}
}
- (OBEXError)sendNextRequestPacket
{
// Previous GET request packet was successful, and we need to send another
// packet to get more data.
return [mSession OBEXGet:YES
headers:NULL
headersLength:0
eventSelector:mClientEventSelector
selectorTarget:mClient
refCon:NULL];
}
- (void)finishedWithError:(OBEXError)error responseCode:(int)responseCode
{
if (_debug) NSLog(@"[BBOBEXGetRequest] finishedWithError: %d", error);
mFinished = YES;
if ([[mClient delegate] respondsToSelector:@selector(client:didFinishGetRequestForStream:error:response:)]) {
[[mClient delegate] client:mClient
didFinishGetRequestForStream:mOutputStream
error:error
response:[BBOBEXResponse responseWithCode:responseCode headers:mResponseHeaders]];
}
}
- (BOOL)readOBEXResponseHeaders:(BBMutableOBEXHeaderSet **)responseHeaders
andResponseCode:(int *)responseCode
fromSessionEvent:(const OBEXSessionEvent *)event
{
if (event->type != kOBEXSessionEventTypeGetCommandResponseReceived)
return NO;
const OBEXGetCommandResponseData *resp = &event->u.getCommandResponseData;
*responseCode = resp->serverResponseOpCode;
BBMutableOBEXHeaderSet *headers = [BBMutableOBEXHeaderSet headerSet];
if ([headers addHeadersFromHeadersData:resp->headerDataPtr
length:resp->headerDataLength]) {
*responseHeaders = headers;
}
return YES;
}
- (void)dealloc
{
if (mHeadersDataRef)
CFRelease(mHeadersDataRef);
[mOutputStream release];
[super dealloc];
}
@end
@implementation BBOBEXSetPathRequest
- (id)initWithClient:(BBBluetoothOBEXClient *)client
eventSelector:(SEL)selector
session:(OBEXSession *)session
changeToParentDirectoryFirst:(BOOL)changeToParentDirectoryFirst
createDirectoriesIfNeeded:(BOOL)createDirectoriesIfNeeded
{
self = [super initWithClient:client eventSelector:selector session:session];
mRequestFlags = 0;
if (changeToParentDirectoryFirst)
mRequestFlags |= 1;
if (!createDirectoriesIfNeeded)
mRequestFlags |= 2;
return self;
}
- (OBEXError)beginWithHeaders:(BBOBEXHeaderSet *)headers
{
if (_debug) NSLog(@"[BBOBEXSetPathRequest] beginWithHeaders (%lu headers)", (unsigned long)[headers count]);
CFMutableDataRef bytes = (CFMutableDataRef)[headers toBytes];
if (!bytes && [headers count] > 0)
return kOBEXInternalError;
OBEXError status = [mSession OBEXSetPath:mRequestFlags
constants:0
optionalHeaders:(bytes ? (void *)CFDataGetBytePtr(bytes) : NULL)
optionalHeadersLength:(bytes ? CFDataGetLength(bytes) : 0)
eventSelector:mClientEventSelector
selectorTarget:mClient
refCon:NULL];
if (bytes)
mHeadersDataRef = bytes;
return status;
}
- (void)finishedWithError:(OBEXError)error responseCode:(int)responseCode
{
if (_debug) NSLog(@"[BBOBEXSetPathRequest] finishedWithError: %d", error);
mFinished = YES;
if ([[mClient delegate] respondsToSelector:@selector(client:didFinishSetPathRequestWithError:response:)]) {
[[mClient delegate] client:mClient
didFinishSetPathRequestWithError:error
response:[BBOBEXResponse responseWithCode:responseCode headers:mResponseHeaders]];
}
}
- (BOOL)readOBEXResponseHeaders:(BBMutableOBEXHeaderSet **)responseHeaders
andResponseCode:(int *)responseCode
fromSessionEvent:(const OBEXSessionEvent *)event
{
if (event->type != kOBEXSessionEventTypeSetPathCommandResponseReceived)
return NO;
const OBEXSetPathCommandResponseData *resp = &event->u.setPathCommandResponseData;
*responseCode = resp->serverResponseOpCode;
BBMutableOBEXHeaderSet *headers = [BBMutableOBEXHeaderSet headerSet];
if ([headers addHeadersFromHeadersData:resp->headerDataPtr
length:resp->headerDataLength]) {
*responseHeaders = headers;
}
return YES;
}
- (void)dealloc
{
if (mHeadersDataRef)
CFRelease(mHeadersDataRef);
[super dealloc];
}
@end
@implementation BBOBEXAbortRequest
- (id)initWithClient:(BBBluetoothOBEXClient *)client
eventSelector:(SEL)selector
session:(OBEXSession *)session
currentRequestStream:(NSStream *)stream
{
self = [super initWithClient:client eventSelector:selector session:session];
mStream = [stream retain];
return self;
}
- (OBEXError)beginWithHeaders:(BBOBEXHeaderSet *)headers
{
if (_debug) NSLog(@"[BBOBEXAbortRequest] beginWithHeaders (%lu headers)", (unsigned long)[headers count]);
CFMutableDataRef bytes = (CFMutableDataRef)[headers toBytes];
if (!bytes && [headers count] > 0)
return kOBEXInternalError;
return [mSession OBEXAbort:(bytes ? (void *)CFDataGetBytePtr(bytes) : NULL)
optionalHeadersLength:(bytes ? CFDataGetLength(bytes) : 0)
eventSelector:mClientEventSelector
selectorTarget:mClient
refCon:NULL];
}
- (void)finishedWithError:(OBEXError)error responseCode:(int)responseCode
{
if (_debug) NSLog(@"[BBOBEXAbortRequest] finishedWithError: %d", error);
mFinished = YES;
if ([[mClient delegate] respondsToSelector:@selector(client:didAbortRequestWithStream:error:response:)]) {
[[mClient delegate] client:mClient
didAbortRequestWithStream:mStream
error:error
response:[BBOBEXResponse responseWithCode:responseCode headers:mResponseHeaders]];
}
}
- (BOOL)readOBEXResponseHeaders:(BBMutableOBEXHeaderSet **)responseHeaders
andResponseCode:(int *)responseCode
fromSessionEvent:(const OBEXSessionEvent *)event
{
if (event->type != kOBEXSessionEventTypeAbortCommandResponseReceived)
return NO;
const OBEXAbortCommandResponseData *resp = &event->u.abortCommandResponseData;
*responseCode = resp->serverResponseOpCode;
BBMutableOBEXHeaderSet *headers = [BBMutableOBEXHeaderSet headerSet];
if ([headers addHeadersFromHeadersData:resp->headerDataPtr
length:resp->headerDataLength]) {
*responseHeaders = headers;
}
return YES;
}
- (void)dealloc
{
[mStream release];
[super dealloc];
}
@end
pybluez-0.23/macos/LightAquaBlue/BBOBEXRequestHandler.h 0000664 0000000 0000000 00000006446 13601523637 0022722 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2009 Bea Lam. All rights reserved.
*
* This file is part of LightBlue.
*
* LightBlue is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LightBlue is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LightBlue. If not, see .
*/
//
// BBOBEXRequestHandler.h
// LightAquaBlue
//
// These are internal classes used by BBBluetoothOBEXServer for handling
// incoming client requests. Each BBOBEXRequestHandler subclass encapsulates
// the process for handling a particular type of request.
//
#import
#import
@class BBBluetoothOBEXServer;
@class BBOBEXHeaderSet;
@class BBMutableOBEXHeaderSet;
@class OBEXSession;
@interface BBOBEXRequestHandler : NSObject {
BBBluetoothOBEXServer *mServer;
SEL mServerEventSelector;
OBEXSession *mSession;
int mNextResponseCode;
BBMutableOBEXHeaderSet *mNextResponseHeaders;
}
+ (void)setDebug:(BOOL)debug;
- (id)initWithServer:(BBBluetoothOBEXServer *)server
eventSelector:(SEL)selector
session:(OBEXSession *)session;
- (void)setNextResponseCode:(int)responseCode;
- (void)addResponseHeaders:(BBOBEXHeaderSet *)responseHeaders;
- (BOOL)handleRequestEvent:(const OBEXSessionEvent *)event;
/*** for subclasses - calls errorOccurred:description: on delegate ***/
- (void)errorOccurred:(OBEXError)error
description:(NSString *)description;
/*** methods below must be overriden by subclasses, and should be regarded
as 'protected' - they don't need to be called by outside classes ***/
- (BOOL)readOBEXRequestHeaders:(BBMutableOBEXHeaderSet **)requestHeaders
andRequestFlags:(OBEXFlags *)flags
fromSessionEvent:(const OBEXSessionEvent *)event;
- (void)prepareResponseForRequestWithHeaders:(BBMutableOBEXHeaderSet *)requestHeaders
flags:(OBEXFlags)flags
isFinalRequestPacket:(BOOL)isFinalRequestPacket;
- (OBEXError)sendNextResponsePacket;
- (void)handleRequestAborted;
- (void)notifyRequestFinished;
@end
@interface BBOBEXConnectRequestHandler : BBOBEXRequestHandler {
CFMutableDataRef mHeadersDataRef;
OBEXMaxPacketLength mMaxPacketLength;
}
@end
@interface BBOBEXDisconnectRequestHandler : BBOBEXRequestHandler {
CFMutableDataRef mHeadersDataRef;
}
@end
@interface BBOBEXPutRequestHandler : BBOBEXRequestHandler {
CFMutableDataRef mHeadersDataRef;
BBMutableOBEXHeaderSet *mPreviousRequestHeaders;
NSOutputStream *mOutputStream;
BOOL mDefinitelyIsPut;
BOOL mAborted;
}
@end
@interface BBOBEXGetRequestHandler : BBOBEXRequestHandler {
CFMutableDataRef mHeadersDataRef;
NSMutableData *mSentBodyData;
NSInputStream *mInputStream;
BOOL mAborted;
}
@end
@interface BBOBEXSetPathRequestHandler : BBOBEXRequestHandler {
CFMutableDataRef mHeadersDataRef;
}
@end
pybluez-0.23/macos/LightAquaBlue/BBOBEXRequestHandler.m 0000664 0000000 0000000 00000076510 13601523637 0022726 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2009 Bea Lam. All rights reserved.
*
* This file is part of LightBlue.
*
* LightBlue is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LightBlue is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LightBlue. If not, see .
*/
//
// BBOBEXRequestHandler.m
// LightAquaBlue
//
// Created by Bea on 3/10/07.
// Copyright 2007 __MyCompanyName__. All rights reserved.
//
#import "BBOBEXRequestHandler.h"
#import "BBBluetoothOBEXServer.h"
#import "BBMutableOBEXHeaderSet.h"
#import
static BOOL _debug = NO;
@implementation BBOBEXRequestHandler
+ (void)setDebug:(BOOL)debug
{
_debug = debug;
}
- (id)initWithServer:(BBBluetoothOBEXServer *)server
eventSelector:(SEL)selector
session:(OBEXSession *)session
{
self = [super init];
mServer = server; // don't retain
mServerEventSelector = selector;
mSession = session; // don't retain
mNextResponseCode = -1;
return self;
}
- (void)setNextResponseCode:(int)responseCode;
{
mNextResponseCode = responseCode;
}
- (int)nextResponseCode
{
return mNextResponseCode;
}
- (void)addResponseHeaders:(BBOBEXHeaderSet *)responseHeaders
{
if (!mNextResponseHeaders)
mNextResponseHeaders = [[BBMutableOBEXHeaderSet alloc] init];
[mNextResponseHeaders addHeadersFromHeaderSet:responseHeaders];
}
/*
Returns whether the request has finished (i.e. sent the final response,
or error occurred while sending a response).
*/
- (BOOL)handleRequestEvent:(const OBEXSessionEvent *)event
{
if (_debug) NSLog(@"[BBOBEXRequestHandler] handleRequestEvent (type=%d)", event->type);
BBMutableOBEXHeaderSet *requestHeaders = nil;
OBEXFlags requestFlags = 0;
if (mNextResponseHeaders) {
[mNextResponseHeaders release];
mNextResponseHeaders = nil;
}
// read the client request
if (_debug) NSLog(@"[BBOBEXRequestHandler] handleRequestEvent read headers");
if (![self readOBEXRequestHeaders:&requestHeaders
andRequestFlags:&requestFlags
fromSessionEvent:event]) {
[self errorOccurred:kOBEXInternalError
description:@"Wrong request handler assigned to read request headers!"];
// OR we got a new request before the last one finished???
mNextResponseCode = kOBEXResponseCodeInternalServerErrorWithFinalBit;
[self sendNextResponsePacket];
[self notifyRequestFinished];
return YES;
}
if (!requestHeaders) {
[self errorOccurred:kOBEXInternalError
description:@"Can't read request headers!"];
mNextResponseCode = kOBEXResponseCodeBadRequestWithFinalBit;
[self sendNextResponsePacket];
[self notifyRequestFinished];
return YES;
}
// get the response for this request
if (_debug) NSLog(@"[BBOBEXRequestHandler] handleRequestEvent getting response");
[self prepareResponseForRequestWithHeaders:requestHeaders
flags:requestFlags
isFinalRequestPacket:event->isEndOfEventData];
// send the response
if (_debug) NSLog(@"[BBOBEXRequestHandler] handleRequestEvent sending response 0x%x", mNextResponseCode);
OBEXError status = [self sendNextResponsePacket];
if (status != kOBEXSuccess) {
[self errorOccurred:status
description:@"Error sending server response"];
return YES;
}
if (mNextResponseCode != kOBEXResponseCodeContinueWithFinalBit) {
[self notifyRequestFinished];
return YES;
}
return NO;
}
- (void)errorOccurred:(OBEXError)error description:(NSString *)description
{
if ([[mServer delegate] respondsToSelector:@selector(server:errorOccurred:description:)]) {
[[mServer delegate] server:mServer
errorOccurred:error
description:description];
}
}
/*** methods below are to be overriden ***/
- (BOOL)readOBEXRequestHeaders:(BBMutableOBEXHeaderSet **)requestHeaders
andRequestFlags:(OBEXFlags *)flags
fromSessionEvent:(const OBEXSessionEvent *)event
{
return NO;
}
- (void)prepareResponseForRequestWithHeaders:(BBMutableOBEXHeaderSet *)requestHeaders
flags:(OBEXFlags)flags
isFinalRequestPacket:(BOOL)isFinalRequestPacket
{
mNextResponseCode = kOBEXResponseCodeInternalServerErrorWithFinalBit;
}
- (void)handleRequestAborted
{
[mSession OBEXAbortResponse:kOBEXResponseCodeSuccessWithFinalBit
optionalHeaders:NULL
optionalHeadersLength:0
eventSelector:mServerEventSelector
selectorTarget:mServer
refCon:NULL];
}
- (OBEXError)sendNextResponsePacket
{
return kOBEXInternalError;
}
- (void)notifyRequestFinished
{
}
- (void)dealloc
{
[mNextResponseHeaders release];
[super dealloc];
}
@end
@implementation BBOBEXConnectRequestHandler
- (BOOL)readOBEXRequestHeaders:(BBMutableOBEXHeaderSet **)requestHeaders
andRequestFlags:(OBEXFlags *)flags
fromSessionEvent:(const OBEXSessionEvent *)event
{
if (_debug) NSLog(@"[BBOBEXConnectRequestHandler] readOBEXRequestHeaders");
if (event->type != kOBEXSessionEventTypeConnectCommandReceived)
return NO;
const OBEXConnectCommandData *request = &event->u.connectCommandData;
*flags = request->flags;
BBMutableOBEXHeaderSet *headers = [BBMutableOBEXHeaderSet headerSet];
if ([headers addHeadersFromHeadersData:request->headerDataPtr
length:request->headerDataLength]) {
*requestHeaders = headers;
}
// note the request max packet size
mMaxPacketLength = request->maxPacketSize;
return YES;
}
- (void)prepareResponseForRequestWithHeaders:(BBMutableOBEXHeaderSet *)requestHeaders
flags:(OBEXFlags)flags
isFinalRequestPacket:(BOOL)isFinalRequestPacket
{
if (_debug) NSLog(@"[BBOBEXConnectRequestHandler] prepareResponseForRequestWithHeaders");
if (![[mServer delegate] respondsToSelector:@selector(server:shouldHandleConnectRequest:)]) {
mNextResponseCode = kOBEXResponseCodeNotImplementedWithFinalBit;
return;
}
// ask delegate to accept/deny request and set the response code & headers
mNextResponseCode = -1;
BOOL accept = [[mServer delegate] server:mServer
shouldHandleConnectRequest:requestHeaders];
if (mNextResponseCode == -1) {
mNextResponseCode = (accept ? kOBEXResponseCodeSuccessWithFinalBit :
kOBEXResponseCodeForbiddenWithFinalBit);
}
}
- (OBEXError)sendNextResponsePacket
{
if (_debug) NSLog(@"[BBOBEXConnectRequestHandler] sendNextResponsePacket");
CFMutableDataRef bytes = NULL;
if (mNextResponseHeaders) {
bytes = (CFMutableDataRef)[mNextResponseHeaders toBytes];
if (!bytes && [mNextResponseHeaders count] > 0)
return kOBEXInternalError;
}
OBEXError status =
[mSession OBEXConnectResponse:mNextResponseCode
flags:0
maxPacketLength:mMaxPacketLength
optionalHeaders:(bytes ? (void *)CFDataGetBytePtr(bytes) : NULL)
optionalHeadersLength:(bytes ? CFDataGetLength(bytes) : 0)
eventSelector:mServerEventSelector
selectorTarget:mServer
refCon:NULL];
if (bytes)
mHeadersDataRef = bytes;
return status;
}
- (void)notifyRequestFinished
{
if (_debug) NSLog(@"[BBOBEXConnectRequestHandler] notifyRequestFinished");
if ([[mServer delegate] respondsToSelector:@selector(serverDidHandleConnectRequest:)]) {
[[mServer delegate] serverDidHandleConnectRequest:mServer];
}
}
- (void)dealloc
{
if (mHeadersDataRef)
CFRelease(mHeadersDataRef);
[super dealloc];
}
@end
@implementation BBOBEXDisconnectRequestHandler
- (BOOL)readOBEXRequestHeaders:(BBMutableOBEXHeaderSet **)requestHeaders
andRequestFlags:(OBEXFlags *)flags
fromSessionEvent:(const OBEXSessionEvent *)event
{
if (_debug) NSLog(@"[BBOBEXDisconnectRequestHandler] readOBEXRequestHeaders");
if (event->type != kOBEXSessionEventTypeDisconnectCommandReceived)
return NO;
const OBEXDisconnectCommandData *request = &event->u.disconnectCommandData;
BBMutableOBEXHeaderSet *headers = [BBMutableOBEXHeaderSet headerSet];
if ([headers addHeadersFromHeadersData:request->headerDataPtr
length:request->headerDataLength]) {
*requestHeaders = headers;
}
return YES;
}
- (void)prepareResponseForRequestWithHeaders:(BBMutableOBEXHeaderSet *)requestHeaders
flags:(OBEXFlags)flags
isFinalRequestPacket:(BOOL)isFinalRequestPacket
{
if (_debug) NSLog(@"[BBOBEXDisconnectRequestHandler] prepareResponseForRequestWithHeaders");
if (![[mServer delegate] respondsToSelector: @selector(server:shouldHandleDisconnectRequest:)]) {
mNextResponseCode = kOBEXResponseCodeNotImplementedWithFinalBit;
return;
}
// ask delegate to accept/deny request and set the response code & headers
mNextResponseCode = -1;
BOOL accept = [[mServer delegate] server:mServer
shouldHandleDisconnectRequest:requestHeaders];
if (mNextResponseCode == -1) {
mNextResponseCode = (accept ? kOBEXResponseCodeSuccessWithFinalBit :
kOBEXResponseCodeForbiddenWithFinalBit);
}
}
- (OBEXError)sendNextResponsePacket
{
if (_debug) NSLog(@"[BBOBEXDisconnectRequestHandler] sendNextResponsePacket");
CFMutableDataRef bytes = NULL;
if (mNextResponseHeaders) {
bytes = (CFMutableDataRef)[mNextResponseHeaders toBytes];
if (!bytes && [mNextResponseHeaders count] > 0)
return kOBEXInternalError;
}
OBEXError status =
[mSession OBEXDisconnectResponse:mNextResponseCode
optionalHeaders:(bytes ? (void *)CFDataGetBytePtr(bytes) : NULL)
optionalHeadersLength:(bytes ? CFDataGetLength(bytes) : 0)
eventSelector:mServerEventSelector
selectorTarget:mServer
refCon:NULL];
if (bytes)
mHeadersDataRef = bytes;
return status;
}
- (void)notifyRequestFinished
{
if ([[mServer delegate] respondsToSelector:@selector(serverDidHandleDisconnectRequest:)]) {
[[mServer delegate] serverDidHandleDisconnectRequest:mServer];
}
}
- (void)dealloc
{
if (mHeadersDataRef)
CFRelease(mHeadersDataRef);
[super dealloc];
}
@end
@implementation BBOBEXPutRequestHandler
- (id)initWithServer:(BBBluetoothOBEXServer *)server
eventSelector:(SEL)selector
session:(OBEXSession *)session
{
self = [super initWithServer:server eventSelector:selector session:session];
mDefinitelyIsPut = NO;
mAborted = NO;
return self;
}
- (BOOL)readOBEXRequestHeaders:(BBMutableOBEXHeaderSet **)requestHeaders
andRequestFlags:(OBEXFlags *)flags
fromSessionEvent:(const OBEXSessionEvent *)event
{
if (_debug) NSLog(@"[BBOBEXPutRequestHandler] readOBEXRequestHeaders");
if (event->type != kOBEXSessionEventTypePutCommandReceived)
return NO;
const OBEXPutCommandData *request = &event->u.putCommandData;
BBMutableOBEXHeaderSet *headers = [BBMutableOBEXHeaderSet headerSet];
if ([headers addHeadersFromHeadersData:request->headerDataPtr
length:request->headerDataLength]) {
*requestHeaders = headers;
}
return YES;
}
- (void)preparePutResponseForRequestWithHeaders:(BBMutableOBEXHeaderSet *)requestHeaders
isFinalRequestPacket:(BOOL)isFinalRequestPacket
{
if (_debug) NSLog(@"[BBOBEXPutRequestHandler] preparePutResponseForRequestWithHeaders");
// don't pass body & end of body headers onto delegate
NSData *bodyData = [requestHeaders valueForByteSequenceHeader:kOBEXHeaderIDBody];
NSData *endOfBodyData = [requestHeaders valueForByteSequenceHeader:kOBEXHeaderIDEndOfBody];
[requestHeaders removeValueForHeader:kOBEXHeaderIDBody];
[requestHeaders removeValueForHeader:kOBEXHeaderIDEndOfBody];
if (!mOutputStream) {
if (![[mServer delegate] respondsToSelector:@selector(server:shouldHandlePutRequest:)]) {
mNextResponseCode = kOBEXResponseCodeNotImplementedWithFinalBit;
return;
}
// ask delegate to accept/deny request and set the response code & headers
BBOBEXHeaderSet *allRequestHeaders;
if (mPreviousRequestHeaders) {
[mPreviousRequestHeaders addHeadersFromHeaderSet:requestHeaders];
allRequestHeaders = mPreviousRequestHeaders;
} else {
allRequestHeaders = requestHeaders;
}
mNextResponseCode = -1;
NSOutputStream *outputStream = [[mServer delegate] server:mServer
shouldHandlePutRequest:allRequestHeaders];
[mPreviousRequestHeaders release];
mPreviousRequestHeaders = nil;
// see if delegate accepted request
BOOL accept = (outputStream != nil);
if (mNextResponseCode == -1) {
if (accept) {
mNextResponseCode = (isFinalRequestPacket ?
kOBEXResponseCodeSuccessWithFinalBit : kOBEXResponseCodeContinueWithFinalBit);
} else {
mNextResponseCode = kOBEXResponseCodeForbiddenWithFinalBit;
}
}
// delegate refused request?
if (mNextResponseCode != kOBEXResponseCodeContinueWithFinalBit
&& mNextResponseCode != kOBEXResponseCodeSuccessWithFinalBit) {
outputStream = nil;
return;
}
if (!outputStream) {
[self errorOccurred:kOBEXInternalError
description:@"Put request error: delegate accepted request but returned nil NSOutputStream"];
mNextResponseCode = kOBEXResponseCodeInternalServerErrorWithFinalBit;
return;
}
if ([outputStream streamStatus] != NSStreamStatusOpen) {
[self errorOccurred:kOBEXInternalError
description:@"Put request error: output stream specified by delegate must be opened"];
mNextResponseCode = kOBEXResponseCodeInternalServerErrorWithFinalBit;
return;
}
mOutputStream = [outputStream retain];
}
int dataLength = 0;
if (bodyData) {
if ([mOutputStream write:[bodyData bytes] maxLength:[bodyData length]] < 0)
dataLength = -1;
else
dataLength += [bodyData length];
}
if (endOfBodyData && dataLength != -1) {
if ([mOutputStream write:[endOfBodyData bytes] maxLength:[endOfBodyData length]] < 0)
dataLength = -1;
else
dataLength += [endOfBodyData length];
}
if (dataLength < 0) {
[self errorOccurred:kOBEXGeneralError
description:@"Put request error: can't write body data to output stream"];
mNextResponseCode = kOBEXResponseCodeInternalServerErrorWithFinalBit;
return;
}
// will notify delegate even if data length is zero
if ([[mServer delegate] respondsToSelector:@selector(server:didReceiveDataOfLength:isLastPacket:)]) {
[[mServer delegate] server:mServer
didReceiveDataOfLength:dataLength
isLastPacket:isFinalRequestPacket];
}
if (mNextResponseCode == -1 || mNextResponseCode == kOBEXResponseCodeContinueWithFinalBit ||
mNextResponseCode == kOBEXResponseCodeSuccessWithFinalBit) {
mNextResponseCode = (isFinalRequestPacket ?
kOBEXResponseCodeSuccessWithFinalBit : kOBEXResponseCodeContinueWithFinalBit);
}
}
- (void)preparePutDeleteResponseForRequestWithHeaders:(BBOBEXHeaderSet *)requestHeaders
{
if (_debug) NSLog(@"[BBOBEXPutRequestHandler] preparePutDeleteResponseForRequestWithHeaders");
if (![[mServer delegate] respondsToSelector:@selector(server:shouldHandlePutDeleteRequest:)]) {
mNextResponseCode = kOBEXResponseCodeNotImplementedWithFinalBit;
return;
}
// ask delegate to accept/deny request and set the response code & headers
BBOBEXHeaderSet *allRequestHeaders;
if (mPreviousRequestHeaders) {
[mPreviousRequestHeaders addHeadersFromHeaderSet:requestHeaders];
allRequestHeaders = mPreviousRequestHeaders;
} else {
allRequestHeaders = requestHeaders;
}
BOOL accept = [[mServer delegate] server:mServer
shouldHandlePutDeleteRequest:allRequestHeaders];
[mPreviousRequestHeaders release];
mPreviousRequestHeaders = nil;
if (mNextResponseCode == -1 || mNextResponseCode == kOBEXResponseCodeContinueWithFinalBit ||
mNextResponseCode == kOBEXResponseCodeSuccessWithFinalBit) {
mNextResponseCode = (accept ? kOBEXResponseCodeSuccessWithFinalBit :
kOBEXResponseCodeForbiddenWithFinalBit);
}
}
- (void)prepareResponseForRequestWithHeaders:(BBMutableOBEXHeaderSet *)requestHeaders
flags:(OBEXFlags)flags
isFinalRequestPacket:(BOOL)isFinalRequestPacket
{
if (_debug) NSLog(@"[BBOBEXPutRequestHandler] prepareResponseForRequestWithHeaders");
BOOL hasBodyData = ( requestHeaders &&
([requestHeaders containsValueForHeader:kOBEXHeaderIDBody] ||
[requestHeaders containsValueForHeader:kOBEXHeaderIDEndOfBody]) );
if (hasBodyData)
mDefinitelyIsPut = YES;
if (mDefinitelyIsPut) {
[self preparePutResponseForRequestWithHeaders:requestHeaders
isFinalRequestPacket:isFinalRequestPacket];
} else {
if (isFinalRequestPacket) {
[self preparePutDeleteResponseForRequestWithHeaders:requestHeaders];
} else {
if (_debug) NSLog(@"[BBOBEXPutRequestHandler] don't know if it's a Put or Put-Delete, so just continue");
mNextResponseCode = kOBEXResponseCodeContinueWithFinalBit;
// keep request headers so they can be passed to delegate later
if (!mPreviousRequestHeaders)
mPreviousRequestHeaders = [[BBMutableOBEXHeaderSet alloc] init];
[mPreviousRequestHeaders addHeadersFromHeaderSet:requestHeaders];
}
}
}
- (OBEXError)sendNextResponsePacket
{
if (_debug) NSLog(@"[BBOBEXPutRequestHandler] sendNextResponsePacket");
CFMutableDataRef bytes = NULL;
if (mNextResponseHeaders) {
bytes = (CFMutableDataRef)[mNextResponseHeaders toBytes];
if (!bytes && [mNextResponseHeaders count] > 0)
return kOBEXInternalError;
}
OBEXError status =
[mSession OBEXPutResponse:mNextResponseCode
optionalHeaders:(bytes ? (void *)CFDataGetBytePtr(bytes) : NULL)
optionalHeadersLength:(bytes ? CFDataGetLength(bytes) : 0)
eventSelector:mServerEventSelector
selectorTarget:mServer
refCon:NULL];
if (bytes) {
if (mHeadersDataRef)
CFRelease(mHeadersDataRef);
mHeadersDataRef = bytes;
}
return status;
}
- (void)handleRequestAborted
{
if (_debug) NSLog(@"[BBOBEXPutRequestHandler] handleRequestAborted");
mAborted = YES;
mDefinitelyIsPut = YES; // can't abort Delete ops, so this must be a Put
[super handleRequestAborted];
[self notifyRequestFinished];
}
- (void)notifyRequestFinished
{
if (_debug) NSLog(@"[BBOBEXPutRequestHandler] notifyRequestFinished");
if (mDefinitelyIsPut) {
if ([[mServer delegate] respondsToSelector:@selector(server:didHandlePutRequestForStream:requestWasAborted:)]) {
[[mServer delegate] server:mServer
didHandlePutRequestForStream:mOutputStream
requestWasAborted:mAborted];
}
} else {
if ([[mServer delegate] respondsToSelector:@selector(serverDidHandlePutDeleteRequest:)]) {
[[mServer delegate] serverDidHandlePutDeleteRequest:mServer];
}
}
[mOutputStream release];
mOutputStream = nil;
mDefinitelyIsPut = NO;
mAborted = NO;
}
- (void)dealloc
{
if (mHeadersDataRef)
CFRelease(mHeadersDataRef);
[mPreviousRequestHeaders release];
[mOutputStream release];
[super dealloc];
}
@end
@implementation BBOBEXGetRequestHandler
- (id)initWithServer:(BBBluetoothOBEXServer *)server
eventSelector:(SEL)selector
session:(OBEXSession *)session
{
self = [super initWithServer:server eventSelector:selector session:session];
mAborted = NO;
return self;
}
- (BOOL)readOBEXRequestHeaders:(BBMutableOBEXHeaderSet **)requestHeaders
andRequestFlags:(OBEXFlags *)flags
fromSessionEvent:(const OBEXSessionEvent *)event
{
if (_debug) NSLog(@"[BBOBEXGetRequestHandler] readOBEXRequestHeaders");
if (event->type != kOBEXSessionEventTypeGetCommandReceived)
return NO;
const OBEXGetCommandData *request = &event->u.getCommandData;
BBMutableOBEXHeaderSet *headers = [BBMutableOBEXHeaderSet headerSet];
if ([headers addHeadersFromHeadersData:request->headerDataPtr
length:request->headerDataLength]) {
*requestHeaders = headers;
}
return YES;
}
- (NSMutableData *)readNextChunkForHeaderLength:(size_t)headersLength
isLastChunk:(BOOL *)outIsLastChunk
{
if (_debug) NSLog(@"[BBOBEXGetRequestHandler] readNextChunkForHeaderLength");
if (mInputStream == nil)
return nil;
OBEXMaxPacketLength maxPacketSize =
[mSession getAvailableCommandPayloadLength:kOBEXOpCodePut];
if (maxPacketSize == 0 || headersLength > maxPacketSize)
return nil;
OBEXMaxPacketLength maxBodySize = maxPacketSize - headersLength;
NSMutableData *data = [NSMutableData dataWithLength:maxBodySize];
NSInteger len = [mInputStream read:[data mutableBytes]
maxLength:maxBodySize];
if (_debug) NSLog(@"[BBOBEXGetRequestHandler] read %ld bytes (maxBodySize = %d)", (long)len, maxBodySize);
// is last packet if there wasn't enough body data to fill up the packet
if (len >= 0)
*outIsLastChunk = (len < maxBodySize);
[data setLength:len];
return data;
}
- (void)prepareResponseForRequestWithHeaders:(BBMutableOBEXHeaderSet *)requestHeaders
flags:(OBEXFlags)flags
isFinalRequestPacket:(BOOL)isFinalRequestPacket
{
if (_debug) NSLog(@"[BBOBEXGetRequestHandler] prepareResponseForRequestWithHeaders");
if (!mInputStream) {
if (![[mServer delegate] respondsToSelector:@selector(server:shouldHandleGetRequest:)]) {
mNextResponseCode = kOBEXResponseCodeNotImplementedWithFinalBit;
return;
}
// ask delegate to accept/deny request and set the response code & headers
mNextResponseCode = -1;
NSInputStream *inputStream = [[mServer delegate] server:mServer
shouldHandleGetRequest:requestHeaders];
BOOL accept = (inputStream != nil);
if (mNextResponseCode == -1) {
mNextResponseCode = (accept ? kOBEXResponseCodeSuccessWithFinalBit :
kOBEXResponseCodeForbiddenWithFinalBit);
}
// delegate refused request?
if (mNextResponseCode != kOBEXResponseCodeContinueWithFinalBit
&& mNextResponseCode != kOBEXResponseCodeSuccessWithFinalBit) {
inputStream = nil;
return;
}
if (!inputStream) {
[self errorOccurred:kOBEXInternalError
description:@"Get request error: delegate accepted request but returned nil NSInputStream"];
mNextResponseCode = kOBEXResponseCodeInternalServerErrorWithFinalBit;
return;
}
if ([inputStream streamStatus] != NSStreamStatusOpen) {
[self errorOccurred:kOBEXInternalError
description:@"Get request error: input stream specified by delegate must be opened"];
mNextResponseCode = kOBEXResponseCodeInternalServerErrorWithFinalBit;
return;
}
mInputStream = [inputStream retain];
}
if (!mNextResponseHeaders)
mNextResponseHeaders = [[BBMutableOBEXHeaderSet alloc] init];
CFMutableDataRef tempHeaderBytes = (CFMutableDataRef)[mNextResponseHeaders toBytes];
CFIndex currentHeaderLength = 0;
if (tempHeaderBytes) {
currentHeaderLength = CFDataGetLength(tempHeaderBytes);
CFRelease(tempHeaderBytes);
}
BOOL isLastChunk = YES;
// the GET headers seem to need 3 bytes padding, maybe for the response code
// plus packet length in the headers.
NSMutableData *mutableData = [self readNextChunkForHeaderLength:currentHeaderLength + 3
isLastChunk:&isLastChunk];
if (!mutableData) {
[self errorOccurred:kOBEXInternalError
description:@"Get request error: can't read data from input stream"];
mNextResponseCode = kOBEXResponseCodeInternalServerErrorWithFinalBit;
return;
}
uint8_t headerID = (isLastChunk ? kOBEXHeaderIDBody : kOBEXHeaderIDEndOfBody);
[mNextResponseHeaders setValue:mutableData forByteSequenceHeader:headerID];
if (![mNextResponseHeaders containsValueForHeader:headerID]) {
[self errorOccurred:kOBEXInternalError
description:@"Get request error: can't add body data to response headers"];
mNextResponseCode = kOBEXResponseCodeInternalServerErrorWithFinalBit;
return;
}
[mutableData retain];
[mSentBodyData release];
mSentBodyData = mutableData;
if (mNextResponseCode == -1 || mNextResponseCode == kOBEXResponseCodeContinueWithFinalBit ||
mNextResponseCode == kOBEXResponseCodeSuccessWithFinalBit) {
if (isLastChunk)
mNextResponseCode = kOBEXResponseCodeSuccessWithFinalBit;
else
mNextResponseCode = kOBEXResponseCodeContinueWithFinalBit;
}
}
- (OBEXError)sendNextResponsePacket
{
if (_debug) NSLog(@"[BBOBEXGetRequestHandler] sendNextResponsePacket");
CFMutableDataRef bytes = NULL;
if (mNextResponseHeaders) {
bytes = (CFMutableDataRef)[mNextResponseHeaders toBytes];
if (!bytes && [mNextResponseHeaders count] > 0)
return kOBEXInternalError;
}
OBEXError status =
[mSession OBEXGetResponse:mNextResponseCode
optionalHeaders:(bytes ? (void *)CFDataGetBytePtr(bytes) : NULL)
optionalHeadersLength:(bytes ? CFDataGetLength(bytes) : 0)
eventSelector:mServerEventSelector
selectorTarget:mServer
refCon:NULL];
if (bytes) {
if (mHeadersDataRef)
CFRelease(mHeadersDataRef);
mHeadersDataRef = bytes;
}
if (mSentBodyData && [[mServer delegate] respondsToSelector:@selector(server:didSendDataOfLength:)]) {
[[mServer delegate] server:mServer
didSendDataOfLength:[mSentBodyData length]];
}
return status;
}
- (void)handleRequestAborted
{
if (_debug) NSLog(@"[BBOBEXGetRequestHandler] handleRequestAborted");
mAborted = YES;
[super handleRequestAborted];
[self notifyRequestFinished];
}
- (void)notifyRequestFinished
{
if ([[mServer delegate] respondsToSelector:@selector(server:didHandleGetRequestForStream:requestWasAborted:)]) {
[[mServer delegate] server:mServer
didHandleGetRequestForStream:mInputStream
requestWasAborted:mAborted];
}
[mInputStream release];
mInputStream = nil;
mAborted = NO;
}
- (void)dealloc
{
if (mHeadersDataRef)
CFRelease(mHeadersDataRef);
[mSentBodyData release];
[mInputStream release];
[super dealloc];
}
@end
@implementation BBOBEXSetPathRequestHandler
- (BOOL)readOBEXRequestHeaders:(BBMutableOBEXHeaderSet **)requestHeaders
andRequestFlags:(OBEXFlags *)flags
fromSessionEvent:(const OBEXSessionEvent *)event
{
if (_debug) NSLog(@"[BBOBEXSetPathRequestHandler] readOBEXRequestHeaders");
if (event->type != kOBEXSessionEventTypeSetPathCommandReceived)
return NO;
const OBEXSetPathCommandData *request = &event->u.setPathCommandData;
*flags = request->flags;
BBMutableOBEXHeaderSet *headers = [BBMutableOBEXHeaderSet headerSet];
if ([headers addHeadersFromHeadersData:request->headerDataPtr
length:request->headerDataLength]) {
*requestHeaders = headers;
}
return YES;
}
- (void)prepareResponseForRequestWithHeaders:(BBMutableOBEXHeaderSet *)requestHeaders
flags:(OBEXFlags)flags
isFinalRequestPacket:(BOOL)isFinalRequestPacket
{
if (_debug) NSLog(@"[BBOBEXSetPathRequestHandler] prepareResponseForRequestWithHeaders");
if (![[mServer delegate] respondsToSelector:@selector(server:shouldHandleSetPathRequest:withFlags:)]) {
mNextResponseCode = kOBEXResponseCodeNotImplementedWithFinalBit;
return;
}
//BOOL changeToParentDirectoryFirst = (flags & 1) != 0;
//BOOL createDirectoriesIfNeeded = (flags & 2) == 0;
// ask delegate to accept/deny request and set the response code & headers
mNextResponseCode = -1;
BOOL accept = [[mServer delegate] server:mServer
shouldHandleSetPathRequest:requestHeaders
withFlags:flags];
if (mNextResponseCode == -1) {
mNextResponseCode = (accept ? kOBEXResponseCodeSuccessWithFinalBit :
kOBEXResponseCodeForbiddenWithFinalBit);
}
}
- (OBEXError)sendNextResponsePacket
{
if (_debug) NSLog(@"[BBOBEXSetPathRequestHandler] sendNextResponsePacket");
CFMutableDataRef bytes = NULL;
if (mNextResponseHeaders) {
bytes = (CFMutableDataRef)[mNextResponseHeaders toBytes];
if (!bytes && [mNextResponseHeaders count] > 0)
return kOBEXInternalError;
}
OBEXError status =
[mSession OBEXSetPathResponse:mNextResponseCode
optionalHeaders:(bytes ? (void *)CFDataGetBytePtr(bytes) : NULL)
optionalHeadersLength:(bytes ? CFDataGetLength(bytes) : 0)
eventSelector:mServerEventSelector
selectorTarget:mServer
refCon:NULL];
if (bytes)
mHeadersDataRef = bytes;
return status;
}
- (void)notifyRequestFinished
{
if ([[mServer delegate] respondsToSelector:@selector(serverDidHandleSetPathRequest:)])
[[mServer delegate] serverDidHandleSetPathRequest:mServer];
}
- (void)dealloc
{
if (mHeadersDataRef)
CFRelease(mHeadersDataRef);
[super dealloc];
}
@end
pybluez-0.23/macos/LightAquaBlue/BBOBEXResponse.h 0000664 0000000 0000000 00000003617 13601523637 0021567 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2009 Bea Lam. All rights reserved.
*
* This file is part of LightBlue.
*
* LightBlue is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LightBlue is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LightBlue. If not, see .
*/
//
// BBOBEXResponse.h
// LightAquaBlue
//
// Contains the details for an OBEX server response.
//
// This is used by BBBluetoothOBEXClient to pass the details of an OBEX
// server response to its delegate.
//
#import
@class BBOBEXHeaderSet;
@interface BBOBEXResponse : NSObject {
int mCode;
BBOBEXHeaderSet *mHeaders;
}
+ (id)responseWithCode:(int)responseCode
headers:(BBOBEXHeaderSet *)headers;
- (id)initWithCode:(int)responseCode
headers:(BBOBEXHeaderSet *)headers;
/*
* Returns the response code.
*
* Use the response codes listed in the OBEXOpCodeResponseValues enum in
* to match against this response code. If the client
* request was accepted by the OBEX server, this response code will be
* kOBEXResponseCodeSuccessWithFinalBit. Otherwise, it will be set to one of
* the other response codes that end with "WithFinalBit".
*/
- (int)responseCode;
/*
* Returns a string description of the response code. E.g.
* kOBEXResponseCodeSuccessWithFinalBit translates to "Success".
*/
- (NSString *)responseCodeDescription;
/*
* Returns the response headers.
*/
- (BBOBEXHeaderSet *)allHeaders;
@end
pybluez-0.23/macos/LightAquaBlue/BBOBEXResponse.m 0000664 0000000 0000000 00000012174 13601523637 0021572 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2009 Bea Lam. All rights reserved.
*
* This file is part of LightBlue.
*
* LightBlue is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LightBlue is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LightBlue. If not, see .
*/
//
// BBOBEXResponse.m
// LightAquaBlue
//
#import "BBOBEXResponse.h"
#import "BBOBEXHeaderSet.h"
@implementation BBOBEXResponse
+ (id)responseWithCode:(int)responseCode
headers:(BBOBEXHeaderSet *)headers
{
return [[[BBOBEXResponse alloc] initWithCode:responseCode
headers:headers] autorelease];
}
- (id)initWithCode:(int)responseCode
headers:(BBOBEXHeaderSet *)headers
{
self = [super init];
mCode = responseCode;
mHeaders = [headers retain];
return self;
}
- (int)responseCode
{
return mCode;
}
- (NSString *)responseCodeDescription
{
switch (mCode) {
case kOBEXResponseCodeContinueWithFinalBit:
return @"Continue";
case kOBEXResponseCodeSuccessWithFinalBit:
return @"Success";
case kOBEXResponseCodeCreatedWithFinalBit:
return @"Created";
case kOBEXResponseCodeAcceptedWithFinalBit:
return @"Accepted";
case kOBEXResponseCodeNonAuthoritativeInfoWithFinalBit:
return @"Non-authoritative info";
case kOBEXResponseCodeNoContentWithFinalBit:
return @"No content";
case kOBEXResponseCodeResetContentWithFinalBit:
return @"Reset content";
case kOBEXResponseCodePartialContentWithFinalBit:
return @"Partial content";
case kOBEXResponseCodeMultipleChoicesWithFinalBit:
return @"Multiple choices";
case kOBEXResponseCodeMovedPermanentlyWithFinalBit:
return @"Moved permanently";
case kOBEXResponseCodeMovedTemporarilyWithFinalBit:
return @"Moved temporarily";
case kOBEXResponseCodeSeeOtherWithFinalBit:
return @"See other";
case kOBEXResponseCodeNotModifiedWithFinalBit:
return @"Code not modified";
case kOBEXResponseCodeUseProxyWithFinalBit:
return @"Use proxy";
case kOBEXResponseCodeBadRequestWithFinalBit:
return @"Bad request";
case kOBEXResponseCodeUnauthorizedWithFinalBit:
return @"Unauthorized";
case kOBEXResponseCodePaymentRequiredWithFinalBit:
return @"Payment required";
case kOBEXResponseCodeForbiddenWithFinalBit:
return @"Forbidden";
case kOBEXResponseCodeNotFoundWithFinalBit:
return @"Not found";
case kOBEXResponseCodeMethodNotAllowedWithFinalBit:
return @"Method not allowed";
case kOBEXResponseCodeNotAcceptableWithFinalBit:
return @"Not acceptable";
case kOBEXResponseCodeProxyAuthenticationRequiredWithFinalBit:
return @"Proxy authentication required";
case kOBEXResponseCodeRequestTimeOutWithFinalBit:
return @"Request time out";
case kOBEXResponseCodeConflictWithFinalBit:
return @"Conflict";
case kOBEXResponseCodeGoneWithFinalBit:
return @"Gone";
case kOBEXResponseCodeLengthRequiredFinalBit:
return @"Length required";
case kOBEXResponseCodePreconditionFailedWithFinalBit:
return @"Precondition failed";
case kOBEXResponseCodeRequestedEntityTooLargeWithFinalBit:
return @"Requested entity too large";
case kOBEXResponseCodeRequestURLTooLargeWithFinalBit:
return @"Requested URL too large";
case kOBEXResponseCodeUnsupportedMediaTypeWithFinalBit:
return @"Unsupported media type";
case kOBEXResponseCodeInternalServerErrorWithFinalBit:
return @"Internal server error";
case kOBEXResponseCodeNotImplementedWithFinalBit:
return @"Not implemented";
case kOBEXResponseCodeBadGatewayWithFinalBit:
return @"Bad gateway";
case kOBEXResponseCodeServiceUnavailableWithFinalBit:
return @"Service unavailable";
case kOBEXResponseCodeGatewayTimeoutWithFinalBit:
return @"Gateway timeout";
case kOBEXResponseCodeHTTPVersionNotSupportedWithFinalBit:
return @"HTTP version not supported";
case kOBEXResponseCodeDatabaseFullWithFinalBit:
return @"Database full";
case kOBEXResponseCodeDatabaseLockedWithFinalBit:
return @"Database locked";
default:
return @"Unknown response";
}
}
- (BBOBEXHeaderSet *)allHeaders
{
return mHeaders;
}
- (void)dealloc
{
[mHeaders release];
[super dealloc];
}
@end
pybluez-0.23/macos/LightAquaBlue/BBServiceAdvertiser.h 0000664 0000000 0000000 00000004643 13601523637 0022744 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2009 Bea Lam. All rights reserved.
*
* This file is part of LightBlue.
*
* LightBlue is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LightBlue is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LightBlue. If not, see .
*/
//
// BBServiceAdvertiser.h
// LightAquaBlue
//
// Provides some basic operations for advertising Bluetooth services.
//
#import
@class IOBluetoothSDPUUID;
@interface BBServiceAdvertiser : NSObject {
//
}
/*
* Returns a ready-made dictionary for advertising a service with the Serial
* Port Profile.
*/
+ (NSDictionary *)serialPortProfileDictionary;
/*
* Returns a ready-made dictionary for advertising a service with the OBEX
* Object Push Profile.
*/
+ (NSDictionary *)objectPushProfileDictionary;
/*
* Returns a ready-made dictionary for advertising a service with the OBEX
* File Transfer Profile.
*/
+ (NSDictionary *)fileTransferProfileDictionary;
/*
* Advertise a RFCOMM-based (i.e. RFCOMM or OBEX) service.
*
* Arguments:
* - dict: the dictionary containing the service details.
* - serviceName: the service name to advertise, which will be added to the
* dictionary. Can be nil.
* - uuid: the custom UUID to advertise for the service, which will be added to
* the dictionary. Can be nil.
* - outChannelID: once the service is advertised, this will be set to the
* RFCOMM channel ID that was used to advertise the service.
* - outServiceRecordHandle: once the service is advertised, this will be set
* to the service record handle which identifies the service.
*/
+ (IOReturn)addRFCOMMServiceDictionary:(NSDictionary *)dict
withName:(NSString *)serviceName
UUID:(NSString *)uuid
channelID:(BluetoothRFCOMMChannelID *)outChannelID
serviceRecordHandle:(BluetoothSDPServiceRecordHandle *)outServiceRecordHandle;
/*
* Stop advertising a service.
*/
+ (IOReturn)removeService:(BluetoothSDPServiceRecordHandle)handle;
@end
pybluez-0.23/macos/LightAquaBlue/BBServiceAdvertiser.m 0000664 0000000 0000000 00000011757 13601523637 0022755 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2009 Bea Lam. All rights reserved.
*
* This file is part of LightBlue.
*
* LightBlue is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LightBlue is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LightBlue. If not, see .
*/
//
// BBServiceAdvertiser.m
// LightAquaBlue
//
#import
#import
#import
#import "BBServiceAdvertiser.h"
static NSString *kServiceItemKeyServiceClassIDList;
static NSString *kServiceItemKeyServiceName;
static NSString *kServiceItemKeyProtocolDescriptorList;
// template service dictionaries for each pre-defined profile
static NSDictionary *serialPortProfileDict;
static NSDictionary *objectPushProfileDict;
static NSDictionary *fileTransferProfileDict;
@implementation BBServiceAdvertiser
+ (void)initialize
{
kServiceItemKeyServiceClassIDList = @"0001 - ServiceClassIDList";
kServiceItemKeyServiceName = @"0100 - ServiceName*";
kServiceItemKeyProtocolDescriptorList = @"0004 - ProtocolDescriptorList";
// initialize the template service dictionaries
NSBundle *classBundle = [NSBundle bundleForClass:[BBServiceAdvertiser class]];
serialPortProfileDict =
[[NSDictionary alloc] initWithContentsOfFile:[classBundle pathForResource:@"SerialPortDictionary"
ofType:@"plist"]];
objectPushProfileDict =
[[NSDictionary alloc] initWithContentsOfFile:[classBundle pathForResource:@"OBEXObjectPushDictionary"
ofType:@"plist"]];
fileTransferProfileDict =
[[NSDictionary alloc] initWithContentsOfFile:[classBundle pathForResource:@"OBEXFileTransferDictionary"
ofType:@"plist"]];
//kRFCOMMChannelNone = 0;
//kRFCOMM_UUID = [[IOBluetoothSDPUUID uuid16:kBluetoothSDPUUID16RFCOMM] retain];
}
+ (NSDictionary *)serialPortProfileDictionary
{
return serialPortProfileDict;
}
+ (NSDictionary *)objectPushProfileDictionary
{
return objectPushProfileDict;
}
+ (NSDictionary *)fileTransferProfileDictionary
{
return fileTransferProfileDict;
}
+ (void)updateServiceDictionary:(NSMutableDictionary *)sdpEntries
withName:(NSString *)serviceName
withUUID:(IOBluetoothSDPUUID *)uuid
{
if (sdpEntries == nil) return;
// set service name
if (serviceName != nil) {
[sdpEntries setObject:serviceName forKey:kServiceItemKeyServiceName];
}
// set service uuid if given
if (uuid != nil) {
NSMutableArray *currentServiceList =
[sdpEntries objectForKey:kServiceItemKeyServiceClassIDList];
if (currentServiceList == nil) {
currentServiceList = [NSMutableArray array];
}
[currentServiceList addObject:[NSData dataWithBytes:[uuid bytes] length:[uuid length]]];
// update dict
[sdpEntries setObject:currentServiceList forKey:kServiceItemKeyServiceClassIDList];
}
}
+ (IOReturn)addRFCOMMServiceDictionary:(NSDictionary *)dict
withName:(NSString *)serviceName
UUID:(NSString *)uuid
channelID:(BluetoothRFCOMMChannelID *)outChannelID
serviceRecordHandle:(BluetoothSDPServiceRecordHandle *)outServiceRecordHandle
{
if (dict == nil)
return kIOReturnError;
NSMutableDictionary *sdpEntries = [NSMutableDictionary dictionaryWithDictionary:dict];
NSUUID * uuid_ = [[NSUUID alloc] initWithUUIDString:uuid];
uuid_t uuidbuf;
[uuid_ getUUIDBytes:uuidbuf];
IOBluetoothSDPUUID * uuidBlutooth = [IOBluetoothSDPUUID uuidWithBytes:uuidbuf length:16];
[BBServiceAdvertiser updateServiceDictionary:sdpEntries
withName:serviceName
withUUID:uuidBlutooth];
// publish the service
IOBluetoothSDPServiceRecord *serviceRecord;
serviceRecord = [IOBluetoothSDPServiceRecord publishedServiceRecordWithDictionary:sdpEntries];
[uuid_ autorelease];
IOReturn status = kIOReturnSuccess;
if (serviceRecord != nil) {
// get service channel ID & service record handle
status = [serviceRecord getRFCOMMChannelID:outChannelID];
if (status == kIOReturnSuccess) {
status = [serviceRecord getServiceRecordHandle:outServiceRecordHandle];
}
// cleanup
[serviceRecord release];
}
return status;
}
+ (IOReturn)removeService:(BluetoothSDPServiceRecordHandle)handle
{
// TODO: We should switch to using [IOBluetoothSDPServiceRecord removeServiceRecord]
// but we don't know how to get an IOBluetoothSDPServiceRecord instance from a handle.
return IOBluetoothRemoveServiceWithRecordHandle(handle);
}
@end
pybluez-0.23/macos/LightAquaBlue/BBStreamingInputStream.h 0000664 0000000 0000000 00000002504 13601523637 0023432 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2009 Bea Lam. All rights reserved.
*
* This file is part of LightBlue.
*
* LightBlue is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LightBlue is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LightBlue. If not, see .
*/
//
// BBDelegatingInputStream.h
// LightAquaBlue
//
// A NSInputStream subclass that calls readDataWithMaxLength: on the delegate
// when data is required.
// This class is only intended for use from the LightBlue library.
// Most methods are not implemented, and there are no stream:HandleEvent:
// calls to the delegate.
//
#import
@interface BBStreamingInputStream : NSInputStream {
id mDelegate;
NSStreamStatus mStatus;
}
- (id)initWithDelegate:(id)delegate;
@end
@protocol BBStreamingInputStreamDelegate
- (NSData *)readDataWithMaxLength:(NSUInteger)maxLength;
@end
pybluez-0.23/macos/LightAquaBlue/BBStreamingInputStream.m 0000664 0000000 0000000 00000004204 13601523637 0023436 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2009 Bea Lam. All rights reserved.
*
* This file is part of LightBlue.
*
* LightBlue is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LightBlue is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LightBlue. If not, see .
*/
//
// BBDelegatingInputStream.m
// LightAquaBlue
//
#import "BBStreamingInputStream.h"
@implementation BBStreamingInputStream
- (id)initWithDelegate:(id)delegate
{
self = [super init];
mDelegate = delegate;
mStatus = NSStreamStatusNotOpen;
return self;
}
- (NSInteger)read:(uint8_t *)buffer maxLength:(NSUInteger)maxLength
{
NSData *data = [mDelegate readDataWithMaxLength:maxLength];
if (!data)
return -1;
NSUInteger copyLength = [data length] < maxLength ? [data length] : maxLength;
[data getBytes:buffer length:copyLength];
return copyLength;
}
- (BOOL)getBuffer:(uint8_t **)buffer length:(NSUInteger *)len
{
// we cannot access buffer data without calling read:maxLength:
return NO;
}
- (BOOL)hasBytesAvailable
{
// don't know whether bytes are available until read:maxLength: is called
return YES;
}
- (void)open
{
mStatus = NSStreamStatusOpen;
}
- (void)close
{
mStatus = NSStreamStatusClosed;
}
- (void)setDelegate:(id)delegate
{
mDelegate = delegate;
}
- (id)delegate
{
return mDelegate;
}
- (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode
{
}
- (void)removeFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode
{
}
- (BOOL)setProperty:(id)property forKey:(NSString *)key
{
return NO;
}
- (id)propertyForKey:(NSString *)key
{
return nil;
}
- (NSStreamStatus)streamStatus
{
return mStatus;
}
@end
pybluez-0.23/macos/LightAquaBlue/BBStreamingOutputStream.h 0000664 0000000 0000000 00000002434 13601523637 0023635 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2009 Bea Lam. All rights reserved.
*
* This file is part of LightBlue.
*
* LightBlue is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LightBlue is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LightBlue. If not, see .
*/
//
// BBStreamingOutputStream.h
// LightAquaBlue
//
// A NSOutputStream subclass that calls write: on its delegate when data
// is available.
// This class is only intended for use from the LightBlue library.
// Most methods are not implemented, and there are no stream:HandleEvent:
// calls to the delegate.
//
#import
@interface BBStreamingOutputStream : NSOutputStream {
id mDelegate;
NSStreamStatus mStatus;
}
- (id)initWithDelegate:(id)delegate;
@end
@protocol BBStreamingOutputStreamDelegate
- (int)write:(NSData *)data;
@end
pybluez-0.23/macos/LightAquaBlue/BBStreamingOutputStream.m 0000664 0000000 0000000 00000003737 13601523637 0023651 0 ustar 00root root 0000000 0000000 /*
* Copyright (c) 2009 Bea Lam. All rights reserved.
*
* This file is part of LightBlue.
*
* LightBlue is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* LightBlue is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with LightBlue. If not, see .
*/
//
// BBStreamingOutputStream.m
// LightAquaBlue
//
#import "BBStreamingOutputStream.h"
@implementation BBStreamingOutputStream
- (id)initWithDelegate:(id)delegate
{
self = [super init];
mDelegate = delegate;
return self;
}
- (NSInteger)write:(const uint8_t *)buffer maxLength:(NSUInteger)len
{
//NSLog(@"[BBStreamingOutputStream] writing data...");
int buflen = [mDelegate write:[NSData dataWithBytesNoCopy:(void *)buffer
length:len
freeWhenDone:NO]];
return buflen;
}
- (BOOL)hasSpaceAvailable
{
// must do write to determine whether space is available
return YES;
}
- (void)open
{
mStatus = NSStreamStatusOpen;
}
- (void)close
{
mStatus = NSStreamStatusClosed;
}
- (void)setDelegate:(id)delegate
{
mDelegate = delegate;
}
- (id)delegate
{
return mDelegate;
}
- (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode
{
}
- (void)removeFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode
{
}
- (BOOL)setProperty:(id)property forKey:(NSString *)key
{
return NO;
}
- (id)propertyForKey:(NSString *)key
{
return nil;
}
- (NSStreamStatus)streamStatus
{
return mStatus;
}
@end
pybluez-0.23/macos/LightAquaBlue/BridgeSupport/ 0000775 0000000 0000000 00000000000 13601523637 0021520 5 ustar 00root root 0000000 0000000 pybluez-0.23/macos/LightAquaBlue/BridgeSupport/LightAquaBlue.bridgesupport 0000664 0000000 0000000 00000007174 13601523637 0027033 0 ustar 00root root 0000000 0000000
pybluez-0.23/macos/LightAquaBlue/English.lproj/ 0000775 0000000 0000000 00000000000 13601523637 0021445 5 ustar 00root root 0000000 0000000 pybluez-0.23/macos/LightAquaBlue/English.lproj/InfoPlist.strings 0000664 0000000 0000000 00000000000 13601523637 0024755 0 ustar 00root root 0000000 0000000 pybluez-0.23/macos/LightAquaBlue/Info.plist 0000664 0000000 0000000 00000001407 13601523637 0020701 0 ustar 00root root 0000000 0000000
CFBundleDevelopmentRegionEnglishCFBundleExecutable${EXECUTABLE_NAME}CFBundleIconFileCFBundleIdentifier$(PRODUCT_BUNDLE_IDENTIFIER)CFBundleInfoDictionaryVersion6.0CFBundleName${PRODUCT_NAME}CFBundlePackageTypeFMWKCFBundleSignature????CFBundleVersion1.0NSPrincipalClass
pybluez-0.23/macos/LightAquaBlue/LightAquaBlue.h 0000664 0000000 0000000 00000001051 13601523637 0021564 0 ustar 00root root 0000000 0000000 #import
#import
#import
#import
#import
#import
#import
#import
#import
#import
#import
#import
pybluez-0.23/macos/LightAquaBlue/LightAquaBlue.xcodeproj/ 0000775 0000000 0000000 00000000000 13601523637 0023412 5 ustar 00root root 0000000 0000000 pybluez-0.23/macos/LightAquaBlue/LightAquaBlue.xcodeproj/blam.mode1v3 0000664 0000000 0000000 00000116674 13601523637 0025544 0 ustar 00root root 0000000 0000000
ActivePerspectiveNameProjectAllowedModulesBundleLoadPathMaxInstancesnModulePBXSmartGroupTreeModuleNameGroups and Files Outline ViewBundleLoadPathMaxInstancesnModulePBXNavigatorGroupNameEditorBundleLoadPathMaxInstancesnModuleXCTaskListModuleNameTask ListBundleLoadPathMaxInstancesnModuleXCDetailModuleNameFile and Smart Group Detail ViewerBundleLoadPathMaxInstances1ModulePBXBuildResultsModuleNameDetailed Build Results ViewerBundleLoadPathMaxInstances1ModulePBXProjectFindModuleNameProject Batch Find ToolBundleLoadPathMaxInstancesnModuleXCProjectFormatConflictsModuleNameProject Format Conflicts ListBundleLoadPathMaxInstancesnModulePBXBookmarksModuleNameBookmarks ToolBundleLoadPathMaxInstancesnModulePBXClassBrowserModuleNameClass BrowserBundleLoadPathMaxInstancesnModulePBXCVSModuleNameSource Code Control ToolBundleLoadPathMaxInstancesnModulePBXDebugBreakpointsModuleNameDebug Breakpoints ToolBundleLoadPathMaxInstancesnModuleXCDockableInspectorNameInspectorBundleLoadPathMaxInstancesnModulePBXOpenQuicklyModuleNameOpen Quickly ToolBundleLoadPathMaxInstances1ModulePBXDebugSessionModuleNameDebuggerBundleLoadPathMaxInstances1ModulePBXDebugCLIModuleNameDebug ConsoleBundleLoadPathMaxInstancesnModuleXCSnapshotModuleNameSnapshots ToolBundlePath/Developer/Library/PrivateFrameworks/DevToolsInterface.framework/ResourcesDescriptionDefaultDescriptionKeyDockingSystemVisibleExtensionmode1v3FavBarConfigPBXProjectModuleGUID669281F20E296950008CB8B0XCBarModuleItemNamesXCBarModuleItemsFirstTimeWindowDisplayedIdentifiercom.apple.perspectives.project.mode1v3MajorVersion33MinorVersion0NameDefaultNotificationsOpenEditorsPerspectiveWidths-1-1PerspectivesChosenToolbarItemsactive-target-popupactive-buildstyle-popupactionNSToolbarFlexibleSpaceItembuildOrCleanbuild-and-goOrGocom.apple.ide.PBXToolbarStopButtonget-infotoggle-editorNSToolbarFlexibleSpaceItemcom.apple.pbx.toolbar.searchfieldControllerClassBaseNameIconNameWindowOfProjectWithEditorIdentifierperspective.projectIsVerticalLayoutContentConfigurationPBXBottomSmartGroupGIDs1C37FBAC04509CD0000001021C37FAAC04509CD0000001021C08E77C0454961000C914BD1C37FABC05509CD0000001021C37FABC05539CD112110102E2644B35053B69B2002112561C37FABC04509CD0001001041CC0EA4004350EF90044410B1CC0EA4004350EF90041110BPBXProjectModuleGUID1CE0B1FE06471DED0097A5F4PBXProjectModuleLabelFilesPBXProjectStructureProvidedyesPBXSmartGroupTreeModuleColumnDataPBXSmartGroupTreeModuleColumnWidthsKey186PBXSmartGroupTreeModuleColumnsKey_v4MainColumnPBXSmartGroupTreeModuleOutlineStateKey_v7PBXSmartGroupTreeModuleOutlineStateExpansionKey0867D691FE84028FC02AAC07089C1665FE841158C02AAC070867D69AFE84028FC02AAC071058C7B2FEA5585E11CA2CBB034768DFFF38A50411DB9C8B1C37FABC05509CD000000102PBXSmartGroupTreeModuleOutlineStateSelectionKey540PBXSmartGroupTreeModuleOutlineStateVisibleRectKey{{0, 0}, {186, 533}}PBXTopSmartGroupGIDsXCIncludePerspectivesSwitchXCSharingTokencom.apple.Xcode.GFSharingTokenGeometryConfigurationFrame{{0, 0}, {203, 551}}GroupTreeTableConfigurationMainColumn186RubberWindowFrame149 115 922 592 0 0 1280 778 ModulePBXSmartGroupTreeModuleProportion203ptDockContentConfigurationPBXProjectModuleGUID1CE0B20306471E060097A5F4PBXProjectModuleLabelLightAquaBlue.bridgesupportPBXSplitModuleInNavigatorKeySplit0PBXProjectModuleGUID1CE0B20406471E060097A5F4PBXProjectModuleLabelLightAquaBlue.bridgesupport_historyCapacity0bookmark6692821F0E468045008CB8B0history669282050E297147008CB8B0669282060E297147008CB8B0669282070E297147008CB8B0669282080E297147008CB8B06692821B0E468045008CB8B06692821C0E468045008CB8B0prevStack6692820A0E297147008CB8B06692820B0E297147008CB8B06692820C0E297147008CB8B06692820D0E297147008CB8B06692820E0E297147008CB8B06692820F0E297147008CB8B0669282100E297147008CB8B0669282110E297147008CB8B0669282120E297147008CB8B0669282130E297147008CB8B0669282140E297147008CB8B0669282150E297147008CB8B06692821E0E468045008CB8B0SplitCount1StatusBarVisibilityGeometryConfigurationFrame{{0, 0}, {714, 332}}RubberWindowFrame149 115 922 592 0 0 1280 778 ModulePBXNavigatorGroupProportion332ptBecomeActiveContentConfigurationPBXProjectModuleGUID1CE0B20506471E060097A5F4PBXProjectModuleLabelDetailGeometryConfigurationFrame{{0, 337}, {714, 214}}RubberWindowFrame149 115 922 592 0 0 1280 778 ModuleXCDetailModuleProportion214ptProportion714ptNameProjectServiceClassesXCModuleDockPBXSmartGroupTreeModuleXCModuleDockPBXNavigatorGroupXCDetailModuleTableOfContents669282020E296AB4008CB8B01CE0B1FE06471DED0097A5F4669282030E296AB4008CB8B01CE0B20306471E060097A5F41CE0B20506471E060097A5F4ToolbarConfigurationxcode.toolbar.config.defaultV3ControllerClassBaseNameIconNameWindowOfProjectIdentifierperspective.morphIsVertical0LayoutBecomeActive1ContentConfigurationPBXBottomSmartGroupGIDs1C37FBAC04509CD0000001021C37FAAC04509CD0000001021C08E77C0454961000C914BD1C37FABC05509CD0000001021C37FABC05539CD112110102E2644B35053B69B2002112561C37FABC04509CD0001001041CC0EA4004350EF90044410B1CC0EA4004350EF90041110BPBXProjectModuleGUID11E0B1FE06471DED0097A5F4PBXProjectModuleLabelFilesPBXProjectStructureProvidedyesPBXSmartGroupTreeModuleColumnDataPBXSmartGroupTreeModuleColumnWidthsKey186PBXSmartGroupTreeModuleColumnsKey_v4MainColumnPBXSmartGroupTreeModuleOutlineStateKey_v7PBXSmartGroupTreeModuleOutlineStateExpansionKey29B97314FDCFA39411CA2CEA1C37FABC05509CD000000102PBXSmartGroupTreeModuleOutlineStateSelectionKey0PBXSmartGroupTreeModuleOutlineStateVisibleRectKey{{0, 0}, {186, 337}}PBXTopSmartGroupGIDsXCIncludePerspectivesSwitch1XCSharingTokencom.apple.Xcode.GFSharingTokenGeometryConfigurationFrame{{0, 0}, {203, 355}}GroupTreeTableConfigurationMainColumn186RubberWindowFrame373 269 690 397 0 0 1440 878 ModulePBXSmartGroupTreeModuleProportion100%NameMorphPreferredWidth300ServiceClassesXCModuleDockPBXSmartGroupTreeModuleTableOfContents11E0B1FE06471DED0097A5F4ToolbarConfigurationxcode.toolbar.config.default.shortV3PerspectivesBarVisibleShelfIsVisibleSourceDescriptionfile at '/Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources/XCPerspectivesSpecificationMode1.xcperspec'StatusbarIsVisibleTimeStamp0.0ToolbarDisplayMode1ToolbarIsVisibleToolbarSizeMode1TypePerspectivesUpdateMessageThe Default Workspace in this version of Xcode now includes support to hide and show the detail view (what has been referred to as the "Metro-Morph" feature). You must discard your current Default Workspace settings and update to the latest Default Workspace in order to gain this feature. Do you wish to update to the latest Workspace defaults for project '%@'?WindowJustification5WindowOrderList/Users/blam/code/lightblue/trunk/src/mac/LightAquaBlue/LightAquaBlue.xcodeprojWindowString149 115 922 592 0 0 1280 778 WindowToolsV3IdentifierwindowTool.buildLayoutDockContentConfigurationPBXProjectModuleGUID1CD0528F0623707200166675PBXProjectModuleLabel<No Editor>PBXSplitModuleInNavigatorKeySplit0PBXProjectModuleGUID1CD052900623707200166675SplitCount1StatusBarVisibility1GeometryConfigurationFrame{{0, 0}, {500, 215}}RubberWindowFrame192 257 500 500 0 0 1280 1002 ModulePBXNavigatorGroupProportion218ptBecomeActive1ContentConfigurationPBXProjectModuleGUIDXCMainBuildResultsModuleGUIDPBXProjectModuleLabelBuildGeometryConfigurationFrame{{0, 222}, {500, 236}}RubberWindowFrame192 257 500 500 0 0 1280 1002 ModulePBXBuildResultsModuleProportion236ptProportion458ptNameBuild ResultsServiceClassesPBXBuildResultsModuleStatusbarIsVisible1TableOfContents1C78EAA5065D492600B070951C78EAA6065D492600B070951CD0528F0623707200166675XCMainBuildResultsModuleGUIDToolbarConfigurationxcode.toolbar.config.buildV3WindowString192 257 500 500 0 0 1280 1002 IdentifierwindowTool.debuggerLayoutDockContentConfigurationDebuggerHorizontalSplitView_collapsingFrameDimension0.0_indexOfCollapsedView0_percentageOfCollapsedView0.0isCollapsedyessizes{{0, 0}, {317, 164}}{{317, 0}, {377, 164}}VerticalSplitView_collapsingFrameDimension0.0_indexOfCollapsedView0_percentageOfCollapsedView0.0isCollapsedyessizes{{0, 0}, {694, 164}}{{0, 164}, {694, 216}}LauncherConfigVersion8PBXProjectModuleGUID1C162984064C10D400B95A72PBXProjectModuleLabelDebug - GLUTExamples (Underwater)GeometryConfigurationDebugConsoleDrawerSize{100, 120}DebugConsoleVisibleNoneDebugConsoleWindowFrame{{200, 200}, {500, 300}}DebugSTDIOWindowFrame{{200, 200}, {500, 300}}Frame{{0, 0}, {694, 380}}RubberWindowFrame321 238 694 422 0 0 1440 878 ModulePBXDebugSessionModuleProportion100%Proportion100%NameDebuggerServiceClassesPBXDebugSessionModuleStatusbarIsVisible1TableOfContents1CD10A99069EF8BA00B067201C0AD2AB069F1E9B00FABCE61C162984064C10D400B95A721C0AD2AC069F1E9B00FABCE6ToolbarConfigurationxcode.toolbar.config.debugV3WindowString321 238 694 422 0 0 1440 878 WindowToolGUID1CD10A99069EF8BA00B06720WindowToolIsVisible0IdentifierwindowTool.findLayoutDockDockContentConfigurationPBXProjectModuleGUID1CDD528C0622207200134675PBXProjectModuleLabel<No Editor>PBXSplitModuleInNavigatorKeySplit0PBXProjectModuleGUID1CD0528D0623707200166675SplitCount1StatusBarVisibility1GeometryConfigurationFrame{{0, 0}, {781, 167}}RubberWindowFrame62 385 781 470 0 0 1440 878 ModulePBXNavigatorGroupProportion781ptProportion50%BecomeActive1ContentConfigurationPBXProjectModuleGUID1CD0528E0623707200166675PBXProjectModuleLabelProject FindGeometryConfigurationFrame{{8, 0}, {773, 254}}RubberWindowFrame62 385 781 470 0 0 1440 878 ModulePBXProjectFindModuleProportion50%Proportion428ptNameProject FindServiceClassesPBXProjectFindModuleStatusbarIsVisible1TableOfContents1C530D57069F1CE1000CFCEE1C530D58069F1CE1000CFCEE1C530D59069F1CE1000CFCEE1CDD528C06222072001346751C530D5A069F1CE1000CFCEE1CE0B1FE06471DED0097A5F41CD0528E0623707200166675WindowString62 385 781 470 0 0 1440 878 WindowToolGUID1C530D57069F1CE1000CFCEEWindowToolIsVisible0IdentifierMENUSEPARATORIdentifierwindowTool.debuggerConsoleLayoutDockBecomeActive1ContentConfigurationPBXProjectModuleGUID1C78EAAC065D492600B07095PBXProjectModuleLabelDebugger ConsoleGeometryConfigurationFrame{{0, 0}, {650, 250}}RubberWindowFrame516 632 650 250 0 0 1680 1027 ModulePBXDebugCLIModuleProportion209ptProportion209ptNameDebugger ConsoleServiceClassesPBXDebugCLIModuleStatusbarIsVisible1TableOfContents1C78EAAD065D492600B070951C78EAAE065D492600B070951C78EAAC065D492600B07095ToolbarConfigurationxcode.toolbar.config.consoleV3WindowString650 41 650 250 0 0 1280 1002 WindowToolGUID1C78EAAD065D492600B07095WindowToolIsVisible0IdentifierwindowTool.snapshotsLayoutDockModuleXCSnapshotModuleProportion100%Proportion100%NameSnapshotsServiceClassesXCSnapshotModuleStatusbarIsVisibleYesToolbarConfigurationxcode.toolbar.config.snapshotsWindowString315 824 300 550 0 0 1440 878 WindowToolIsVisibleYesIdentifierwindowTool.scmLayoutDockContentConfigurationPBXProjectModuleGUID1C78EAB2065D492600B07095PBXProjectModuleLabel<No Editor>PBXSplitModuleInNavigatorKeySplit0PBXProjectModuleGUID1C78EAB3065D492600B07095SplitCount1StatusBarVisibility1GeometryConfigurationFrame{{0, 0}, {452, 0}}RubberWindowFrame743 379 452 308 0 0 1280 1002 ModulePBXNavigatorGroupProportion0ptBecomeActive1ContentConfigurationPBXProjectModuleGUID1CD052920623707200166675PBXProjectModuleLabelSCMGeometryConfigurationConsoleFrame{{0, 259}, {452, 0}}Frame{{0, 7}, {452, 259}}RubberWindowFrame743 379 452 308 0 0 1280 1002 TableConfigurationStatus30FileName199Path197.09500122070312TableFrame{{0, 0}, {452, 250}}ModulePBXCVSModuleProportion262ptProportion266ptNameSCMServiceClassesPBXCVSModuleStatusbarIsVisible1TableOfContents1C78EAB4065D492600B070951C78EAB5065D492600B070951C78EAB2065D492600B070951CD052920623707200166675ToolbarConfigurationxcode.toolbar.config.scmWindowString743 379 452 308 0 0 1280 1002 IdentifierwindowTool.breakpointsIsVertical0LayoutDockBecomeActive1ContentConfigurationPBXBottomSmartGroupGIDs1C77FABC04509CD000000102PBXProjectModuleGUID1CE0B1FE06471DED0097A5F4PBXProjectModuleLabelFilesPBXProjectStructureProvidednoPBXSmartGroupTreeModuleColumnDataPBXSmartGroupTreeModuleColumnWidthsKey168PBXSmartGroupTreeModuleColumnsKey_v4MainColumnPBXSmartGroupTreeModuleOutlineStateKey_v7PBXSmartGroupTreeModuleOutlineStateExpansionKey1C77FABC04509CD000000102PBXSmartGroupTreeModuleOutlineStateSelectionKey0PBXSmartGroupTreeModuleOutlineStateVisibleRectKey{{0, 0}, {168, 350}}PBXTopSmartGroupGIDsXCIncludePerspectivesSwitch0GeometryConfigurationFrame{{0, 0}, {185, 368}}GroupTreeTableConfigurationMainColumn168RubberWindowFrame315 424 744 409 0 0 1440 878 ModulePBXSmartGroupTreeModuleProportion185ptContentConfigurationPBXProjectModuleGUID1CA1AED706398EBD00589147PBXProjectModuleLabelDetailGeometryConfigurationFrame{{190, 0}, {554, 368}}RubberWindowFrame315 424 744 409 0 0 1440 878 ModuleXCDetailModuleProportion554ptProportion368ptMajorVersion3MinorVersion0NameBreakpointsServiceClassesPBXSmartGroupTreeModuleXCDetailModuleStatusbarIsVisible1TableOfContents1CDDB66807F98D9800BB58171CDDB66907F98D9800BB58171CE0B1FE06471DED0097A5F41CA1AED706398EBD00589147ToolbarConfigurationxcode.toolbar.config.breakpointsV3WindowString315 424 744 409 0 0 1440 878 WindowToolGUID1CDDB66807F98D9800BB5817WindowToolIsVisible1IdentifierwindowTool.debugAnimatorLayoutDockModulePBXNavigatorGroupProportion100%Proportion100%NameDebug VisualizerServiceClassesPBXNavigatorGroupStatusbarIsVisible1ToolbarConfigurationxcode.toolbar.config.debugAnimatorV3WindowString100 100 700 500 0 0 1280 1002 IdentifierwindowTool.bookmarksLayoutDockModulePBXBookmarksModuleProportion100%Proportion100%NameBookmarksServiceClassesPBXBookmarksModuleStatusbarIsVisible0WindowString538 42 401 187 0 0 1280 1002 IdentifierwindowTool.projectFormatConflictsLayoutDockModuleXCProjectFormatConflictsModuleProportion100%Proportion100%NameProject Format ConflictsServiceClassesXCProjectFormatConflictsModuleStatusbarIsVisible0WindowContentMinSize450 300WindowString50 850 472 307 0 0 1440 877IdentifierwindowTool.classBrowserLayoutDockBecomeActive1ContentConfigurationOptionsSetNameHierarchy, all classesPBXProjectModuleGUID1CA6456E063B45B4001379D8PBXProjectModuleLabelClass Browser - NSObjectGeometryConfigurationClassesFrame{{0, 0}, {374, 96}}ClassesTreeTableConfigurationPBXClassNameColumnIdentifier208PBXClassBookColumnIdentifier22Frame{{0, 0}, {630, 331}}MembersFrame{{0, 105}, {374, 395}}MembersTreeTableConfigurationPBXMemberTypeIconColumnIdentifier22PBXMemberNameColumnIdentifier216PBXMemberTypeColumnIdentifier97PBXMemberBookColumnIdentifier22PBXModuleWindowStatusBarHidden21RubberWindowFrame385 179 630 352 0 0 1440 878 ModulePBXClassBrowserModuleProportion332ptProportion332ptNameClass BrowserServiceClassesPBXClassBrowserModuleStatusbarIsVisible0TableOfContents1C0AD2AF069F1E9B00FABCE61C0AD2B0069F1E9B00FABCE61CA6456E063B45B4001379D8ToolbarConfigurationxcode.toolbar.config.classbrowserWindowString385 179 630 352 0 0 1440 878 WindowToolGUID1C0AD2AF069F1E9B00FABCE6WindowToolIsVisible0IdentifierwindowTool.refactoringIncludeInToolsMenu0LayoutDockBecomeActive1GeometryConfigurationFrame{0, 0}, {500, 335}RubberWindowFrame{0, 0}, {500, 335}ModuleXCRefactoringModuleProportion100%Proportion100%NameRefactoringServiceClassesXCRefactoringModuleWindowString200 200 500 356 0 0 1920 1200
pybluez-0.23/macos/LightAquaBlue/LightAquaBlue.xcodeproj/project.pbxproj 0000664 0000000 0000000 00000062574 13601523637 0026504 0 ustar 00root root 0000000 0000000 // !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
2A841F731FBC0935008778A4 /* BridgeSupport in Resources */ = {isa = PBXBuildFile; fileRef = 2A841F721FBC0935008778A4 /* BridgeSupport */; };
8100016A0D09536000FA9985 /* BBStreamingOutputStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 810001680D09536000FA9985 /* BBStreamingOutputStream.h */; settings = {ATTRIBUTES = (Public, ); }; };
8100016B0D09536000FA9985 /* BBStreamingOutputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 810001690D09536000FA9985 /* BBStreamingOutputStream.m */; };
8100FE030D056D0100FA9985 /* BBBluetoothOBEXClient.h in Headers */ = {isa = PBXBuildFile; fileRef = 8100FDEB0D056D0000FA9985 /* BBBluetoothOBEXClient.h */; settings = {ATTRIBUTES = (Public, ); }; };
8100FE040D056D0100FA9985 /* BBBluetoothOBEXClient.m in Sources */ = {isa = PBXBuildFile; fileRef = 8100FDEC0D056D0000FA9985 /* BBBluetoothOBEXClient.m */; };
8100FE050D056D0100FA9985 /* BBBluetoothOBEXServer.h in Headers */ = {isa = PBXBuildFile; fileRef = 8100FDED0D056D0000FA9985 /* BBBluetoothOBEXServer.h */; settings = {ATTRIBUTES = (Public, ); }; };
8100FE060D056D0100FA9985 /* BBBluetoothOBEXServer.m in Sources */ = {isa = PBXBuildFile; fileRef = 8100FDEE0D056D0000FA9985 /* BBBluetoothOBEXServer.m */; };
8100FE070D056D0100FA9985 /* BBStreamingInputStream.h in Headers */ = {isa = PBXBuildFile; fileRef = 8100FDEF0D056D0000FA9985 /* BBStreamingInputStream.h */; settings = {ATTRIBUTES = (Public, ); }; };
8100FE080D056D0100FA9985 /* BBStreamingInputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 8100FDF00D056D0000FA9985 /* BBStreamingInputStream.m */; };
8100FE090D056D0100FA9985 /* BBLocalDevice.h in Headers */ = {isa = PBXBuildFile; fileRef = 8100FDF10D056D0000FA9985 /* BBLocalDevice.h */; settings = {ATTRIBUTES = (Public, ); }; };
8100FE0A0D056D0100FA9985 /* BBLocalDevice.m in Sources */ = {isa = PBXBuildFile; fileRef = 8100FDF20D056D0000FA9985 /* BBLocalDevice.m */; };
8100FE0B0D056D0100FA9985 /* BBMutableOBEXHeaderSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 8100FDF30D056D0000FA9985 /* BBMutableOBEXHeaderSet.h */; settings = {ATTRIBUTES = (Public, ); }; };
8100FE0C0D056D0100FA9985 /* BBMutableOBEXHeaderSet.m in Sources */ = {isa = PBXBuildFile; fileRef = 8100FDF40D056D0000FA9985 /* BBMutableOBEXHeaderSet.m */; };
8100FE0D0D056D0100FA9985 /* BBOBEXHeaderSet.h in Headers */ = {isa = PBXBuildFile; fileRef = 8100FDF50D056D0000FA9985 /* BBOBEXHeaderSet.h */; settings = {ATTRIBUTES = (Public, ); }; };
8100FE0E0D056D0100FA9985 /* BBOBEXHeaderSet.m in Sources */ = {isa = PBXBuildFile; fileRef = 8100FDF60D056D0000FA9985 /* BBOBEXHeaderSet.m */; };
8100FE0F0D056D0100FA9985 /* BBOBEXRequest.h in Headers */ = {isa = PBXBuildFile; fileRef = 8100FDF70D056D0100FA9985 /* BBOBEXRequest.h */; settings = {ATTRIBUTES = (Public, ); }; };
8100FE100D056D0100FA9985 /* BBOBEXRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 8100FDF80D056D0100FA9985 /* BBOBEXRequest.m */; };
8100FE110D056D0100FA9985 /* BBOBEXRequestHandler.h in Headers */ = {isa = PBXBuildFile; fileRef = 8100FDF90D056D0100FA9985 /* BBOBEXRequestHandler.h */; settings = {ATTRIBUTES = (Public, ); }; };
8100FE120D056D0100FA9985 /* BBOBEXRequestHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 8100FDFA0D056D0100FA9985 /* BBOBEXRequestHandler.m */; };
8100FE150D056D0100FA9985 /* BBServiceAdvertiser.h in Headers */ = {isa = PBXBuildFile; fileRef = 8100FDFD0D056D0100FA9985 /* BBServiceAdvertiser.h */; settings = {ATTRIBUTES = (Public, ); }; };
8100FE160D056D0100FA9985 /* BBServiceAdvertiser.m in Sources */ = {isa = PBXBuildFile; fileRef = 8100FDFE0D056D0100FA9985 /* BBServiceAdvertiser.m */; };
8100FE170D056D0100FA9985 /* LightAquaBlue.h in Headers */ = {isa = PBXBuildFile; fileRef = 8100FDFF0D056D0100FA9985 /* LightAquaBlue.h */; settings = {ATTRIBUTES = (Public, ); }; };
8100FE180D056D0100FA9985 /* OBEXFileTransferDictionary.plist in Resources */ = {isa = PBXBuildFile; fileRef = 8100FE000D056D0100FA9985 /* OBEXFileTransferDictionary.plist */; };
8100FE190D056D0100FA9985 /* OBEXObjectPushDictionary.plist in Resources */ = {isa = PBXBuildFile; fileRef = 8100FE010D056D0100FA9985 /* OBEXObjectPushDictionary.plist */; };
8100FE1A0D056D0100FA9985 /* SerialPortDictionary.plist in Resources */ = {isa = PBXBuildFile; fileRef = 8100FE020D056D0100FA9985 /* SerialPortDictionary.plist */; };
8100FE1C0D056D4300FA9985 /* IOBluetooth.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8100FE1B0D056D4300FA9985 /* IOBluetooth.framework */; };
817D21A30D3D7FA500469B5D /* BBBluetoothChannelDelegate.h in Headers */ = {isa = PBXBuildFile; fileRef = 817D21A10D3D7FA500469B5D /* BBBluetoothChannelDelegate.h */; settings = {ATTRIBUTES = (Public, ); }; };
817D21A40D3D7FA500469B5D /* BBBluetoothChannelDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 817D21A20D3D7FA500469B5D /* BBBluetoothChannelDelegate.m */; };
817D239D0D40313600469B5D /* BBOBEXResponse.h in Headers */ = {isa = PBXBuildFile; fileRef = 817D239B0D40313600469B5D /* BBOBEXResponse.h */; settings = {ATTRIBUTES = (Public, ); }; };
817D239E0D40313600469B5D /* BBOBEXResponse.m in Sources */ = {isa = PBXBuildFile; fileRef = 817D239C0D40313600469B5D /* BBOBEXResponse.m */; };
8DC2EF570486A6940098B216 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
0867D69BFE84028FC02AAC07 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; };
0867D6A5FE840307C02AAC07 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; };
089C1667FE841158C02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; };
1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; };
2A841F721FBC0935008778A4 /* BridgeSupport */ = {isa = PBXFileReference; lastKnownFileType = folder; path = BridgeSupport; sourceTree = ""; };
32DBCF5E0370ADEE00C91783 /* LightAquaBlue_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LightAquaBlue_Prefix.pch; sourceTree = ""; };
810001680D09536000FA9985 /* BBStreamingOutputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BBStreamingOutputStream.h; sourceTree = ""; };
810001690D09536000FA9985 /* BBStreamingOutputStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BBStreamingOutputStream.m; sourceTree = ""; };
8100FDEB0D056D0000FA9985 /* BBBluetoothOBEXClient.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = BBBluetoothOBEXClient.h; sourceTree = ""; };
8100FDEC0D056D0000FA9985 /* BBBluetoothOBEXClient.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = BBBluetoothOBEXClient.m; sourceTree = ""; };
8100FDED0D056D0000FA9985 /* BBBluetoothOBEXServer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = BBBluetoothOBEXServer.h; sourceTree = ""; };
8100FDEE0D056D0000FA9985 /* BBBluetoothOBEXServer.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = BBBluetoothOBEXServer.m; sourceTree = ""; };
8100FDEF0D056D0000FA9985 /* BBStreamingInputStream.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = BBStreamingInputStream.h; sourceTree = ""; };
8100FDF00D056D0000FA9985 /* BBStreamingInputStream.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = BBStreamingInputStream.m; sourceTree = ""; };
8100FDF10D056D0000FA9985 /* BBLocalDevice.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = BBLocalDevice.h; sourceTree = ""; };
8100FDF20D056D0000FA9985 /* BBLocalDevice.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = BBLocalDevice.m; sourceTree = ""; };
8100FDF30D056D0000FA9985 /* BBMutableOBEXHeaderSet.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = BBMutableOBEXHeaderSet.h; sourceTree = ""; };
8100FDF40D056D0000FA9985 /* BBMutableOBEXHeaderSet.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = BBMutableOBEXHeaderSet.m; sourceTree = ""; };
8100FDF50D056D0000FA9985 /* BBOBEXHeaderSet.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = BBOBEXHeaderSet.h; sourceTree = ""; };
8100FDF60D056D0000FA9985 /* BBOBEXHeaderSet.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = BBOBEXHeaderSet.m; sourceTree = ""; };
8100FDF70D056D0100FA9985 /* BBOBEXRequest.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = BBOBEXRequest.h; sourceTree = ""; };
8100FDF80D056D0100FA9985 /* BBOBEXRequest.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = BBOBEXRequest.m; sourceTree = ""; };
8100FDF90D056D0100FA9985 /* BBOBEXRequestHandler.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = BBOBEXRequestHandler.h; sourceTree = ""; };
8100FDFA0D056D0100FA9985 /* BBOBEXRequestHandler.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = BBOBEXRequestHandler.m; sourceTree = ""; };
8100FDFD0D056D0100FA9985 /* BBServiceAdvertiser.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = BBServiceAdvertiser.h; sourceTree = ""; };
8100FDFE0D056D0100FA9985 /* BBServiceAdvertiser.m */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.objc; path = BBServiceAdvertiser.m; sourceTree = ""; };
8100FDFF0D056D0100FA9985 /* LightAquaBlue.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = LightAquaBlue.h; sourceTree = ""; };
8100FE000D056D0100FA9985 /* OBEXFileTransferDictionary.plist */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.plist.xml; path = OBEXFileTransferDictionary.plist; sourceTree = ""; };
8100FE010D056D0100FA9985 /* OBEXObjectPushDictionary.plist */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.plist.xml; path = OBEXObjectPushDictionary.plist; sourceTree = ""; };
8100FE020D056D0100FA9985 /* SerialPortDictionary.plist */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.plist.xml; path = SerialPortDictionary.plist; sourceTree = ""; };
8100FE1B0D056D4300FA9985 /* IOBluetooth.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOBluetooth.framework; path = /System/Library/Frameworks/IOBluetooth.framework; sourceTree = ""; };
817D21A10D3D7FA500469B5D /* BBBluetoothChannelDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BBBluetoothChannelDelegate.h; sourceTree = ""; };
817D21A20D3D7FA500469B5D /* BBBluetoothChannelDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BBBluetoothChannelDelegate.m; sourceTree = ""; };
817D239B0D40313600469B5D /* BBOBEXResponse.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BBOBEXResponse.h; sourceTree = ""; };
817D239C0D40313600469B5D /* BBOBEXResponse.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BBOBEXResponse.m; sourceTree = ""; };
8DC2EF5A0486A6940098B216 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; };
8DC2EF5B0486A6940098B216 /* LightAquaBlue.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = LightAquaBlue.framework; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
8DC2EF560486A6940098B216 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
8DC2EF570486A6940098B216 /* Cocoa.framework in Frameworks */,
8100FE1C0D056D4300FA9985 /* IOBluetooth.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
034768DFFF38A50411DB9C8B /* Products */ = {
isa = PBXGroup;
children = (
8DC2EF5B0486A6940098B216 /* LightAquaBlue.framework */,
);
name = Products;
sourceTree = "";
};
0867D691FE84028FC02AAC07 /* LightAquaBlue */ = {
isa = PBXGroup;
children = (
8100FDFF0D056D0100FA9985 /* LightAquaBlue.h */,
08FB77AEFE84172EC02AAC07 /* Classes */,
32C88DFF0371C24200C91783 /* Other Sources */,
089C1665FE841158C02AAC07 /* Resources */,
0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */,
034768DFFF38A50411DB9C8B /* Products */,
);
name = LightAquaBlue;
sourceTree = "";
};
0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */ = {
isa = PBXGroup;
children = (
8100FE1B0D056D4300FA9985 /* IOBluetooth.framework */,
1058C7B0FEA5585E11CA2CBB /* Linked Frameworks */,
1058C7B2FEA5585E11CA2CBB /* Other Frameworks */,
);
name = "External Frameworks and Libraries";
sourceTree = "";
};
089C1665FE841158C02AAC07 /* Resources */ = {
isa = PBXGroup;
children = (
2A841F721FBC0935008778A4 /* BridgeSupport */,
8100FE000D056D0100FA9985 /* OBEXFileTransferDictionary.plist */,
8100FE010D056D0100FA9985 /* OBEXObjectPushDictionary.plist */,
8100FE020D056D0100FA9985 /* SerialPortDictionary.plist */,
8DC2EF5A0486A6940098B216 /* Info.plist */,
089C1666FE841158C02AAC07 /* InfoPlist.strings */,
);
name = Resources;
sourceTree = "";
};
08FB77AEFE84172EC02AAC07 /* Classes */ = {
isa = PBXGroup;
children = (
810001680D09536000FA9985 /* BBStreamingOutputStream.h */,
810001690D09536000FA9985 /* BBStreamingOutputStream.m */,
8100FDEB0D056D0000FA9985 /* BBBluetoothOBEXClient.h */,
8100FDEC0D056D0000FA9985 /* BBBluetoothOBEXClient.m */,
8100FDED0D056D0000FA9985 /* BBBluetoothOBEXServer.h */,
8100FDEE0D056D0000FA9985 /* BBBluetoothOBEXServer.m */,
8100FDEF0D056D0000FA9985 /* BBStreamingInputStream.h */,
8100FDF00D056D0000FA9985 /* BBStreamingInputStream.m */,
8100FDF10D056D0000FA9985 /* BBLocalDevice.h */,
8100FDF20D056D0000FA9985 /* BBLocalDevice.m */,
8100FDF30D056D0000FA9985 /* BBMutableOBEXHeaderSet.h */,
8100FDF40D056D0000FA9985 /* BBMutableOBEXHeaderSet.m */,
8100FDF50D056D0000FA9985 /* BBOBEXHeaderSet.h */,
8100FDF60D056D0000FA9985 /* BBOBEXHeaderSet.m */,
8100FDF70D056D0100FA9985 /* BBOBEXRequest.h */,
8100FDF80D056D0100FA9985 /* BBOBEXRequest.m */,
8100FDF90D056D0100FA9985 /* BBOBEXRequestHandler.h */,
8100FDFA0D056D0100FA9985 /* BBOBEXRequestHandler.m */,
8100FDFD0D056D0100FA9985 /* BBServiceAdvertiser.h */,
8100FDFE0D056D0100FA9985 /* BBServiceAdvertiser.m */,
817D21A10D3D7FA500469B5D /* BBBluetoothChannelDelegate.h */,
817D21A20D3D7FA500469B5D /* BBBluetoothChannelDelegate.m */,
817D239B0D40313600469B5D /* BBOBEXResponse.h */,
817D239C0D40313600469B5D /* BBOBEXResponse.m */,
);
name = Classes;
sourceTree = "";
};
1058C7B0FEA5585E11CA2CBB /* Linked Frameworks */ = {
isa = PBXGroup;
children = (
1058C7B1FEA5585E11CA2CBB /* Cocoa.framework */,
);
name = "Linked Frameworks";
sourceTree = "";
};
1058C7B2FEA5585E11CA2CBB /* Other Frameworks */ = {
isa = PBXGroup;
children = (
0867D6A5FE840307C02AAC07 /* AppKit.framework */,
0867D69BFE84028FC02AAC07 /* Foundation.framework */,
);
name = "Other Frameworks";
sourceTree = "";
};
32C88DFF0371C24200C91783 /* Other Sources */ = {
isa = PBXGroup;
children = (
32DBCF5E0370ADEE00C91783 /* LightAquaBlue_Prefix.pch */,
);
name = "Other Sources";
sourceTree = "";
};
/* End PBXGroup section */
/* Begin PBXHeadersBuildPhase section */
8DC2EF500486A6940098B216 /* Headers */ = {
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
8100FE030D056D0100FA9985 /* BBBluetoothOBEXClient.h in Headers */,
8100FE050D056D0100FA9985 /* BBBluetoothOBEXServer.h in Headers */,
8100FE070D056D0100FA9985 /* BBStreamingInputStream.h in Headers */,
8100FE090D056D0100FA9985 /* BBLocalDevice.h in Headers */,
8100FE0B0D056D0100FA9985 /* BBMutableOBEXHeaderSet.h in Headers */,
8100FE0D0D056D0100FA9985 /* BBOBEXHeaderSet.h in Headers */,
8100FE0F0D056D0100FA9985 /* BBOBEXRequest.h in Headers */,
8100FE110D056D0100FA9985 /* BBOBEXRequestHandler.h in Headers */,
8100FE150D056D0100FA9985 /* BBServiceAdvertiser.h in Headers */,
8100FE170D056D0100FA9985 /* LightAquaBlue.h in Headers */,
8100016A0D09536000FA9985 /* BBStreamingOutputStream.h in Headers */,
817D21A30D3D7FA500469B5D /* BBBluetoothChannelDelegate.h in Headers */,
817D239D0D40313600469B5D /* BBOBEXResponse.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXHeadersBuildPhase section */
/* Begin PBXNativeTarget section */
8DC2EF4F0486A6940098B216 /* LightAquaBlue */ = {
isa = PBXNativeTarget;
buildConfigurationList = 1DEB91AD08733DA50010E9CD /* Build configuration list for PBXNativeTarget "LightAquaBlue" */;
buildPhases = (
8DC2EF500486A6940098B216 /* Headers */,
8DC2EF520486A6940098B216 /* Resources */,
8DC2EF540486A6940098B216 /* Sources */,
8DC2EF560486A6940098B216 /* Frameworks */,
);
buildRules = (
);
dependencies = (
);
name = LightAquaBlue;
productInstallPath = "$(HOME)/Library/Frameworks";
productName = LightAquaBlue;
productReference = 8DC2EF5B0486A6940098B216 /* LightAquaBlue.framework */;
productType = "com.apple.product-type.framework";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
0867D690FE84028FC02AAC07 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0910;
};
buildConfigurationList = 1DEB91B108733DA50010E9CD /* Build configuration list for PBXProject "LightAquaBlue" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 1;
knownRegions = (
en,
);
mainGroup = 0867D691FE84028FC02AAC07 /* LightAquaBlue */;
productRefGroup = 034768DFFF38A50411DB9C8B /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
8DC2EF4F0486A6940098B216 /* LightAquaBlue */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
8DC2EF520486A6940098B216 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8100FE180D056D0100FA9985 /* OBEXFileTransferDictionary.plist in Resources */,
8100FE190D056D0100FA9985 /* OBEXObjectPushDictionary.plist in Resources */,
8100FE1A0D056D0100FA9985 /* SerialPortDictionary.plist in Resources */,
2A841F731FBC0935008778A4 /* BridgeSupport in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
8DC2EF540486A6940098B216 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8100FE040D056D0100FA9985 /* BBBluetoothOBEXClient.m in Sources */,
8100FE060D056D0100FA9985 /* BBBluetoothOBEXServer.m in Sources */,
8100FE080D056D0100FA9985 /* BBStreamingInputStream.m in Sources */,
8100FE0A0D056D0100FA9985 /* BBLocalDevice.m in Sources */,
8100FE0C0D056D0100FA9985 /* BBMutableOBEXHeaderSet.m in Sources */,
8100FE0E0D056D0100FA9985 /* BBOBEXHeaderSet.m in Sources */,
8100FE100D056D0100FA9985 /* BBOBEXRequest.m in Sources */,
8100FE120D056D0100FA9985 /* BBOBEXRequestHandler.m in Sources */,
8100FE160D056D0100FA9985 /* BBServiceAdvertiser.m in Sources */,
8100016B0D09536000FA9985 /* BBStreamingOutputStream.m in Sources */,
817D21A40D3D7FA500469B5D /* BBBluetoothChannelDelegate.m in Sources */,
817D239E0D40313600469B5D /* BBOBEXResponse.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXVariantGroup section */
089C1666FE841158C02AAC07 /* InfoPlist.strings */ = {
isa = PBXVariantGroup;
children = (
089C1667FE841158C02AAC07 /* English */,
);
name = InfoPlist.strings;
sourceTree = "";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
1DEB91AE08733DA50010E9CD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
COPY_PHASE_STRIP = NO;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
FRAMEWORK_VERSION = A;
GCC_DYNAMIC_NO_PIC = NO;
GCC_MODEL_TUNING = G5;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = LightAquaBlue_Prefix.pch;
INFOPLIST_FILE = Info.plist;
INSTALL_PATH = "$(HOME)/Library/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.blammit.LightAquaBlue;
PRODUCT_NAME = LightAquaBlue;
WRAPPER_EXTENSION = framework;
ZERO_LINK = YES;
};
name = Debug;
};
1DEB91AF08733DA50010E9CD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 1;
FRAMEWORK_VERSION = A;
GCC_GENERATE_DEBUGGING_SYMBOLS = NO;
GCC_MODEL_TUNING = G5;
GCC_PRECOMPILE_PREFIX_HEADER = YES;
GCC_PREFIX_HEADER = LightAquaBlue_Prefix.pch;
INFOPLIST_FILE = Info.plist;
INSTALL_PATH = "$(HOME)/Library/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = com.blammit.LightAquaBlue;
PRODUCT_NAME = LightAquaBlue;
WRAPPER_EXTENSION = framework;
};
name = Release;
};
1DEB91B208733DA50010E9CD /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
MACOSX_DEPLOYMENT_TARGET = "";
ONLY_ACTIVE_ARCH = YES;
};
name = Debug;
};
1DEB91B308733DA50010E9CD /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
1DEB91AD08733DA50010E9CD /* Build configuration list for PBXNativeTarget "LightAquaBlue" */ = {
isa = XCConfigurationList;
buildConfigurations = (
1DEB91AE08733DA50010E9CD /* Debug */,
1DEB91AF08733DA50010E9CD /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
1DEB91B108733DA50010E9CD /* Build configuration list for PBXProject "LightAquaBlue" */ = {
isa = XCConfigurationList;
buildConfigurations = (
1DEB91B208733DA50010E9CD /* Debug */,
1DEB91B308733DA50010E9CD /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 0867D690FE84028FC02AAC07 /* Project object */;
}
pybluez-0.23/macos/LightAquaBlue/LightAquaBlue.xcodeproj/project.xcworkspace/ 0000775 0000000 0000000 00000000000 13601523637 0027410 5 ustar 00root root 0000000 0000000 contents.xcworkspacedata 0000664 0000000 0000000 00000000207 13601523637 0034272 0 ustar 00root root 0000000 0000000 pybluez-0.23/macos/LightAquaBlue/LightAquaBlue.xcodeproj/project.xcworkspace
pybluez-0.23/macos/LightAquaBlue/LightAquaBlue.xcodeproj/project.xcworkspace/xcshareddata/ 0000775 0000000 0000000 00000000000 13601523637 0032043 5 ustar 00root root 0000000 0000000 IDEWorkspaceChecks.plist 0000664 0000000 0000000 00000000356 13601523637 0036446 0 ustar 00root root 0000000 0000000 pybluez-0.23/macos/LightAquaBlue/LightAquaBlue.xcodeproj/project.xcworkspace/xcshareddata
IDEDidComputeMac32BitWarning
WorkspaceSettings.xcsettings 0000664 0000000 0000000 00000000265 13601523637 0037563 0 ustar 00root root 0000000 0000000 pybluez-0.23/macos/LightAquaBlue/LightAquaBlue.xcodeproj/project.xcworkspace/xcshareddata
pybluez-0.23/macos/LightAquaBlue/LightAquaBlue_Prefix.pch 0000664 0000000 0000000 00000000236 13601523637 0023430 0 ustar 00root root 0000000 0000000 //
// Prefix header for all source files of the 'LightAquaBlue' target in the 'LightAquaBlue' project.
//
#ifdef __OBJC__
#import
#endif
pybluez-0.23/macos/LightAquaBlue/OBEXFileTransferDictionary.plist 0000664 0000000 0000000 00000003540 13601523637 0025076 0 ustar 00root root 0000000 0000000
0001 - ServiceClassIDList
EQY=
0004 - ProtocolDescriptorList
AQA=
AAM=
DataElementSize1DataElementType1DataElementValue3
AAg=
0005 - BrowseGroupList*
EAI=
0006 - LanguageBaseAttributeIDList*DataElementSize2DataElementType1DataElementValue25966DataElementSize2DataElementType1DataElementValue106DataElementSize2DataElementType1DataElementValue2560009 - BluetoothProfileDescriptorList
EQY=
DataElementSize2DataElementType1DataElementValue2560303 - Supported Formats ListDataElementType1DataElementValue
/w==
pybluez-0.23/macos/LightAquaBlue/OBEXObjectPushDictionary.plist 0000664 0000000 0000000 00000003540 13601523637 0024560 0 ustar 00root root 0000000 0000000
0001 - ServiceClassIDList
EQU=
0004 - ProtocolDescriptorList
AQA=
AAM=
DataElementSize1DataElementType1DataElementValue3
AAg=
0005 - BrowseGroupList*
EAI=
0006 - LanguageBaseAttributeIDList*DataElementSize2DataElementType1DataElementValue25966DataElementSize2DataElementType1DataElementValue106DataElementSize2DataElementType1DataElementValue2560009 - BluetoothProfileDescriptorList
EQU=
DataElementSize2DataElementType1DataElementValue2560303 - Supported Formats ListDataElementType1DataElementValue
/w==
pybluez-0.23/macos/LightAquaBlue/SerialPortDictionary.plist 0000664 0000000 0000000 00000003456 13601523637 0024126 0 ustar 00root root 0000000 0000000
0001 - ServiceClassIDList
EQE=
0004 - ProtocolDescriptorList
AQA=
AAM=
DataElementSize1DataElementType1DataElementValue30005 - BrowseGroupList*
EAI=
0006 - LanguageBaseAttributeIDList*DataElementSize2DataElementType1DataElementValue25966DataElementSize2DataElementType1DataElementValue106DataElementSize2DataElementType1DataElementValue2560009 - BluetoothProfileDescriptorList
EQE=
DataElementSize2DataElementType1DataElementValue2560303 - Supported Formats ListDataElementType1DataElementValue
/w==
pybluez-0.23/macos/LightAquaBlue/advertising-notes.txt 0000664 0000000 0000000 00000002764 13601523637 0023146 0 ustar 00root root 0000000 0000000 SerialPortDictionary.plist is a modification of the same file in the OBEXSample project available in the Mac OS X Developer examples (under 'Bluetooth').
I modified it by adding a 0x1101 (Serial Port Profile) in the ServiceClassIDList entry. Without this entry, the Nokia 6600 (and it seems Series 60 phones in general) could not find the service when searching for RFCOMM services. Other web resources seem to confirm that the 0x1101 is necessary for RFCOMM services.
How does OBEXObjectPushDictionary.plist differ from SerialPortDictionary.plist?
In OBEXObjectPushDictionary.plist:
- ServiceClassIDList property has <1105> as a data object to represent the OBEX Object Push Profile.
- BluetoothProfileDescriptorList has <1105> too as an entry.
- ProtocolDescriptorList has <0008> (for OBEX protocol) along with the L2CAP (0x0100) and RFCOMM (0x0003) entries
I used 0x1105 which is the UUID for the OBEX Object Push Profile. OBEXFileTransferDictionary uses 0x1106 instead which is the UUID for the File Transfer Profile.
The thing to do is to build a server which supports particular operations and then choose the right profile depending on whether you support the corresponding operations. E.g. if you advertise the File Transfer Profile your server should support folder browsing, and Object Push servers might support some kind of business card exchange via vCards etc.
See BluetoothAssignedNumbers.h in the IOBluetooth.framework headers for a list of all the appropriate UUIDs and numbers and what they mean.
pybluez-0.23/macos/_IOBluetooth.py 0000775 0000000 0000000 00000016067 13601523637 0017163 0 ustar 00root root 0000000 0000000 # Copyright (c) 2009 Bea Lam. All rights reserved.
#
# This file is part of LightBlue.
#
# LightBlue is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# LightBlue is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with LightBlue. If not, see .
"""
Provides a python interface to the Mac OSX IOBluetooth Framework classes,
through PyObjC.
For example:
>>> from lightblue import _IOBluetooth
>>> for d in _IOBluetooth.IOBluetoothDevice.recentDevices_(0):
... print d.getName()
...
Munkey
Adam
My Nokia 6600
>>>
See http://developer.apple.com/documentation/DeviceDrivers/Reference/IOBluetooth/index.html
for Apple's IOBluetooth documentation.
See http://pyobjc.sourceforge.net for details on how to access Objective-C
classes through PyObjC.
"""
import objc
if hasattr(objc, 'ObjCLazyModule'):
# `ObjCLazyModule` function is available for PyObjC version >= 2.4
io_bluetooth = objc.ObjCLazyModule("IOBluetooth",
frameworkIdentifier="com.apple.IOBluetooth",
frameworkPath=objc.pathForFramework(
"/System/Library/Frameworks/IOBluetooth.framework"
),
metadict=globals())
objc.registerMetaDataForSelector(b"IOBluetoothSDPServiceRecord",
b"getRFCOMMChannelID:",
dict(
arguments={
2: dict(type=objc._C_PTR + objc._C_CHAR_AS_INT, type_modifier=objc._C_OUT),
}
))
objc.registerMetaDataForSelector(b"IOBluetoothSDPServiceRecord",
b"getL2CAPPSM:",
dict(
arguments={
2: dict(type=objc._C_PTR + objc._C_CHAR_AS_INT, type_modifier=objc._C_OUT),
}
))
objc.registerMetaDataForSelector(b"IOBluetoothDevice",
b"openRFCOMMChannelSync:withChannelID:delegate:",
dict(
arguments={
2: dict(type=objc._C_PTR + objc._C_CHAR_AS_INT, type_modifier=objc._C_OUT),
2 + 1: dict(type_modifier=objc._C_IN, null_accepted=False),
2 + 3: dict(type_modifier=objc._C_IN, null_accepted=False),
}
))
objc.registerMetaDataForSelector(b"IOBluetoothDevice",
b"openL2CAPChannelSync:withPSM:delegate:",
dict(
arguments={
2: dict(type=objc._C_PTR + objc._C_CHAR_AS_INT, type_modifier=objc._C_OUT),
2 + 1: dict(type_modifier=objc._C_IN, null_accepted=False),
2 + 3: dict(type_modifier=objc._C_IN, null_accepted=False),
}
))
# This still doesn't seem to work since it's expecting (BluetoothDeviceAddress *)
# objc.registerMetaDataForSelector(b"IOBluetoothDevice",
# b"withAddress:",
# dict(
# arguments={
# 2+0: dict(type_modifier=objc._C_IN, c_array_of_fixed_length=6, null_accepted=False)
# }
# ))
locals_ = locals()
for variable_name in dir(io_bluetooth):
locals_[variable_name] = getattr(io_bluetooth, variable_name)
else:
try:
# mac os 10.5 loads frameworks using bridgesupport metadata
__bundle__ = objc.initFrameworkWrapper("IOBluetooth",
frameworkIdentifier="com.apple.IOBluetooth",
frameworkPath=objc.pathForFramework(
"/System/Library/Frameworks/IOBluetooth.framework"),
globals=globals())
except (AttributeError, ValueError):
# earlier versions use loadBundle() and setSignatureForSelector()
objc.loadBundle("IOBluetooth", globals(),
bundle_path=objc.pathForFramework('/System/Library/Frameworks/IOBluetooth.framework'))
# Sets selector signatures in order to receive arguments correctly from
# PyObjC methods. These MUST be set, otherwise the method calls won't work
# at all, mostly because you can't pass by pointers in Python.
# set to return int, and take an unsigned char output arg
# i.e. in python: return (int, unsigned char) and accept no args
objc.setSignatureForSelector("IOBluetoothSDPServiceRecord",
"getRFCOMMChannelID:", "i12@0:o^C")
# set to return int, and take an unsigned int output arg
# i.e. in python: return (int, unsigned int) and accept no args
objc.setSignatureForSelector("IOBluetoothSDPServiceRecord",
"getL2CAPPSM:", "i12@0:o^S")
# set to return int, and take (output object, unsigned char, object) args
# i.e. in python: return (int, object) and accept (unsigned char, object)
objc.setSignatureForSelector("IOBluetoothDevice",
"openRFCOMMChannelSync:withChannelID:delegate:", "i16@0:o^@C@")
# set to return int, and take (output object, unsigned int, object) args
# i.e. in python: return (int, object) and accept (unsigned int, object)
objc.setSignatureForSelector("IOBluetoothDevice",
"openL2CAPChannelSync:withPSM:delegate:", "i20@0:o^@I@")
# set to return int, take a const 6-char array arg
# i.e. in python: return object and accept 6-char list
# this seems to work even though the selector doesn't take a char aray,
# it takes a struct 'BluetoothDeviceAddress' which contains a char array.
objc.setSignatureForSelector("IOBluetoothDevice",
"withAddress:", '@12@0:r^[6C]')
del objc
pybluez-0.23/macos/_IOBluetoothUI.py 0000664 0000000 0000000 00000003755 13601523637 0017416 0 ustar 00root root 0000000 0000000 # Copyright (c) 2009 Bea Lam. All rights reserved.
#
# This file is part of LightBlue.
#
# LightBlue is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# LightBlue is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with LightBlue. If not, see .
"""
Provides a python interface to the Mac OSX IOBluetoothUI Framework classes,
through PyObjC.
For example:
>>> from lightblue import _IOBluetoothUI
>>> selector = _IOBluetoothUI.IOBluetoothDeviceSelectorController.deviceSelector()
>>> selector.runModal() # ask user to select a device
-1000
>>> for device in selector.getResults():
... print device.getName() # show name of selected device
...
Nokia 6600
>>>
See http://developer.apple.com/documentation/DeviceDrivers/Reference/IOBluetoothUI/index.html
for Apple's IOBluetoothUI documentation.
See http://pyobjc.sourceforge.net for details on how to access Objective-C
classes through PyObjC.
"""
import objc
try:
# mac os 10.5 loads frameworks using bridgesupport metadata
__bundle__ = objc.initFrameworkWrapper("IOBluetoothUI",
frameworkIdentifier="com.apple.IOBluetoothUI",
frameworkPath=objc.pathForFramework(
"/System/Library/Frameworks/IOBluetoothUI.framework"),
globals=globals())
except (AttributeError, ValueError):
# earlier versions use loadBundle() and setSignatureForSelector()
objc.loadBundle("IOBluetoothUI", globals(),
bundle_path=objc.pathForFramework('/System/Library/Frameworks/IOBluetoothUI.framework'))
del objc
pybluez-0.23/macos/_LightAquaBlue.py 0000775 0000000 0000000 00000002603 13601523637 0017444 0 ustar 00root root 0000000 0000000 # Copyright (c) 2009 Bea Lam. All rights reserved.
#
# This file is part of LightBlue.
#
# LightBlue is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# LightBlue is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with LightBlue. If not, see .
"""
Provides a python interface to the LightAquaBlue Framework classes, through
PyObjC.
See http://pyobjc.sourceforge.net for details on how to access Objective-C
classes through PyObjC.
"""
import objc
import os.path
from pkg_resources import resource_filename
_FRAMEWORK_PATH = resource_filename('lightblue', 'LightAquaBlue.framework')
if not os.path.isdir(_FRAMEWORK_PATH):
raise ImportError("Cannot load LightAquaBlue framework, not found at " + \
_FRAMEWORK_PATH)
__bundle__ = objc.initFrameworkWrapper("LightAquaBlue",
frameworkIdentifier="com.blammit.LightAquaBlue",
frameworkPath=objc.pathForFramework(_FRAMEWORK_PATH),
globals=globals())
del objc
pybluez-0.23/macos/__init__.py 0000775 0000000 0000000 00000014150 13601523637 0016355 0 ustar 00root root 0000000 0000000 # Copyright (c) 2009 Bea Lam. All rights reserved.
#
# This file is part of LightBlue.
#
# LightBlue is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# LightBlue is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with LightBlue. If not, see .
"LightBlue - a simple bluetooth library."
# Docstrings for attributes in this module.
_docstrings = {
"finddevices":
"""
Performs a device discovery and returns the found devices as a list of
(address, name, class-of-device) tuples. Raises BluetoothError if an error
occurs.
Arguments:
- getnames=True: True if device names should be retrieved during
discovery. If false, None will be returned instead of the device
name.
- length=10: the number of seconds to spend discovering devices
(this argument has no effect on Python for Series 60)
Do not invoke a new discovery before a previous discovery has finished.
Also, to minimise interference with other wireless and bluetooth traffic,
and to conserve battery power on the local device, discoveries should not
be invoked too frequently (an interval of at least 20 seconds is
recommended).
""",
"findservices":
"""
Performs a service discovery and returns the found services as a list of
(device-address, service-port, service-name) tuples. Raises BluetoothError
if an error occurs.
Arguments:
- addr=None: a device address, to search only for services on a
specific device
- name=None: a service name string, to search only for a service with a
specific name
- servicetype=None: can be RFCOMM or OBEX to search only for RFCOMM or
OBEX-type services. (OBEX services are not returned from an RFCOMM
search)
If more than one criteria is specified, this returns services that match
all criteria.
Currently the Python for Series 60 implementation will only find RFCOMM and
OBEX services.
""",
"finddevicename":
"""
Returns the name of the device with the given bluetooth address.
finddevicename(gethostaddr()) returns the local device name.
Arguments:
- address: the address of the device to look up
- usecache=True: if True, the device name will be fetched from a local
cache if possible. If False, or if the device name is not in the
cache, the remote device will be contacted to request its name.
Raise BluetoothError if the name cannot be retrieved.
""",
"gethostaddr":
"""
Returns the address of the local bluetooth device.
Raise BluetoothError if the local device is not available.
""",
"gethostclass":
"""
Returns the class of device of the local bluetooth device.
These values indicate the device's major services and the type of the
device (e.g. mobile phone, laptop, etc.). If you google for
"assigned numbers bluetooth baseband" you might find some documents
that discuss how to extract this information from the class of device.
Raise BluetoothError if the local device is not available.
""",
"socket":
"""
socket(proto=RFCOMM) -> socket object
Returns a new socket object.
Arguments:
- proto=RFCOMM: the type of socket to be created - either L2CAP or
RFCOMM.
Note that L2CAP sockets are not available on Python For Series 60, and
only L2CAP client sockets are supported on Mac OS X and Linux (i.e. you can
connect() the socket but not bind(), accept(), etc.).
""",
"advertise":
"""
Starts advertising a service with the given name, using the given server
socket. Raises BluetoothError if the service cannot be advertised.
Arguments:
- name: name of the service to be advertised
- sock: the socket object that will serve this service. The socket must
be already bound to a channel. If a RFCOMM service is being
advertised, the socket should also be listening.
- servicetype: the type of service to advertise - either RFCOMM or
OBEX. (L2CAP services are not currently supported.)
(If the servicetype is RFCOMM, the service will be advertised with the
Serial Port Profile; if the servicetype is OBEX, the service will be
advertised with the OBEX Object Push Profile.)
""",
"stopadvertise":
"""
Stops advertising the service on the given socket. Raises BluetoothError if
no service is advertised on the socket.
This will error if the given socket is already closed.
""",
"selectdevice":
"""
Displays a GUI which allows the end user to select a device from a list of
discovered devices.
Returns the selected device as an (address, name, class-of-device) tuple.
Returns None if the selection was cancelled.
(On Python For Series 60, the device selection will fail if there are any
open bluetooth connections.)
""",
"selectservice":
"""
Displays a GUI which allows the end user to select a service from a list of
discovered devices and their services.
Returns the selected service as a (device-address, service-port, service-
name) tuple. Returns None if the selection was cancelled.
(On Python For Series 60, the device selection will fail if there are any
open bluetooth connections.)
Currently the Python for Series 60 implementation will only find RFCOMM and
OBEX services.
"""
}
# import implementation modules
from ._lightblue import *
from ._lightbluecommon import *
from . import obex # plus submodule
# set docstrings
from . import _lightblue
localattrs = locals()
for attr in _lightblue.__all__:
try:
localattrs[attr].__doc__ = _docstrings[attr]
except KeyError:
pass
del attr, localattrs
pybluez-0.23/macos/_bluetoothsockets.py 0000664 0000000 0000000 00000103407 13601523637 0020357 0 ustar 00root root 0000000 0000000 # Copyright (c) 2009 Bea Lam. All rights reserved.
#
# This file is part of LightBlue.
#
# LightBlue is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# LightBlue is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with LightBlue. If not, see .
# Mac OS X bluetooth sockets implementation.
#
# To-do:
# - allow socket options
#
# if doing security AUTH, should set bool arg when calling
# openConnection_withPageTimeout_authenticationRequired_() in connect()
import time
import socket as _socket
import threading
import os
import errno
import types
import objc
import Foundation
from . import _IOBluetooth
from . import _lightbluecommon
from . import _macutil
from ._LightAquaBlue import BBServiceAdvertiser, BBBluetoothChannelDelegate
#import sets # python 2.3
try:
SHUT_RD, SHUT_WR, SHUT_RDWR = \
_socket.SHUT_RD, _socket.SHUT_WR, _socket.SHUT_RDWR
except AttributeError:
# python 2.3
SHUT_RD, SHUT_WR, SHUT_RDWR = (0, 1, 2)
def _getavailableport(proto):
# Just advertise a service and see what channel it was assigned, then
# stop advertising the service and return the channel.
# It's a hacky way of doing it, but IOBluetooth doesn't seem to provide
# functionality for just getting an available channel.
if proto == _lightbluecommon.RFCOMM:
try:
result, channelID, servicerecordhandle = BBServiceAdvertiser.addRFCOMMServiceDictionary_withName_UUID_channelID_serviceRecordHandle_(BBServiceAdvertiser.serialPortProfileDictionary(), "DummyService", None, None, None)
except:
result, channelID, servicerecordhandle = BBServiceAdvertiser.addRFCOMMServiceDictionary_withName_UUID_channelID_serviceRecordHandle_(BBServiceAdvertiser.serialPortProfileDictionary(), "DummyService", None)
if result != _macutil.kIOReturnSuccess:
raise _lightbluecommon.BluetoothError(result, \
"Could not retrieve an available service channel")
result = BBServiceAdvertiser.removeService_(servicerecordhandle)
if result != _macutil.kIOReturnSuccess:
raise _lightbluecommon.BluetoothError(result, \
"Could not retrieve an available service channel")
return channelID
else:
raise NotImplementedError("L2CAP server sockets not currently supported")
def _checkaddrpair(address, checkbtaddr=True):
# will want checkbtaddr=False if the address might be empty string
# (for binding to a server address)
if not isinstance(address, tuple):
raise TypeError("address must be (address, port) tuple, was %s" % \
type(address))
if len(address) != 2:
raise TypeError("address tuple must have 2 items (has %d)" % \
len(address))
if not isinstance(address[0], str):
raise TypeError("address host value must be string, was %s" % \
type(address[0]))
if checkbtaddr:
if not _lightbluecommon._isbtaddr(address[0]):
raise TypeError("address '%s' is not a bluetooth address" % \
address[0])
if not isinstance(address[1], int):
raise TypeError("address port value must be int, was %s" % \
type(address[1]))
# from std lib socket module
class _closedsocket(object):
__slots__ = []
def _dummy(*args):
raise _socket.error(errno.EBADF, 'Bad file descriptor')
send = recv = sendto = recvfrom = __getattr__ = _dummy
# TODO: replace with BytesIO if minimum supported version is python3?
# or just get rid of wrapper class altogether & use bytearray directly if
# multi-threaded usage isn't support (it's not currently).
class _ByteQueue(object):
def __init__(self):
self.buffered = bytearray()
self.lock = threading.Lock()
def empty(self):
return len(self.buffered) == 0
def write(self, data):
with self.lock:
self.buffered.extend(data)
def __len__(self):
#calculate length without needing to _build_str
return len(self.buffered)
def read(self, count):
with self.lock:
#get data requested by caller
result = self.buffered[:count]
#remove requested data from buffer
del self.buffered[:count]
return result
#class _SocketWrapper(_socket._socketobject):
class _SocketWrapper(object):
"""
A Bluetooth socket object has the same interface as a socket object from
the Python standard library module. It also uses the same
exceptions, raising socket.error for general errors and socket.timeout for
timeout errors.
Note that L2CAP sockets are not available on Python For Series 60, and
only L2CAP client sockets are supported on Mac OS X and Linux.
A simple client socket example:
>>> from lightblue import *
>>> s = socket() # or socket(L2CAP) to create an L2CAP socket
>>> s.connect(("00:12:2c:45:8a:7b", 5))
>>> s.send("hello")
5
>>> s.close()
A simple server socket example:
>>> from lightblue import *
>>> s = socket()
>>> s.bind(("", 0))
>>> s.listen(1)
>>> advertise("My RFCOMM Service", s, RFCOMM)
>>> conn, addr = s.accept()
>>> print("Connected by", addr)
Connected by ('00:0D:93:19:C8:68', 5)
>>> conn.recv(1024)
"hello"
>>> conn.close()
>>> s.close()
"""
def __init__(self, sock):
self._sock = sock
def accept(self):
sock, addr = self._sock.accept()
return _SocketWrapper(sock), addr
accept.__doc__ = _lightbluecommon._socketdocs["accept"]
def dup(self):
return _SocketWrapper(self._sock)
dup.__doc__ = _lightbluecommon._socketdocs["dup"]
def close(self):
self._sock.close()
self._sock = _closedsocket()
self.send = self.recv = self.sendto = self.recvfrom = self._sock._dummy
try:
import lightblue
lightblue.stopadvertise(self)
except:
pass
close.__doc__ = _lightbluecommon._socketdocs["close"]
def makefile(self, mode='r', bufsize=-1):
# use std lib socket's _fileobject
return _socket._fileobject(self._sock, mode, bufsize)
makefile.__doc__ = _lightbluecommon._socketdocs["makefile"]
# delegate all other method calls to internal sock obj
def __getattr__(self, attr):
return getattr(self._sock, attr)
# internal _sock object for RFCOMM and L2CAP sockets
class _BluetoothSocket(object):
_boundports = { _lightbluecommon.L2CAP: set(),
_lightbluecommon.RFCOMM: set() }
# conn is the associated _RFCOMMConnection or _L2CAPConnection
def __init__(self, conn):
self.__conn = conn
if conn is not None and conn.channel is not None:
self.__remotedevice = conn.channel.getDevice()
else:
self.__remotedevice = None
# timeout=None cos sockets default to blocking mode
self.__timeout = None
#self.__isserverspawned = (conn.channel is not None)
self.__port = 0
self.__eventlistener = None
self.__closed = False
self.__maxqueuedconns = 0
self.__incomingdata = _ByteQueue()
self.__queuedchannels = []
self.__queuedchannels_lock = threading.RLock()
# whether send or recv has been shut down
# set initial value to be other than SHUT_WR/SHUT_RD/SHUT_RDWR
self.__commstate = -1
def accept(self):
if not self.__isbound():
raise _socket.error('Socket not bound')
if not self.__islistening():
raise _socket.error('Socket must be listening first')
def clientconnected():
return len(self.__queuedchannels) > 0
if not clientconnected():
self.__waituntil(clientconnected, "accept timed out")
self.__queuedchannels_lock.acquire()
try:
newchannel = self.__queuedchannels.pop(0)
finally:
self.__queuedchannels_lock.release()
# return (new-socket, addr) pair using the new channel
newconn = _SOCKET_CLASSES[self.__conn.proto](newchannel)
sock = _SocketWrapper(_BluetoothSocket(newconn))
sock.__startevents()
return (sock, sock.getpeername())
def bind(self, address):
_checkaddrpair(address, False)
if self.__isbound():
raise _socket.error('Socket is already bound')
elif self.__isconnected():
raise _socket.error("Socket is already connected, cannot be bound")
if self.__conn.proto == _lightbluecommon.L2CAP:
raise NotImplementedError("L2CAP server sockets not currently supported")
if address[1] != 0:
raise _socket.error("must bind to port 0, other ports not supported on Mac OS X")
address = (address[0], _getavailableport(self.__conn.proto))
# address must be either empty string or local device address
if address[0] != "":
try:
import lightblue
localaddr = lightblue.gethostaddr()
except:
localaddr = None
if localaddr is None or address[0] != localaddr:
raise _socket.error(
errno.EADDRNOTAVAIL, os.strerror(errno.EADDRNOTAVAIL))
# is this port already in use?
if address[1] in self._boundports[self.__conn.proto]:
raise _socket.error(errno.EADDRINUSE, os.strerror(errno.EADDRINUSE))
self._boundports[self.__conn.proto].add(address[1])
self.__port = address[1]
def close(self):
wasconnected = self.__isconnected() or self.__isbound()
self.__stopevents()
if self.__conn is not None:
if self.__isbound():
self._boundports[self.__conn.proto].discard(self.__port)
else:
if self.__conn.channel is not None:
self.__conn.channel.setDelegate_(None)
self.__conn.channel.closeChannel()
# disconnect the baseband connection.
# This will fail if other RFCOMM channels to the remote device are
# still open (which is what we want, cos we don't know if another
# process is talking to the device)
if self.__remotedevice is not None:
self.__remotedevice.closeConnection() # returns err code
# if you don't run the event loop a little here, it's likely you won't
# be able to reconnect to the same remote device later
if wasconnected:
_macutil.waitfor(0.5)
def connect(self, address):
if self.__isbound():
raise _socket.error("Can't connect, socket has been bound")
elif self.__isconnected():
raise _socket.error("Socket is already connected")
_checkaddrpair(address)
# open a connection to device
self.__remotedevice = _IOBluetooth.IOBluetoothDevice.withAddressString_(address[0])
if not self.__remotedevice.isConnected():
if self.__timeout is None:
result = self.__remotedevice.openConnection()
else:
result = self.__remotedevice.openConnection_withPageTimeout_authenticationRequired_(
None, self.__timeout*1000, False)
if result != _macutil.kIOReturnSuccess:
if result == _macutil.kBluetoothHCIErrorPageTimeout:
if self.__timeout == 0:
raise _socket.error(errno.EAGAIN,
"Resource temporarily unavailable")
else:
raise _socket.timeout("connect timed out")
else:
raise _socket.error(result,
"Cannot connect to %s, can't open connection." \
% str(address[0]))
# open RFCOMM or L2CAP channel
self.__eventlistener = self.__createlistener()
result = self.__conn.connect(self.__remotedevice, address[1],
self.__eventlistener) # pass listener as cocoa delegate
if result != _macutil.kIOReturnSuccess:
self.__remotedevice.closeConnection()
self.__stopevents()
self.__eventlistener = None
raise _socket.error(result,
"Cannot connect to %d on %s" % (address[1], address[0]))
return
# if you don't run the event loop a little here, it's likely you won't
# be able to reconnect to the same remote device later
_macutil.waitfor(0.5)
def connect_ex(self, address):
try:
self.connect(address)
except _socket.error as err:
if len(err.args) > 1:
return err.args[0]
else:
# there's no error code, just a message, so this error wasn't
# from a system call -- so re-raise the exception
raise _socket.error(err)
return 0
def getpeername(self):
self.__checkconnected()
addr = _macutil.formatdevaddr(self.__remotedevice.getAddressString())
return (addr, self._getport())
def getsockname(self):
if self.__isbound() or self.__isconnected():
import lightblue
return (lightblue.gethostaddr(), self._getport())
else:
return ("00:00:00:00:00:00", 0)
def listen(self, backlog):
if self.__islistening():
return
if not self.__isbound():
raise _socket.error('Socket not bound')
if not isinstance(backlog, int):
raise TypeError("backlog must be int, was %s" % type(backlog))
if backlog < 0:
raise ValueError("backlog cannot be negative, was %d" % backlog)
self.__maxqueuedconns = backlog
# start listening for client connections
self.__startevents()
def _isclosed(self):
# isOpen() check doesn't work for incoming (server-spawned) channels
if (self.__conn.proto == _lightbluecommon.RFCOMM and
self.__conn.channel is not None and
not self.__conn.channel.isIncoming()):
return not self.__conn.channel.isOpen()
return self.__closed
def recv(self, bufsize, flags=0):
if self.__commstate in (SHUT_RD, SHUT_RDWR):
return ""
self.__checkconnected()
if not isinstance(bufsize, int):
raise TypeError("buffer size must be int, was %s" % type(bufsize))
if bufsize < 0:
raise ValueError("negative buffersize in recv") # as for tcp
if bufsize == 0:
return ""
# need this to ensure the _isclosed() check is up-to-date
_macutil.looponce()
if self._isclosed():
if len(self.__incomingdata) == 0:
raise _socket.error(errno.ECONNRESET,
os.strerror(errno.ECONNRESET))
return self.__incomingdata.read(bufsize)
# if incoming data buffer is empty, wait until data is available or
# channel is closed
def gotdata():
return not self.__incomingdata.empty() or self._isclosed()
if not gotdata():
self.__waituntil(gotdata, "recv timed out")
# other side closed connection while waiting?
if self._isclosed() and len(self.__incomingdata) == 0:
raise _socket.error(errno.ECONNRESET, os.strerror(errno.ECONNRESET))
return self.__incomingdata.read(bufsize)
# recvfrom() is really for datagram sockets not stream sockets but it
# can be implemented anyway.
def recvfrom(self, bufsize, flags=0):
# stream sockets return None, instead of address
return (self.recv(bufsize, flags), None)
def sendall(self, data, flags=0):
sentbytescount = self.send(data, flags)
while sentbytescount < len(data):
sentbytescount += self.send(data[sentbytescount:], flags)
return None
def send(self, data, flags=0):
# On python 2 this should be OK for backwards compatability as "bytes"
# is an alias for "str".
if not isinstance(data, (bytes, bytearray)):
raise TypeError("data must be bytes, was %s" % type(data))
if self.__commstate in (SHUT_WR, SHUT_RDWR):
raise _socket.error(errno.EPIPE, os.strerror(errno.EPIPE))
self.__checkconnected()
# do setup for if sock is in non-blocking mode
if self.__timeout is not None:
if self.__timeout == 0:
# in non-blocking mode
# isTransmissionPaused() is not available for L2CAP sockets,
# what to do for that?
if self.__conn.proto == _lightbluecommon.RFCOMM and \
self.__conn.channel.isTransmissionPaused():
# sending data now will block
raise _socket.error(errno.EAGAIN,
"Resource temporarily unavailable")
elif self.__timeout > 0:
# non-blocking with timeout
starttime = time.time()
# loop until all data is sent
writebuf = data
bytesleft = len(data)
mtu = self.__conn.getwritemtu()
while bytesleft > 0:
if self.__timeout is not None and self.__timeout > 0:
if time.time() - starttime > self.__timeout:
raise _socket.timeout("send timed out")
# write the data to the channel (only the allowed amount)
# the method/selector is the same for L2CAP and RFCOMM channels
if bytesleft > mtu:
sendbytecount = mtu
else:
sendbytecount = bytesleft
#result = self.__conn.channel.writeSync_length_(
# writebuf[:sendbytecount], sendbytecount)
result = self.__conn.write(writebuf[:sendbytecount])
# normal tcp sockets don't seem to actually error on the first
# send() after a connection has broken; if you try a second time,
# then you get the (32, 'Broken pipe') socket.error
if result != _macutil.kIOReturnSuccess:
raise _socket.error(result, "Error sending data")
bytesleft -= sendbytecount
writebuf = writebuf[sendbytecount:] # remove the data just sent
return len(data) - bytesleft
# sendto args may be one of:
# - data, address
# - data, flags, address
#
# The standard behaviour seems to be to ignore the given address if already
# connected.
# sendto() is really for datagram sockets not stream sockets but it
# can be implemented anyway.
def sendto(self, data, *args):
if len(args) == 1:
address = args[0]
flags = 0
elif len(args) == 2:
flags, address = args
else:
raise TypeError("sendto takes at most 3 arguments (%d given)" % \
(len(args) + 1))
_checkaddrpair(address)
# must already be connected, cos this is stream socket
self.__checkconnected()
return self.send(data, flags)
def fileno(self):
raise NotImplementedError
def getsockopt(self, level, optname, buflen=0):
# see what options on Linux+s60
# possibly have socket security option.
raise _socket.error(
errno.ENOPROTOOPT, os.strerror(errno.ENOPROTOOPT))
def setsockopt(self, level, optname, value):
# see what options on Linux+s60
# possibly have socket security option.
raise _socket.error(
errno.ENOPROTOOPT, os.strerror(errno.ENOPROTOOPT))
def setblocking(self, flag):
if flag == 0:
self.__timeout = 0 # non-blocking
else:
self.__timeout = None # blocking
def gettimeout(self):
return self.__timeout
def settimeout(self, value):
if value is not None and not isinstance(value, (float, int)):
msg = "timeout value must be a number or None, was %s" % \
type(value)
raise TypeError(msg)
if value < 0:
msg = "timeout value cannot be negative, was %d" % value
raise ValueError(msg)
self.__timeout = value
def shutdown(self, how):
if how not in (SHUT_RD, SHUT_WR, SHUT_RDWR):
raise _socket.error(22, "Invalid argument")
self.__commstate = how
# This method is called from outside this file.
def _getport(self):
if self.__isconnected():
return self.__conn.getport()
if self.__isbound():
return self.__port
raise _lightbluecommon.BluetoothError("socket is neither connected nor bound")
# This method is called from outside this file.
def _getchannel(self):
if self.__conn is None:
return None
return self.__conn.channel
# Called by the event listener when data is available
# 'channel' is IOBluetoothRFCOMMChannel or IOBluetoothL2CAPChannel object
def _handle_channeldata(self, channel, data):
self.__incomingdata.write(data)
_macutil.interruptwait()
# Called by the event listener when a client connects to a server socket
def _handle_channelopened(self, channel):
# put new channels into a queue, which 'accept' can then pull out
self.__queuedchannels_lock.acquire()
try:
# need to implement max connections
#if len(self.__queuedchannels) < self.__maxqueuedconns:
self.__queuedchannels.append(channel)
_macutil.interruptwait()
finally:
self.__queuedchannels_lock.release()
# Called by the event listener when the channel is closed.
def _handle_channelclosed(self, channel):
# beware that this value won't actually be set until the event loop
# has been driven so that this method is actually called
self.__closed = True
_macutil.interruptwait()
def __waituntil(self, stopwaiting, timeoutmsg):
"""
Waits until stopwaiting() returns True, or until the wait times out
(according to the self.__timeout value).
This is to make a function wait until a buffer has been filled. i.e.
stopwaiting() should return True when the buffer is no longer empty.
"""
if not stopwaiting():
if self.__timeout == 0:
# in non-blocking mode (immediate timeout)
# push event loop to really be sure there is no data available
_macutil.looponce()
if not stopwaiting():
# trying to perform operation now would block
raise _socket.error(errno.EAGAIN, os.strerror(errno.EAGAIN))
else:
# block and wait until we get data, or time out
if not _macutil.waituntil(stopwaiting, self.__timeout):
raise _socket.timeout(timeoutmsg)
def __createlistener(self):
if self.__isbound():
return _ChannelServerEventListener.alloc().initWithDelegate_port_protocol_(self,
self._getport(), self.__conn.proto)
else:
listener = _ChannelEventListener.alloc().initWithDelegate_(self)
if self.__conn.channel is not None:
self.__conn.channel.setDelegate_(listener.delegate())
listener.registerclosenotif(self.__conn.channel)
return listener
# should not call this if connect() has been called to connect this socket
def __startevents(self):
if self.__eventlistener is not None:
raise _lightbluecommon.BluetoothError("socket already listening")
self.__eventlistener = self.__createlistener()
def __stopevents(self):
if self.__eventlistener is not None:
self.__eventlistener.close()
def __islistening(self):
return self.__eventlistener is not None
def __checkconnected(self):
if not self._sock.isconnected(): # i.e. is connected, non-server socket
# not connected, raise "socket not connected"
raise _socket.error(errno.ENOTCONN, os.strerror(errno.ENOTCONN))
# returns whether socket is a bound server socket
def __isbound(self):
return self.__port != 0
def __isconnected(self):
return self.__conn.channel is not None
def __checkconnected(self):
if not self.__isconnected():
# not connected, raise "socket not connected"
raise _socket.error(errno.ENOTCONN, os.strerror(errno.ENOTCONN))
# set method docstrings
definedmethods = locals() # i.e. defined methods in _SocketWrapper
for name, doc in list(_lightbluecommon._socketdocs.items()):
try:
definedmethods[name].__doc__ = doc
except KeyError:
pass
class _RFCOMMConnection(object):
proto = _lightbluecommon.RFCOMM
def __init__(self, channel=None):
# self.channel is accessed by _BluetoothSocket parent
self.channel = channel
def connect(self, device, port, listener):
# open RFCOMM channel (should timeout actually apply to opening of
# channel as well? if so need to do timeout with async callbacks)
try:
# pyobjc 2.0
result, self.channel = device.openRFCOMMChannelSync_withChannelID_delegate_(None, port, listener.delegate())
except TypeError:
result, self.channel = device.openRFCOMMChannelSync_withChannelID_delegate_(port, listener.delegate())
if result == _macutil.kIOReturnSuccess:
self.channel.setDelegate_(listener.delegate())
listener.registerclosenotif(self.channel)
else:
self.channel = None
return result
def write(self, data):
if self.channel is None:
raise _socket.error("socket not connected")
return \
BBBluetoothChannelDelegate.synchronouslyWriteData_toRFCOMMChannel_(
Foundation.NSData.alloc().initWithBytes_length_(data, len(data)),
self.channel)
def getwritemtu(self):
return self.channel.getMTU()
def getport(self):
return self.channel.getChannelID()
class _L2CAPConnection(object):
proto = _lightbluecommon.L2CAP
def __init__(self, channel=None):
# self.channel is accessed by _BluetoothSocket parent
self.channel = channel
def connect(self, device, port, listener):
try:
# pyobjc 2.0
result, self.channel = device.openL2CAPChannelSync_withPSM_delegate_(None, port, listener.delegate())
except TypeError:
result, self.channel = device.openL2CAPChannelSync_withPSM_delegate_(port, listener.delegate())
if result == _macutil.kIOReturnSuccess:
self.channel.setDelegate_(listener.delegate())
listener.registerclosenotif(self.channel)
else:
self.channel = None
return result
def write(self, data):
if self.channel is None:
raise _socket.error("socket not connected")
return \
BBBluetoothChannelDelegate.synchronouslyWriteData_toL2CAPChannel_(
bytes(data), self.channel)
def getwritemtu(self):
return self.channel.getOutgoingMTU()
def getport(self):
return self.channel.getPSM()
class _ChannelEventListener(Foundation.NSObject):
"""
Uses a BBBluetoothChannelDelegate to listen for events on an
IOBluetoothRFCOMMChannel or IOBluetoothL2CAPChannel, and makes callbacks to
a specified object when events occur.
"""
# note this is a NSObject "init", not a python object "__init__"
def initWithDelegate_(self, cb_obj):
"""
Arguments:
- cb_obj: An object that receives callbacks when events occur. This
object should have:
- a method '_handle_channeldata' which takes the related channel (a
IOBluetoothRFCOMMChannel or IOBluetoothL2CAPChannel) and the new
data (a string) as the arguments.
- a method '_handle_channelclosed' which takes the related channel
as the argument.
If this listener's delegate is passed to the openRFCOMMChannel... or
openL2CAPChannel... selectors as the delegate, the delegate (and
therefore this listener) will automatically start receiving events.
Otherwise, call setDelegate_() on the channel with this listener's
delegate as the argument to allow this listener to start receiving
channel events. (This is the only option for server-spawned sockets.)
"""
self = super(_ChannelEventListener, self).init()
if cb_obj is None:
raise TypeError("callback object is None")
self.__cb_obj = cb_obj
self.__closenotif = None
self.__channelDelegate = \
BBBluetoothChannelDelegate.alloc().initWithDelegate_(self)
return self
initWithDelegate_ = objc.selector(initWithDelegate_, signature=b"@@:@")
def delegate(self):
return self.__channelDelegate
@objc.python_method
def registerclosenotif(self, channel):
# oddly enough, sometimes the channelClosed: selector doesn't get called
# (maybe if there's a lot of data being passed?) but this seems to work
notif = channel.registerForChannelCloseNotification_selector_(self,
"channelClosedEvent:channel:")
if notif is not None:
self.__closenotif = notif
def close(self):
if self.__closenotif is not None:
self.__closenotif.unregister()
def channelClosedEvent_channel_(self, notif, channel):
if hasattr(self.__cb_obj, '_handle_channelclosed'):
self.__cb_obj._handle_channelclosed(channel)
channelClosedEvent_channel_ = objc.selector(
channelClosedEvent_channel_, signature=b"v@:@@")
# implement method from BBBluetoothChannelDelegateObserver protocol:
# - (void)channelData:(id)channel data:(NSData *)data;
def channelData_data_(self, channel, data):
if hasattr(self.__cb_obj, '_handle_channeldata'):
self.__cb_obj._handle_channeldata(channel, data[:])
channelData_data_ = objc.selector(channelData_data_, signature=b"v@:@@")
# implement method from BBBluetoothChannelDelegateObserver protocol:
# - (void)channelClosed:(id)channel;
def channelClosed_(self, channel):
if hasattr(self.__cb_obj, '_handle_channelclosed'):
self.__cb_obj._handle_channelclosed(channel)
channelClosed_ = objc.selector(channelClosed_, signature=b"v@:@")
class _ChannelServerEventListener(Foundation.NSObject):
"""
Listens for server-specific events on a RFCOMM or L2CAP channel (i.e. when a
client connects) and makes callbacks to a specified object when events
occur.
"""
# note this is a NSObject "init", not a python object "__init__"
def initWithDelegate_port_protocol_(self, cb_obj, port, proto):
"""
Arguments:
- cb_obj: to receive callbacks when a client connects to
to the channel, the callback object should have a method
'_handle_channelopened' which takes the newly opened
IOBluetoothRFCOMMChannel or IOBluetoothL2CAPChannel as its argument.
- port: the channel or PSM that the server is listening on
- proto: L2CAP or RFCOMM.
"""
self = super(_ChannelServerEventListener, self).init()
if cb_obj is None:
raise TypeError("callback object is None")
self.__cb_obj = cb_obj
self.__usernotif = None
if proto == _lightbluecommon.RFCOMM:
usernotif = _IOBluetooth.IOBluetoothRFCOMMChannel.registerForChannelOpenNotifications_selector_withChannelID_direction_(self, "newChannelOpened:channel:", port, _macutil.kIOBluetoothUserNotificationChannelDirectionIncoming)
elif proto == _lightbluecommon.L2CAP:
usernotif = _IOBluetooth.IOBluetoothL2CAPChannel.registerForChannelOpenNotifications_selector_withPSM_direction_(self, "newChannelOpened:channel:", port, _macutil.kIOBluetoothUserNotificationChannelDirectionIncoming)
if usernotif is None:
raise _socket.error("Unable to register for channel-" + \
"opened notifications on server socket on channel/PSM %d" % \
port)
self.__usernotif = usernotif
return self
initWithDelegate_port_protocol_ = objc.selector(
initWithDelegate_port_protocol_, signature=b"@@:@ii")
def close(self):
if self.__usernotif is not None:
self.__usernotif.unregister()
def newChannelOpened_channel_(self, notif, newChannel):
"""
Handle when a client connects to the server channel.
(This method is called for both RFCOMM and L2CAP channels.)
"""
if newChannel is not None and newChannel.isIncoming():
# not sure if delegate really needs to be set
newChannel.setDelegate_(self)
if hasattr(self.__cb_obj, '_handle_channelopened'):
self.__cb_obj._handle_channelopened(newChannel)
# makes this method receive notif and channel as objects
newChannelOpened_channel_ = objc.selector(
newChannelOpened_channel_, signature=b"v@:@@")
# -----------------------------------------------------------
# protocol-specific classes
_SOCKET_CLASSES = { _lightbluecommon.RFCOMM: _RFCOMMConnection,
_lightbluecommon.L2CAP: _L2CAPConnection }
def _getsocketobject(proto):
if proto not in list(_SOCKET_CLASSES.keys()):
raise ValueError("Unknown socket protocol, must be L2CAP or RFCOMM")
return _SocketWrapper(_BluetoothSocket(_SOCKET_CLASSES[proto]()))
pybluez-0.23/macos/_lightblue.py 0000775 0000000 0000000 00000045427 13601523637 0016747 0 ustar 00root root 0000000 0000000 # Copyright (c) 2009 Bea Lam. All rights reserved.
#
# This file is part of LightBlue.
#
# LightBlue is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# LightBlue is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with LightBlue. If not, see .
# Mac OS X main module implementation.
import types
import warnings
import Foundation
import AppKit
import objc
from objc import super
from . import _IOBluetooth
from . import _LightAquaBlue
from . import _lightbluecommon
from . import _macutil
from . import _bluetoothsockets
# public attributes
__all__ = ("finddevices", "findservices", "finddevicename",
"selectdevice", "selectservice",
"gethostaddr", "gethostclass",
"socket",
"advertise", "stopadvertise")
# details of advertised services
__advertised = {}
def finddevices(getnames=True, length=10):
inquiry = _SyncDeviceInquiry()
inquiry.run(getnames, length)
devices = inquiry.getfounddevices()
return devices
def findservices(addr=None, name=None, servicetype=None):
if servicetype not in (_lightbluecommon.RFCOMM, _lightbluecommon.OBEX, None):
raise ValueError("servicetype must be RFCOMM, OBEX or None, was %s" % \
servicetype)
if addr is None:
try:
founddevices = finddevices()
except _lightbluecommon.BluetoothError as e:
msg = "findservices() failed, " +\
"error while finding devices: " + str(e)
raise _lightbluecommon.BluetoothError(msg)
#print founddevices
addresses = [dev[0] for dev in founddevices]
else:
addresses = [addr]
services = []
for devaddr in addresses:
iobtdevice = _IOBluetooth.IOBluetoothDevice.withAddressString_(devaddr)
if not iobtdevice and addr is not None:
msg = "findservices() failed, " +\
"failed to find " + devaddr
raise _lightbluecommon.BluetoothError(msg)
elif not iobtdevice:
continue
try:
lastseen = iobtdevice.getLastServicesUpdate()
if lastseen is None or lastseen.timeIntervalSinceNow() < -2:
# perform SDP query to update known services.
# wait at least a few seconds between service discovery cos
# sometimes it doesn't work if doing updates too often.
# In future should have option to not do updates.
serviceupdater = _SDPQueryRunner.alloc().init()
try:
serviceupdater.query(iobtdevice) # blocks until updated
except _lightbluecommon.BluetoothError as e:
msg = "findservices() couldn't get services for %s: %s" % \
(iobtdevice.getNameOrAddress(), str(e))
warnings.warn(msg)
# or should I use cached services instead of warning?
# but sometimes the cached ones are totally wrong.
# if searching for RFCOMM, exclude OBEX services
if servicetype == _lightbluecommon.RFCOMM:
uuidbad = _macutil.PROTO_UUIDS.get(_lightbluecommon.OBEX)
else:
uuidbad = None
filtered = _searchservices(iobtdevice, name=name,
uuid=_macutil.PROTO_UUIDS.get(servicetype),
uuidbad=uuidbad)
#print "unfiltered:", iobtdevice.getServices()
services.extend([_getservicetuple(s) for s in filtered])
finally:
# close baseband connection (not sure if this is necessary, but
# sometimes the transport connection seems to stay open?)
iobtdevice.closeConnection()
return services
def finddevicename(address, usecache=True):
if not _lightbluecommon._isbtaddr(address):
raise TypeError("%s is not a valid bluetooth address" % str(address))
if address == gethostaddr():
return _gethostname()
device = _IOBluetooth.IOBluetoothDevice.withAddressString_(address)
if usecache:
name = device.getName()
if name is not None:
return name
# do name request with timeout of 10 seconds
result = device.remoteNameRequest_withPageTimeout_(None, 10000)
if result == _macutil.kIOReturnSuccess:
return device.getName()
raise _lightbluecommon.BluetoothError(
"Could not find device name for %s" % address)
### local device ###
def gethostaddr():
addr = _LightAquaBlue.BBLocalDevice.getAddressString()
if addr is not None:
# PyObjC returns all strings as unicode, but the address doesn't need
# to be unicode cos it's just hex values
return _macutil.formatdevaddr(addr)
raise _lightbluecommon.BluetoothError("Cannot read local device address")
def gethostclass():
cod = _LightAquaBlue.BBLocalDevice.getClassOfDevice()
if cod != -1:
return int(cod)
raise _lightbluecommon.BluetoothError("Cannot read local device class")
def _gethostname():
name = _LightAquaBlue.BBLocalDevice.getName()
if name is not None:
return name
raise _lightbluecommon.BluetoothError("Cannot read local device name")
### socket ###
def socket(proto=_lightbluecommon.RFCOMM):
return _bluetoothsockets._getsocketobject(proto)
### advertising services ###
def advertise(name, sock, servicetype, uuid=None):
if not isinstance(name, str):
raise TypeError("name must be string, was %s" % type(name))
# raises exception if socket is not bound
boundchannelID = sock._getport()
# advertise the service
if servicetype == _lightbluecommon.RFCOMM or servicetype == _lightbluecommon.OBEX:
try:
result, finalchannelID, servicerecordhandle = _LightAquaBlue.BBServiceAdvertiser\
.addRFCOMMServiceDictionary_withName_UUID_channelID_serviceRecordHandle_(
_LightAquaBlue.BBServiceAdvertiser.serialPortProfileDictionary(),
name, uuid, None, None)
except:
result, finalchannelID, servicerecordhandle = _LightAquaBlue.BBServiceAdvertiser\
.addRFCOMMServiceDictionary_withName_UUID_channelID_serviceRecordHandle_(
_LightAquaBlue.BBServiceAdvertiser.serialPortProfileDictionary(),
name, uuid)
else:
raise ValueError("servicetype must be either RFCOMM or OBEX")
if result != _macutil.kIOReturnSuccess:
raise _lightbluecommon.BluetoothError(
result, "Error advertising service")
if boundchannelID and boundchannelID != finalchannelID:
msg = "socket bound to unavailable channel (%d), " % boundchannelID +\
"use channel value of 0 to bind to dynamically assigned channel"
raise _lightbluecommon.BluetoothError(msg)
# note service record handle, so that the service can be stopped later
__advertised[id(sock)] = servicerecordhandle
def stopadvertise(sock):
if sock is None:
raise TypeError("Given socket is None")
servicerecordhandle = __advertised.get(id(sock))
if servicerecordhandle is None:
raise _lightbluecommon.BluetoothError("no service advertised")
result = _LightAquaBlue.BBServiceAdvertiser.removeService_(servicerecordhandle)
if result != _macutil.kIOReturnSuccess:
raise _lightbluecommon.BluetoothError(
result, "Error stopping advertising of service")
### GUI ###
def selectdevice():
from . import _IOBluetoothUI
gui = _IOBluetoothUI.IOBluetoothDeviceSelectorController.deviceSelector()
# try to bring GUI to foreground by setting it as floating panel
# (if this is called from pyobjc app, it would automatically be in foreground)
try:
gui.window().setFloatingPanel_(True)
except:
pass
# show the window and wait for user's selection
response = gui.runModal() # problems here if transferring a lot of data??
if response == AppKit.NSRunStoppedResponse:
results = gui.getResults()
if len(results) > 0: # should always be > 0, but check anyway
devinfo = _getdevicetuple(results[0])
# sometimes the baseband connection stays open which causes
# problems with connections w so close it here, see if this fixes
# it
dev = _IOBluetooth.IOBluetoothDevice.withAddressString_(devinfo[0])
if dev.isConnected():
dev.closeConnection()
return devinfo
# user cancelled selection
return None
def selectservice():
from . import _IOBluetoothUI
gui = _IOBluetoothUI.IOBluetoothServiceBrowserController.serviceBrowserController_(
_macutil.kIOBluetoothServiceBrowserControllerOptionsNone)
# try to bring GUI to foreground by setting it as floating panel
# (if this is called from pyobjc app, it would automatically be in foreground)
try:
gui.window().setFloatingPanel_(True)
except:
pass
# show the window and wait for user's selection
response = gui.runModal()
if response == AppKit.NSRunStoppedResponse:
results = gui.getResults()
if len(results) > 0: # should always be > 0, but check anyway
serviceinfo = _getservicetuple(results[0])
# sometimes the baseband connection stays open which causes
# problems with connections ... so close it here, see if this fixes
# it
dev = _IOBluetooth.IOBluetoothDevice.deviceWithAddressString_(serviceinfo[0])
if dev.isConnected():
dev.closeConnection()
return serviceinfo
# user cancelled selection
return None
### classes ###
class _SDPQueryRunner(Foundation.NSObject):
"""
Convenience class for performing a synchronous or asynchronous SDP query
on an IOBluetoothDevice.
"""
@objc.python_method
def query(self, device, timeout=10.0):
# do SDP query
err = device.performSDPQuery_(self)
if err != _macutil.kIOReturnSuccess:
raise _lightbluecommon.BluetoothError(err, self._errmsg(device))
# performSDPQuery_ is async, so block-wait
self._queryresult = None
if not _macutil.waituntil(lambda: self._queryresult is not None,
timeout):
raise _lightbluecommon.BluetoothError(
"Timed out getting services for %s" % \
device.getNameOrAddress())
# query is now complete
if self._queryresult != _macutil.kIOReturnSuccess:
raise _lightbluecommon.BluetoothError(
self._queryresult, self._errmsg(device))
def sdpQueryComplete_status_(self, device, status):
# can't raise exception during a callback, so just keep the err value
self._queryresult = status
_macutil.interruptwait()
sdpQueryComplete_status_ = objc.selector(
sdpQueryComplete_status_, signature=b"v@:@i") # accept object, int
@objc.python_method
def _errmsg(self, device):
return "Error getting services for %s" % device.getNameOrAddress()
class _SyncDeviceInquiry(object):
def __init__(self):
super(_SyncDeviceInquiry, self).__init__()
self._inquiry = _AsyncDeviceInquiry.alloc().init()
self._inquiry.cb_completed = self._inquirycomplete
self._inquiring = False
def run(self, getnames, duration):
if self._inquiring:
raise _lightbluecommon.BluetoothError(
"Another inquiry in progress")
# set inquiry attributes
self._inquiry.updatenames = getnames
self._inquiry.length = duration
# start the inquiry
err = self._inquiry.start()
if err != _macutil.kIOReturnSuccess:
raise _lightbluecommon.BluetoothError(
err, "Error starting device inquiry")
# if error occurs during inquiry, set _inquiryerr to the error code
self._inquiryerr = _macutil.kIOReturnSuccess
# wait until the inquiry is complete
self._inquiring = True
_macutil.waituntil(lambda: not self._inquiring)
# if error occured during inquiry, raise exception
if self._inquiryerr != _macutil.kIOReturnSuccess:
raise _lightbluecommon.BluetoothError(self._inquiryerr,
"Error during device inquiry")
def getfounddevices(self):
# return as list of device-info tuples
return [_getdevicetuple(device) for device in \
self._inquiry.getfounddevices()]
def _inquirycomplete(self, err, aborted):
if err != 188: # no devices found
self._inquiryerr = err
self._inquiring = False
_macutil.interruptwait()
def __del__(self):
self._inquiry.__del__()
super(_SyncDeviceInquiry, self).__del__()
# Wrapper around IOBluetoothDeviceInquiry, with python callbacks that you can
# set to receive callbacks when the inquiry is started or stopped, or when it
# finds a device.
#
# This discovery doesn't block, so it could be used in a PyObjC application
# that is running an event loop.
#
# Properties:
# - 'length': the inquiry length (seconds)
# - 'updatenames': whether to update device names during the inquiry
# (i.e. perform remote name requests, which will take a little longer)
#
class _AsyncDeviceInquiry(Foundation.NSObject):
# NSObject init, not python __init__
def init(self):
try:
attr = _IOBluetooth.IOBluetoothDeviceInquiry
except AttributeError:
raise ImportError("Cannot find IOBluetoothDeviceInquiry class " +\
"to perform device discovery. This class was introduced in " +\
"Mac OS X 10.4, are you running an earlier version?")
self = super(_AsyncDeviceInquiry, self).init()
self._inquiry = \
_IOBluetooth.IOBluetoothDeviceInquiry.inquiryWithDelegate_(self)
# callbacks
self.cb_started = None
self.cb_completed = None
self.cb_founddevice = None
return self
# length property
@objc.python_method
def _setlength(self, length):
self._inquiry.setInquiryLength_(length)
length = property(
lambda self: self._inquiry.inquiryLength(),
_setlength)
# updatenames property
@objc.python_method
def _setupdatenames(self, update):
self._inquiry.setUpdateNewDeviceNames_(update)
updatenames = property(
lambda self: self._inquiry.updateNewDeviceNames(),
_setupdatenames)
# returns error code
def start(self):
return self._inquiry.start()
# returns error code
def stop(self):
return self._inquiry.stop()
# returns list of IOBluetoothDevice objects
def getfounddevices(self):
return self._inquiry.foundDevices()
def __del__(self):
super(_AsyncDeviceInquiry, self).dealloc()
#
# delegate methods follow (these are called by the internal
# IOBluetoothDeviceInquiry object when inquiry events occur)
#
# - (void)deviceInquiryDeviceFound:(IOBluetoothDeviceInquiry*)sender
# device:(IOBluetoothDevice*)device;
def deviceInquiryDeviceFound_device_(self, inquiry, device):
if self.cb_founddevice:
self.cb_founddevice(device)
deviceInquiryDeviceFound_device_ = objc.selector(
deviceInquiryDeviceFound_device_, signature=b"v@:@@")
# - (void)deviceInquiryComplete:error:aborted;
def deviceInquiryComplete_error_aborted_(self, inquiry, err, aborted):
if self.cb_completed:
self.cb_completed(err, aborted)
deviceInquiryComplete_error_aborted_ = objc.selector(
deviceInquiryComplete_error_aborted_, signature=b"v@:@iZ")
# - (void)deviceInquiryStarted:(IOBluetoothDeviceInquiry*)sender;
def deviceInquiryStarted_(self, inquiry):
if self.cb_started:
self.cb_started()
# - (void)deviceInquiryDeviceNameUpdated:device:devicesRemaining:
def deviceInquiryDeviceNameUpdated_device_devicesRemaining_(self, sender,
device,
devicesRemaining):
pass
# - (void)deviceInquiryUpdatingDeviceNamesStarted:devicesRemaining:
def deviceInquiryUpdatingDeviceNamesStarted_devicesRemaining_(self, sender,
devicesRemaining):
pass
### utility methods ###
def _searchservices(device, name=None, uuid=None, uuidbad=None):
"""
Searches the given IOBluetoothDevice using the specified parameters.
Returns an empty list if the device has no services.
uuid should be IOBluetoothSDPUUID object.
"""
if not isinstance(device, _IOBluetooth.IOBluetoothDevice):
raise ValueError("device must be IOBluetoothDevice, was %s" % \
type(device))
services = []
allservices = device.getServices()
if uuid:
gooduuids = (uuid, )
else:
gooduuids = ()
if uuidbad:
baduuids = (uuidbad, )
else:
baduuids = ()
if allservices is not None:
for s in allservices:
if gooduuids and not s.hasServiceFromArray_(gooduuids):
continue
if baduuids and s.hasServiceFromArray_(baduuids):
continue
if name is None or s.getServiceName() == name:
services.append(s)
return services
def _getdevicetuple(iobtdevice):
"""
Returns an (addr, name, COD) device tuple from a IOBluetoothDevice object.
"""
addr = _macutil.formatdevaddr(iobtdevice.getAddressString())
name = iobtdevice.getName()
cod = iobtdevice.getClassOfDevice()
return (addr, name, cod)
def _getservicetuple(servicerecord):
"""
Returns a (device-addr, service-channel, service-name) tuple from the given
IOBluetoothSDPServiceRecord.
"""
addr = _macutil.formatdevaddr(servicerecord.getDevice().getAddressString())
name = servicerecord.getServiceName()
try:
result, channel = servicerecord.getRFCOMMChannelID_(None) # pyobjc 2.0
except TypeError:
result, channel = servicerecord.getRFCOMMChannelID_()
if result != _macutil.kIOReturnSuccess:
try:
result, channel = servicerecord.getL2CAPPSM_(None) # pyobjc 2.0
except:
result, channel = servicerecord.getL2CAPPSM_()
if result != _macutil.kIOReturnSuccess:
channel = None
return (addr, channel, name)
pybluez-0.23/macos/_lightbluecommon.py 0000775 0000000 0000000 00000024453 13601523637 0020154 0 ustar 00root root 0000000 0000000 # Copyright (c) 2009 Bea Lam. All rights reserved.
#
# This file is part of LightBlue.
#
# LightBlue is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# LightBlue is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with LightBlue. If not, see .
# Defines attributes with common implementations across the different
# platforms.
# public attributes
__all__ = ("L2CAP", "RFCOMM", "OBEX", "BluetoothError", "splitclass")
# Protocol/service class types, used for sockets and advertising services
L2CAP, RFCOMM, OBEX = (10, 11, 12)
class BluetoothError(IOError):
"""
Generic exception raised for Bluetooth errors. This is not raised for
socket-related errors; socket objects raise the socket.error and
socket.timeout exceptions from the standard library socket module.
Note that error codes are currently platform-independent. In particular,
the Mac OS X implementation returns IOReturn error values from the IOKit
framework, and OBEXError codes from for OBEX operations.
"""
pass
def splitclass(classofdevice):
"""
Splits the given class of device to return a 3-item tuple with the
major service class, major device class and minor device class values.
These values indicate the device's major services and the type of the
device (e.g. mobile phone, laptop, etc.). If you google for
"assigned numbers bluetooth baseband" you might find some documents
that discuss how to extract this information from the class of device.
Example:
>>> splitclass(1057036)
(129, 1, 3)
>>>
"""
if not isinstance(classofdevice, int):
try:
classofdevice = int(classofdevice)
except (TypeError, ValueError):
raise TypeError("Given device class '%s' cannot be split" % \
str(classofdevice))
data = classofdevice >> 2 # skip over the 2 "format" bits
service = data >> 11
major = (data >> 6) & 0x1F
minor = data & 0x3F
return (service, major, minor)
_validbtaddr = None
def _isbtaddr(address):
"""
Returns whether the given address is a valid bluetooth address.
For example, "00:0e:6d:7b:a2:0a" is a valid address.
Returns False if the argument is None or is not a string.
"""
# Define validity regex. Accept either ":" or "-" as separators.
global _validbtaddr
if _validbtaddr is None:
import re
_validbtaddr = re.compile("((\d|[a-f]){2}(:|-)){5}(\d|[a-f]){2}",
re.IGNORECASE)
import types
if not isinstance(address, str):
return False
return _validbtaddr.match(address) is not None
# --------- other attributes ---------
def _joinclass(codtuple):
"""
The opposite of splitclass(). Joins a (service, major, minor) class-of-
device tuple into a whole class of device value.
"""
if not isinstance(codtuple, tuple):
raise TypeError("argument must be tuple, was %s" % type(codtuple))
if len(codtuple) != 3:
raise ValueError("tuple must have 3 items, has %d" % len(codtuple))
serviceclass = codtuple[0] << 2 << 11
majorclass = codtuple[1] << 2 << 6
minorclass = codtuple[2] << 2
return (serviceclass | majorclass | minorclass)
# Docstrings for socket objects.
# Based on std lib socket docs.
_socketdocs = {
"accept":
"""
accept() -> (socket object, address info)
Wait for an incoming connection. Return a new socket representing the
connection, and the address of the client. For RFCOMM sockets, the address
info is a pair (hostaddr, channel).
The socket must be bound and listening before calling this method.
""",
"bind":
"""
bind(address)
Bind the socket to a local address. For RFCOMM sockets, the address is a
pair (host, channel); the host must refer to the local host.
A port value of 0 binds the socket to a dynamically assigned port.
(Note that on Mac OS X, the port value must always be 0.)
The socket must not already be bound.
""",
"close":
"""
close()
Close the socket. It cannot be used after this call.
""",
"connect":
"""
connect(address)
Connect the socket to a remote address. The address should be a
(host, channel) pair for RFCOMM sockets, and a (host, PSM) pair for L2CAP
sockets.
The socket must not be already connected.
""",
"connect_ex":
"""
connect_ex(address) -> errno
This is like connect(address), but returns an error code instead of raising
an exception when an error occurs.
""",
"dup":
"""
dup() -> socket object
Returns a new socket object connected to the same system resource.
""",
"fileno":
"""
fileno() -> integer
Return the integer file descriptor of the socket.
Raises NotImplementedError on Mac OS X and Python For Series 60.
""",
"getpeername":
"""
getpeername() -> address info
Return the address of the remote endpoint. The address info is a
(host, channel) pair for RFCOMM sockets, and a (host, PSM) pair for L2CAP
sockets.
If the socket has not been connected, socket.error will be raised.
""",
"getsockname":
"""
getsockname() -> address info
Return the address of the local endpoint. The address info is a
(host, channel) pair for RFCOMM sockets, and a (host, PSM) pair for L2CAP
sockets.
If the socket has not been connected nor bound, this returns the tuple
("00:00:00:00:00:00", 0).
""",
"getsockopt":
"""
getsockopt(level, option[, bufsize]) -> value
Get a socket option. See the Unix manual for level and option.
If a nonzero buffersize argument is given, the return value is a
string of that length; otherwise it is an integer.
Currently support for socket options are platform independent -- i.e.
depends on the underlying Series 60 or BlueZ socket options support.
The Mac OS X implementation currently does not support any options at
all and automatically raises socket.error.
""",
"gettimeout":
"""
gettimeout() -> timeout
Returns the timeout in floating seconds associated with socket
operations. A timeout of None indicates that timeouts on socket
operations are disabled.
Currently not supported on Python For Series 60 implementation, which
will always return None.
""",
"listen":
"""
listen(backlog)
Enable a server to accept connections. The backlog argument must be at
least 1; it specifies the number of unaccepted connection that the system
will allow before refusing new connections.
The socket must not be already listening.
Currently not implemented on Mac OS X.
""",
"makefile":
"""
makefile([mode[, bufsize]]) -> file object
Returns a regular file object corresponding to the socket. The mode
and bufsize arguments are as for the built-in open() function.
""",
"recv":
"""
recv(bufsize[, flags]) -> data
Receive up to bufsize bytes from the socket. For the optional flags
argument, see the Unix manual. When no data is available, block until
at least one byte is available or until the remote end is closed. When
the remote end is closed and all data is read, return the empty string.
Currently the flags argument has no effect on Mac OS X.
""",
"recvfrom":
"""
recvfrom(bufsize[, flags]) -> (data, address info)
Like recv(buffersize, flags) but also return the sender's address info.
""",
"send":
"""
send(data[, flags]) -> count
Send a data string to the socket. For the optional flags
argument, see the Unix manual. Return the number of bytes
sent.
The socket must be connected to a remote socket.
Currently the flags argument has no effect on Mac OS X.
""",
"sendall":
"""
sendall(data[, flags])
Send a data string to the socket. For the optional flags
argument, see the Unix manual. This calls send() repeatedly
until all data is sent. If an error occurs, it's impossible
to tell how much data has been sent.
""",
"sendto":
"""
sendto(data[, flags], address) -> count
Like send(data, flags) but allows specifying the destination address.
For RFCOMM sockets, the address is a pair (hostaddr, channel).
""",
"setblocking":
"""
setblocking(flag)
Set the socket to blocking (flag is true) or non-blocking (false).
setblocking(True) is equivalent to settimeout(None);
setblocking(False) is equivalent to settimeout(0.0).
Initially a socket is in blocking mode. In non-blocking mode, if a
socket operation cannot be performed immediately, socket.error is raised.
The underlying implementation on Python for Series 60 only supports
non-blocking mode for send() and recv(), and ignores it for connect() and
accept().
""",
"setsockopt":
"""
setsockopt(level, option, value)
Set a socket option. See the Unix manual for level and option.
The value argument can either be an integer or a string.
Currently support for socket options are platform independent -- i.e.
depends on the underlying Series 60 or BlueZ socket options support.
The Mac OS X implementation currently does not support any options at
all and automatically raise socket.error.
""",
"settimeout":
"""
settimeout(timeout)
Set a timeout on socket operations. 'timeout' can be a float,
giving in seconds, or None. Setting a timeout of None disables
the timeout feature and is equivalent to setblocking(1).
Setting a timeout of zero is the same as setblocking(0).
If a timeout is set, the connect, accept, send and receive operations will
raise socket.timeout if a timeout occurs.
Raises NotImplementedError on Python For Series 60.
""",
"shutdown":
"""
shutdown(how)
Shut down the reading side of the socket (flag == socket.SHUT_RD), the
writing side of the socket (flag == socket.SHUT_WR), or both ends
(flag == socket.SHUT_RDWR).
"""
}
pybluez-0.23/macos/_macutil.py 0000775 0000000 0000000 00000021357 13601523637 0016422 0 ustar 00root root 0000000 0000000 # Copyright (c) 2009 Bea Lam. All rights reserved.
#
# This file is part of LightBlue.
#
# LightBlue is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# LightBlue is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with LightBlue. If not, see .
# Mac-specific utility functions and constants.
from Foundation import NSObject, NSDate, NSPoint, NSDefaultRunLoopMode, NSTimer
from AppKit import NSApplication, NSEvent, NSApplicationDefined, NSAnyEventMask
import objc
import time
from . import _IOBluetooth
from . import _lightbluecommon
# for mac os 10.5
try:
from Foundation import NSUIntegerMax
NSAnyEventMask = NSUIntegerMax
except:
pass
# values of constants used in _IOBluetooth.framework
kIOReturnSuccess = 0 # defined in
kIOBluetoothUserNotificationChannelDirectionIncoming = 1
# defined in
kBluetoothHCIErrorPageTimeout = 0x04 #
# defined in
kIOBluetoothServiceBrowserControllerOptionsNone = 0
LIGHTBLUE_NOTIFY_ID = 5444 # any old number
WAIT_MAX_TIMEOUT = 3
# IOBluetoothSDPUUID objects for RFCOMM and OBEX protocol UUIDs
PROTO_UUIDS = {
_lightbluecommon.RFCOMM: _IOBluetooth.IOBluetoothSDPUUID.uuid16_(0x0003),
_lightbluecommon.OBEX: _IOBluetooth.IOBluetoothSDPUUID.uuid16_(0x0008)
}
def formatdevaddr(addr):
"""
Returns address of a device in usual form e.g. "00:00:00:00:00:00"
- addr: address as returned by device.getAddressString() on an
IOBluetoothDevice
"""
# make uppercase cos PyS60 & Linux seem to always return uppercase
# addresses
# can safely encode to ascii cos BT addresses are only in hex (pyobjc
# returns all strings in unicode)
return addr.replace("-", ":").encode('ascii').upper()
def createbtdevaddr(addr):
# in mac 10.5, can use BluetoothDeviceAddress directly
chars = btaddrtochars(addr)
try:
btdevaddr = _IOBluetooth.BluetoothDeviceAddress(chars)
return btdevaddr
except:
return chars
def btaddrtochars(addr):
"""
Takes a bluetooth address and returns a tuple with the corresponding
char values. This can then be used to construct a
IOBluetoothDevice object, providing the signature of the withAddress:
selector has been set (as in _setpyobjcsignatures() in this module).
For example:
>>> chars = btaddrtochars("00:0e:0a:00:a2:00")
>>> chars
(0, 14, 10, 0, 162, 0)
>>> device = _IOBluetooth.IOBluetoothDevice.withAddress_(chars)
>>> type(device)
>>> device.getAddressString()
u'00-0e-0a-00-a2-00'
"""
if not _lightbluecommon._isbtaddr(addr):
raise TypeError("address %s not valid bluetooth address" % str(addr))
if addr.find(":") == -1:
addr = addr.replace("-", ":") # consider alternative addr separator
# unhexlify gives binary value like '\x0e', then ord to get the char value.
# unhexlify throws TypeError if value is not a hex pair.
import binascii
chars = [ord(binascii.unhexlify(part)) for part in addr.split(":")]
return tuple(chars)
def looponce():
app = NSApplication.sharedApplication()
# to push the run loops I seem to have to do this twice
# use NSEventTrackingRunLoopMode or NSDefaultRunLoopMode?
for i in range(2):
event = app.nextEventMatchingMask_untilDate_inMode_dequeue_(
NSAnyEventMask, NSDate.dateWithTimeIntervalSinceNow_(0.02),
NSDefaultRunLoopMode, False)
def waituntil(conditionfunc, timeout=None):
"""
Waits until conditionfunc() returns true, or seconds have passed.
(If timeout=None, this waits indefinitely until conditionfunc() returns
true.) Returns false if the process timed out, otherwise returns true.
Note!! You must call interruptwait() when you know that conditionfunc()
should be checked (e.g. if you are waiting for data and you know some data
has arrived) so that this can check conditionfunc(); otherwise it will just
continue to wait. (This allows the function to wait for an event that is
sent by interruptwait() instead of polling conditionfunc().)
This allows the caller to wait while the main event loop processes its
events. This must be done for certain situations, e.g. to receive socket
data or to accept client connections on a server socket, since IOBluetooth
requires the presence of an event loop to run these operations.
This function doesn't need to be called if there is something else that is
already processing the main event loop, e.g. if called from within a Cocoa
application.
"""
app = NSApplication.sharedApplication()
starttime = time.time()
if timeout is None:
timeout = NSDate.distantFuture().timeIntervalSinceNow()
if not isinstance(timeout, (int, float)):
raise TypeError("timeout must be int or float, was %s" % \
type(timeout))
endtime = starttime + timeout
while True:
currtime = time.time()
if currtime >= endtime:
return False
# use WAIT_MAX_TIMEOUT, don't wait forever in case of KeyboardInterrupt
e = app.nextEventMatchingMask_untilDate_inMode_dequeue_(NSAnyEventMask, NSDate.dateWithTimeIntervalSinceNow_(min(endtime - currtime, WAIT_MAX_TIMEOUT)), NSDefaultRunLoopMode, True)
if e is not None:
if (e.type() == NSApplicationDefined and e.subtype() == LIGHTBLUE_NOTIFY_ID):
if conditionfunc():
return True
else:
app.postEvent_atStart_(e, True)
def interruptwait():
"""
If waituntil() has been called, this will interrupt the waiting process so
it can check whether it should stop waiting.
"""
evt = NSEvent.otherEventWithType_location_modifierFlags_timestamp_windowNumber_context_subtype_data1_data2_(NSApplicationDefined, NSPoint(), NSApplicationDefined, 0, 1, None, LIGHTBLUE_NOTIFY_ID, 0, 0)
NSApplication.sharedApplication().postEvent_atStart_(evt, True)
class BBCocoaSleeper(NSObject):
def init(self):
self = super(BBCocoaSleeper, self).init()
self.timedout = False
return self
@objc.python_method
def sleep(self, timeout):
NSTimer.scheduledTimerWithTimeInterval_target_selector_userInfo_repeats_(
timeout, self, "timedOut:", None, False)
self.timedout = False
waituntil(lambda: self.timedout)
def timedOut_(self, timer):
self.timedout = True
interruptwait()
timedOut_ = objc.selector(timedOut_, signature=b"v@:@")
def waitfor(timeout):
sleeper = BBCocoaSleeper.alloc().init()
sleeper.sleep(timeout)
class BBFileLikeObjectReader(NSObject):
"""
Provides a suitable delegate class for the BBDelegatingInputStream class in
LightAquaBlue.framework.
This basically provides a wrapper for a python file-like object so that it
can be read through a NSInputStream.
"""
def initWithFileLikeObject_(self, fileobj):
self = super(BBFileLikeObjectReader, self).init()
self.__fileobj = fileobj
return self
initWithFileLikeObject_ = objc.selector(initWithFileLikeObject_,
signature=b"@@:@")
def readDataWithMaxLength_(self, maxlength):
try:
data = self.__fileobj.read(maxlength)
except Exception:
return None
return memoryview(data.encode())
readDataWithMaxLength_ = objc.selector(readDataWithMaxLength_,
signature=b"@@:I") #"@12@0:4I8" #"@:I"
class BBFileLikeObjectWriter(NSObject):
"""
Provides a suitable delegate class for the BBDelegatingOutputStream class in
LightAquaBlue.framework.
This basically provides a wrapper for a python file-like object so that it
can be written to through a NSOutputStream.
"""
def initWithFileLikeObject_(self, fileobj):
self = super(BBFileLikeObjectWriter, self).init()
self.__fileobj = fileobj
return self
initWithFileLikeObject_ = objc.selector(initWithFileLikeObject_,
signature=b"@@:@")
def write_(self, data):
try:
self.__fileobj.write(data)
except Exception:
return -1
return data.length()
write_ = objc.selector(write_, signature=b"i12@0:4@8") #i12@0:4@8 #i@:@
pybluez-0.23/macos/_obex.py 0000775 0000000 0000000 00000055654 13601523637 0015730 0 ustar 00root root 0000000 0000000 # Copyright (c) 2009 Bea Lam. All rights reserved.
#
# This file is part of LightBlue.
#
# LightBlue is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# LightBlue is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with LightBlue. If not, see .
import datetime
import time
import types
import objc
from Foundation import NSObject, NSDate
from ._IOBluetooth import OBEXSession, IOBluetoothDevice, \
IOBluetoothRFCOMMChannel
from ._LightAquaBlue import BBBluetoothOBEXClient, BBBluetoothOBEXServer, \
BBStreamingInputStream, BBStreamingOutputStream, \
BBMutableOBEXHeaderSet, \
BBLocalDevice
from . import _lightbluecommon
from . import _obexcommon
from . import _macutil
from ._obexcommon import OBEXError
# from
_kOBEXSuccess = 0
_kOBEXGeneralError = -21850
_kOBEXSessionNotConnectedError = -21876
_kOBEXSessionAlreadyConnectedError = -21882
_kOBEXSessionNoTransportError = -21879
_kOBEXSessionTransportDiedError = -21880
_OBEX_FINAL_MASK = 0x80
_HEADER_MASK = 0xc0
_HEADER_UNICODE = 0x00
_HEADER_BYTE_SEQ = 0x40
_HEADER_1BYTE = 0x80
_HEADER_4BYTE = 0xc0
# public attributes
__all__ = ("OBEXClient", "sendfile", "recvfile")
_obexerrorcodes = { 0: "no error", -21850: "general error", -21851: "no resources", -21852: "operation not supported", -21853: "internal error", -21854: "bad argument", -21855: "timeout", -21856: "bad request", -21857: "cancelled", -21875: "session is busy", -21876: "OBEX session not connected", -21877: "bad request in OBEX session", -21878: "bad response from other party", -21879: "Bluetooth transport not available", -21880: "Bluetooth transport connection died", -21881: "OBEX session timed out", -21882: "OBEX session already connected" }
def errdesc(errorcode):
return _obexerrorcodes.get(errorcode, str(errorcode))
# OBEXSession provides response codes with the final bit set, but OBEXResponse
# class expects the response code to not have the final bit set.
def _cutresponsefinalbit(responsecode):
return (responsecode & ~_OBEX_FINAL_MASK)
def _headersdicttoset(headers):
headerset = BBMutableOBEXHeaderSet.alloc().init()
for header, value in list(headers.items()):
if isinstance(header, str):
hid = _obexcommon._HEADER_STRINGS_TO_IDS.get(header.lower())
else:
hid = header
if hid is None:
raise ValueError("unknown header '%s'" % header)
if isinstance(value, datetime.datetime):
value = value.strftime("%Y%m%dT%H%M%S")
mask = hid & _HEADER_MASK
if mask == _HEADER_UNICODE:
if not isinstance(value, str):
raise TypeError("value for '%s' must be string, was %s" %
(str(header), type(value)))
headerset.setValue_forUnicodeHeader_(value, hid)
elif mask == _HEADER_BYTE_SEQ:
try:
value = memoryview(value.encode())
except:
raise TypeError("value for '%s' must be string, array or other buffer type, was %s" % (str(header), type(value)))
headerset.setValue_forByteSequenceHeader_(value, hid)
elif mask == _HEADER_1BYTE:
if not isinstance(value, int):
raise TypeError("value for '%s' must be int, was %s" %
(str(header), type(value)))
headerset.setValue_for1ByteHeader_(value, hid)
elif mask == _HEADER_4BYTE:
if not isinstance(value, int) and not isinstance(value, int):
raise TypeError("value for '%s' must be int, was %s" %
(str(header), type(value)))
headerset.setValue_for4ByteHeader_(value, hid)
if not headerset.containsValueForHeader_(hid):
raise ValueError("cannot set OBEX header value for '%s'" % header)
return headerset
# returns in { header-id: value } form.
def _headersettodict(headerset):
headers = {}
for number in headerset.allHeaders():
hid = number.unsignedCharValue()
mask = hid & _HEADER_MASK
if mask == _HEADER_UNICODE:
value = headerset.valueForUnicodeHeader_(hid)
elif mask == _HEADER_BYTE_SEQ:
value = headerset.valueForByteSequenceHeader_(hid)[:]
if hid == 0x42: # type
if len(value) > 0 and value[-1] == '\0':
value = value[:-1] # remove null byte
elif hid == 0x44: # time iso-8601 string
value = _obexcommon._datetimefromstring(value)
elif mask == _HEADER_1BYTE:
value = headerset.valueFor1ByteHeader_(hid)
elif mask == _HEADER_4BYTE:
value = headerset.valueFor4ByteHeader_(hid)
headers[hid] = value
return headers
class OBEXClient(object):
__doc__ = _obexcommon._obexclientclassdoc
def __init__(self, address, channel):
if not _lightbluecommon._isbtaddr(address):
raise TypeError("address '%s' is not a valid bluetooth address"
% address)
if not type(channel) == int:
raise TypeError("channel must be int, was %s" % type(channel))
if channel < 0:
raise ValueError("channel cannot be negative")
self.__serveraddr = (address, channel)
self.__busy = False
self.__client = None
self.__obexsession = None # for testing
#BBBluetoothOBEXClient.setDebug_(True)
def connect(self, headers={}):
if self.__client is None:
if not BBLocalDevice.isPoweredOn():
raise OBEXError(_kOBEXSessionNoTransportError,
"Bluetooth device not available")
self.__delegate = _BBOBEXClientDelegate.alloc().initWithCallback_(
self._finishedrequest)
self.__client = BBBluetoothOBEXClient.alloc().initWithRemoteDeviceAddress_channelID_delegate_(
_macutil.createbtdevaddr(self.__serveraddr[0]),
self.__serveraddr[1], self.__delegate)
if self.__obexsession is not None:
self.__client.performSelector_withObject_("setOBEXSession:",
self.__obexsession)
self.__reset()
headerset = _headersdicttoset(headers)
r = self.__client.sendConnectRequestWithHeaders_(headerset)
if r != _kOBEXSuccess:
self.__closetransport()
raise OBEXError(r, "error starting Connect request (%s)" %
errdesc(r))
_macutil.waituntil(self._done)
if self.__error != _kOBEXSuccess:
self.__closetransport()
raise OBEXError(self.__error, "error during Connect request (%s)" %
errdesc(self.__error))
resp = self.__getresponse()
if resp.code != _obexcommon.OK:
self.__closetransport()
return resp
def disconnect(self, headers={}):
self.__checkconnected()
self.__reset()
try:
headerset = _headersdicttoset(headers)
r = self.__client.sendDisconnectRequestWithHeaders_(headerset)
if r != _kOBEXSuccess:
raise OBEXError(r, "error starting Disconnect request (%s)" %
errdesc(r))
_macutil.waituntil(self._done)
if self.__error != _kOBEXSuccess:
raise OBEXError(self.__error,
"error during Disconnect request (%s)" %
errdesc(self.__error))
finally:
# close channel regardless of disconnect result
self.__closetransport()
return self.__getresponse()
def put(self, headers, fileobj):
if not hasattr(fileobj, "read"):
raise TypeError("file-like object must have read() method")
self.__checkconnected()
self.__reset()
headerset = _headersdicttoset(headers)
self.fileobj = fileobj
self.__fileobjdelegate = _macutil.BBFileLikeObjectReader.alloc().initWithFileLikeObject_(fileobj)
self.instream = BBStreamingInputStream.alloc().initWithDelegate_(self.__fileobjdelegate)
self.instream.open()
r = self.__client.sendPutRequestWithHeaders_readFromStream_(
headerset, self.instream)
if r != _kOBEXSuccess:
raise OBEXError(r, "error starting Put request (%s)" % errdesc(r))
_macutil.waituntil(self._done)
if self.__error != _kOBEXSuccess:
raise OBEXError(self.__error, "error during Put request (%s)" %
errdesc(self.__error))
return self.__getresponse()
def delete(self, headers):
self.__checkconnected()
self.__reset()
headerset = _headersdicttoset(headers)
r = self.__client.sendPutRequestWithHeaders_readFromStream_(headerset,
None)
if r != _kOBEXSuccess:
raise OBEXError(r, "error starting Delete request (%s)" %
errdesc(r))
_macutil.waituntil(self._done)
if self.__error != _kOBEXSuccess:
raise OBEXError(self.__error, "error during Delete request (%s)" %
errdesc(self.__error))
return self.__getresponse()
def get(self, headers, fileobj):
if not hasattr(fileobj, "write"):
raise TypeError("file-like object must have write() method")
self.__checkconnected()
self.__reset()
headerset = _headersdicttoset(headers)
delegate = _macutil.BBFileLikeObjectWriter.alloc().initWithFileLikeObject_(fileobj)
outstream = BBStreamingOutputStream.alloc().initWithDelegate_(delegate)
outstream.open()
r = self.__client.sendGetRequestWithHeaders_writeToStream_(
headerset, outstream)
if r != _kOBEXSuccess:
raise OBEXError(r, "error starting Get request (%s)" % errdesc(r))
_macutil.waituntil(self._done)
if self.__error != _kOBEXSuccess:
raise OBEXError(self.__error, "error during Get request (%s)" %
errdesc(self.__error))
return self.__getresponse()
def setpath(self, headers, cdtoparent=False, createdirs=False):
self.__checkconnected()
self.__reset()
headerset = _headersdicttoset(headers)
r = self.__client.sendSetPathRequestWithHeaders_changeToParentDirectoryFirst_createDirectoriesIfNeeded_(headerset, cdtoparent, createdirs)
if r != _kOBEXSuccess:
raise OBEXError(r, "error starting SetPath request (%s)" %
errdesc(r))
_macutil.waituntil(self._done)
if self.__error != _kOBEXSuccess:
raise OBEXError(self.__error, "error during SetPath request (%s)" %
errdesc(self.__error))
return self.__getresponse()
def _done(self):
return not self.__busy
def _finishedrequest(self, error, response):
if error in (_kOBEXSessionNoTransportError,
_kOBEXSessionTransportDiedError):
self.__closetransport()
self.__error = error
self.__response = response
self.__busy = False
_macutil.interruptwait()
def _setobexsession(self, session):
self.__obexsession = session
# Note that OBEXSession returns kOBEXSessionNotConnectedError if you don't
# send CONNECT before sending any other requests; this means the OBEXClient
# must send connect() before other requests, so this restriction is enforced
# in the Linux version as well, for consistency.
def __checkconnected(self):
if self.__client is None:
raise OBEXError(_kOBEXSessionNotConnectedError,
"must connect() before sending other requests")
def __closetransport(self):
if self.__client is not None:
try:
self.__client.RFCOMMChannel().closeChannel()
self.__client.RFCOMMChannel().getDevice().closeConnection()
except:
pass
self.__client = None
def __reset(self):
self.__busy = True
self.__error = None
self.__response = None
def __getresponse(self):
code = self.__response.responseCode()
rawheaders = _headersettodict(self.__response.allHeaders())
return _obexcommon.OBEXResponse(_cutresponsefinalbit(code), rawheaders)
def __del__(self):
if self.__client is not None:
self.__client.__del__()
super(OBEXClient, self).__del__()
# set method docstrings
definedmethods = locals() # i.e. defined methods in OBEXClient
for name, doc in list(_obexcommon._obexclientdocs.items()):
try:
definedmethods[name].__doc__ = doc
except KeyError:
pass
class _BBOBEXClientDelegate(NSObject):
def initWithCallback_(self, cb_requestdone):
self = super(_BBOBEXClientDelegate, self).init()
self._cb_requestdone = cb_requestdone
return self
initWithCallback_ = objc.selector(initWithCallback_, signature=b"@@:@")
def __del__(self):
super(_BBOBEXClientDelegate, self).dealloc()
#
# Delegate methods follow. objc signatures for all methods must be set
# using objc.selector or else may get bus error.
#
# - (void)client:(BBBluetoothOBEXClient *)client
# didFinishConnectRequestWithError:(OBEXError)error
# response:(BBOBEXResponse *)response;
def client_didFinishConnectRequestWithError_response_(self, client, error,
response):
self._cb_requestdone(error, response)
client_didFinishConnectRequestWithError_response_ = objc.selector(
client_didFinishConnectRequestWithError_response_, signature=b"v@:@i@")
# - (void)client:(BBBluetoothOBEXClient *)client
# didFinishDisconnectRequestWithError:(OBEXError)error
# response:(BBOBEXResponse *)response;
def client_didFinishDisconnectRequestWithError_response_(self, client,
error, response):
self._cb_requestdone(error, response)
client_didFinishDisconnectRequestWithError_response_ = objc.selector(
client_didFinishDisconnectRequestWithError_response_,signature=b"v@:@i@")
# - (void)client:(BBBluetoothOBEXClient *)client
# didFinishPutRequestForStream:(NSInputStream *)inputStream
# error:(OBEXError)error
# response:(BBOBEXResponse *)response;
def client_didFinishPutRequestForStream_error_response_(self, client,
instream, error, response):
self._cb_requestdone(error, response)
client_didFinishPutRequestForStream_error_response_ = objc.selector(
client_didFinishPutRequestForStream_error_response_,signature=b"v@:@@i@")
# - (void)client:(BBBluetoothOBEXClient *)client
# didFinishGetRequestForStream:(NSOutputStream *)outputStream
# error:(OBEXError)error
# response:(BBOBEXResponse *)response;
def client_didFinishGetRequestForStream_error_response_(self, client,
outstream, error, response):
self._cb_requestdone(error, response)
client_didFinishGetRequestForStream_error_response_ = objc.selector(
client_didFinishGetRequestForStream_error_response_,signature=b"v@:@@i@")
# - (void)client:(BBBluetoothOBEXClient *)client
# didFinishSetPathRequestWithError:(OBEXError)error
# response:(BBOBEXResponse *)response;
def client_didFinishSetPathRequestWithError_response_(self, client, error,
response):
self._cb_requestdone(error, response)
client_didFinishSetPathRequestWithError_response_ = objc.selector(
client_didFinishSetPathRequestWithError_response_, signature=b"v@:@i@")
# client:didAbortRequestWithStream:error:response: not
# implemented since OBEXClient does not allow abort requests
# ------------------------------------------------------------------
def sendfile(address, channel, source):
if not _lightbluecommon._isbtaddr(address):
raise TypeError("address '%s' is not a valid bluetooth address" %
address)
if not isinstance(channel, int):
raise TypeError("channel must be int, was %s" % type(channel))
if not isinstance(source, str) and \
not hasattr(source, "read"):
raise TypeError("source must be string or file-like object with read() method")
if isinstance(source, str):
headers = {"name": source}
fileobj = open(source, "rb")
closefileobj = True
else:
if hasattr(source, "name"):
headers = {"name": source.name}
fileobj = source
closefileobj = False
client = OBEXClient(address, channel)
client.connect()
try:
resp = client.put(headers, fileobj)
finally:
if closefileobj:
fileobj.close()
try:
client.disconnect()
except:
pass # always ignore disconnection errors
if resp.code != _obexcommon.OK:
raise OBEXError("server denied the Put request")
# ------------------------------------------------------------------
class BBOBEXObjectPushServer(NSObject):
def initWithChannel_fileLikeObject_(self, channel, fileobject):
if not isinstance(channel, IOBluetoothRFCOMMChannel) and \
not isinstance(channel, OBEXSession):
raise TypeError("internal error, channel is of wrong type %s" %
type(channel))
if not hasattr(fileobject, "write"):
raise TypeError("fileobject must be file-like object with write() method")
self = super(BBOBEXObjectPushServer, self).init()
self.__fileobject = fileobject
self.__server = BBBluetoothOBEXServer.alloc().initWithIncomingRFCOMMChannel_delegate_(channel, self)
#BBBluetoothOBEXServer.setDebug_(True)
self.__error = None
self.__gotfile = False
self.__gotdisconnect = False
self.__disconnected = False
# for internal testing
if isinstance(channel, OBEXSession):
self.__server.performSelector_withObject_("setOBEXSession:",
channel)
return self
initWithChannel_fileLikeObject_ = objc.selector(
initWithChannel_fileLikeObject_, signature=b"@@:i@")
def run(self):
self.__server.run()
# wait until client sends a file, or an error occurs
_macutil.waituntil(lambda: self.__gotfile or self.__error is not None)
# wait briefly for a disconnect request (client may have decided to just
# close the connection without sending a disconnect request)
if self.__error is None:
ok = _macutil.waituntil(lambda: self.__gotdisconnect, 3)
if ok:
_macutil.waituntil(lambda: self.__disconnected)
# only raise OBEXError if file was not received
if not self.__gotfile:
if self.__error is not None:
raise OBEXError(self.__error[0], self.__error[1])
# if client connected but didn't send PUT
raise OBEXError(_kOBEXGeneralError, "client did not send a file")
def __del__(self):
super(BBOBEXObjectPushServer, self).dealloc()
#
# BBBluetoothOBEXClientDelegate methods follow.
# These enable this class to get callbacks when some event occurs on the
# server (e.g. got a new client request, or an error occurred, etc.).
#
# - (BOOL)server:(BBBluetoothOBEXServer *)server
# shouldHandleConnectRequest:(BBOBEXHeaderSet *)requestHeaders;
def server_shouldHandleConnectRequest_(self, server, requestheaders):
return True
server_shouldHandleConnectRequest_ = objc.selector(
server_shouldHandleConnectRequest_, signature=b"c@:@@")
# - (BOOL)server:(BBBluetoothOBEXServer *)server
# shouldHandleDisconnectRequest:(BBOBEXHeaderSet *)requestHeaders;
def server_shouldHandleDisconnectRequest_(self, server, requestheaders):
self.__gotdisconnect = True
_macutil.interruptwait()
return True
server_shouldHandleDisconnectRequest_ = objc.selector(
server_shouldHandleDisconnectRequest_, signature=b"c@:@@")
# - (void)serverDidHandleDisconnectRequest:(BBBluetoothOBEXServer *)server;
def serverDidHandleDisconnectRequest_(self, server):
self.__disconnected = True
_macutil.interruptwait()
serverDidHandleDisconnectRequest_ = objc.selector(
serverDidHandleDisconnectRequest_, signature=b"v@:@")
# - (NSOutputStream *)server:(BBBluetoothOBEXServer *)server
# shouldHandlePutRequest:(BBOBEXHeaderSet *)requestHeaders;
def server_shouldHandlePutRequest_(self, server, requestheaders):
#print "Incoming file:", requestHeaders.valueForNameHeader()
self.delegate = _macutil.BBFileLikeObjectWriter.alloc().initWithFileLikeObject_(self.__fileobject)
outstream = BBStreamingOutputStream.alloc().initWithDelegate_(self.delegate)
outstream.open()
return outstream
server_shouldHandlePutRequest_ = objc.selector(
server_shouldHandlePutRequest_, signature=b"@@:@@")
# - (void)server:(BBBluetoothOBEXServer *)server
# didHandlePutRequestForStream:(NSOutputStream *)outputStream
# requestWasAborted:(BOOL)aborted;
def server_didHandlePutRequestForStream_requestWasAborted_(self, server,
stream, aborted):
if aborted:
self.__error = (_kOBEXGeneralError, "client aborted file transfer")
else:
self.__gotfile = True
_macutil.interruptwait()
server_didHandlePutRequestForStream_requestWasAborted_ = objc.selector(
server_didHandlePutRequestForStream_requestWasAborted_,
signature=b"v@:@@c")
# - (void)server:(BBBluetoothOBEXServer *)server
# errorOccurred:(OBEXError)error
# description:(NSString *)description;
def server_errorOccurred_description_(self, server, error, desc):
self.__error = (error, desc)
_macutil.interruptwait()
server_errorOccurred_description_ = objc.selector(
server_errorOccurred_description_, signature=b"v@:@i@")
# ------------------------------------------------------------------
def recvfile(sock, dest):
if sock is None:
raise TypeError("Given socket is None")
if not isinstance(dest, (str, types.FileType)):
raise TypeError("dest must be string or file-like object with write() method")
if isinstance(dest, str):
fileobj = open(dest, "wb")
closefileobj = True
else:
fileobj = dest
closefileobj = False
try:
sock.listen(1)
conn, addr = sock.accept()
#print "A client connected:", addr
server = BBOBEXObjectPushServer.alloc().initWithChannel_fileLikeObject_(
conn._getchannel(), fileobj)
server.run()
conn.close()
finally:
if closefileobj:
fileobj.close()
pybluez-0.23/macos/_obexcommon.py 0000775 0000000 0000000 00000043414 13601523637 0017130 0 ustar 00root root 0000000 0000000 # Copyright (c) 2009 Bea Lam. All rights reserved.
#
# This file is part of LightBlue.
#
# LightBlue is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# LightBlue is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with LightBlue. If not, see .
from . import _lightbluecommon
__all__ = ('OBEXResponse', 'OBEXError',
'CONTINUE', 'OK', 'CREATED', 'ACCEPTED', 'NON_AUTHORITATIVE_INFORMATION',
'NO_CONTENT', 'RESET_CONTENT', 'PARTIAL_CONTENT',
'MULTIPLE_CHOICES', 'MOVED_PERMANENTLY', 'MOVED_TEMPORARILY', 'SEE_OTHER',
'NOT_MODIFIED', 'USE_PROXY',
'BAD_REQUEST', 'UNAUTHORIZED', 'PAYMENT_REQUIRED', 'FORBIDDEN',
'NOT_FOUND', 'METHOD_NOT_ALLOWED', 'NOT_ACCEPTABLE',
'PROXY_AUTHENTICATION_REQUIRED', 'REQUEST_TIME_OUT', 'CONFLICT', 'GONE',
'LENGTH_REQUIRED', 'PRECONDITION_FAILED', 'REQUESTED_ENTITY_TOO_LARGE',
'REQUEST_URL_TOO_LARGE', 'UNSUPPORTED_MEDIA_TYPE',
'INTERNAL_SERVER_ERROR', 'NOT_IMPLEMENTED', 'BAD_GATEWAY',
'SERVICE_UNAVAILABLE', 'GATEWAY_TIMEOUT', 'HTTP_VERSION_NOT_SUPPORTED',
'DATABASE_FULL', 'DATABASE_LOCKED')
class OBEXError(_lightbluecommon.BluetoothError):
"""
Generic exception raised for OBEX-related errors.
"""
pass
class OBEXResponse:
"""
Contains the OBEX response received from an OBEX server.
When an OBEX client sends a request, the OBEX server sends back a response
code (to indicate whether the request was successful) and a set of response
headers (to provide other useful information).
For example, if a client sends a 'Get' request to retrieve a file, the
client might get a response like this:
>>> import lightblue
>>> client = lightblue.obex.OBEXClient("aa:bb:cc:dd:ee:ff", 10)
>>> response = client.get({"name": "file.txt"}, file("file.txt", "w"))
>>> print response
You can get the response code and response headers in different formats:
>>> print response.reason
'OK' # a string description of the response code
>>> print response.code
32 # the response code (e.g. this is 0x20)
>>> print response.headers
{'length': 35288} # the headers, with string keys
>>> print response.rawheaders
{195: 35288} # the headers, with raw header ID keys
>>>
Note how the 'code' attribute does not have the final bit set - e.g. for
OK/Success, the response code is 0x20, not 0xA0.
The lightblue.obex module defines constants for response code values (e.g.
lightblue.obex.OK, lightblue.obex.FORBIDDEN, etc.).
"""
def __init__(self, code, rawheaders):
self.__code = code
self.__reason = _OBEX_RESPONSES.get(code, "Unknown response code")
self.__rawheaders = rawheaders
self.__headers = None
code = property(lambda self: self.__code,
doc='The response code, without the final bit set.')
reason = property(lambda self: self.__reason,
doc='A string description of the response code.')
rawheaders = property(lambda self: self.__rawheaders,
doc='The response headers, as a dictionary with header ID (unsigned byte) keys.')
def getheader(self, header, default=None):
'''
Returns the response header value for the given header, which may
either be a string (not case-sensitive) or the raw byte
value of the header ID.
Returns the specified default value if the header is not present.
'''
if isinstance(header, str):
return self.headers.get(header.lower(), default)
return self.__rawheaders.get(header, default)
def __getheaders(self):
if self.__headers is None:
self.__headers = {}
for headerid, value in list(self.__rawheaders.items()):
if headerid in _HEADER_IDS_TO_STRINGS:
self.__headers[_HEADER_IDS_TO_STRINGS[headerid]] = value
else:
self.__headers["0x%02x" % headerid] = value
return self.__headers
headers = property(__getheaders,
doc='The response headers, as a dictionary with string keys.')
def __repr__(self):
return "" % \
(self.__reason, self.__code, (self.__code | 0x80), str(self.headers))
try:
import datetime
# as from python docs example
class UTC(datetime.tzinfo):
"""UTC"""
def utcoffset(self, dt):
return datetime.timedelta(0)
def tzname(self, dt):
return "UTC"
def dst(self, dt):
return datetime.timedelta(0)
except:
pass # no datetime on pys60
_LOCAL_TIME_FORMAT = "%Y%m%dT%H%M%S"
_UTC_TIME_FORMAT = _LOCAL_TIME_FORMAT + "Z"
def _datetimefromstring(s):
import time
if s[-1:] == "Z":
# add UTC() instance as tzinfo
args = (time.strptime(s, _UTC_TIME_FORMAT)[0:6]) + (0, UTC())
return datetime.datetime(*args)
else:
return datetime.datetime(*(time.strptime(s, _LOCAL_TIME_FORMAT)[0:6]))
_HEADER_STRINGS_TO_IDS = {
"count": 0xc0,
"name": 0x01,
"type": 0x42,
"length": 0xc3,
"time": 0x44,
"description": 0x05,
"target": 0x46,
"http": 0x47,
"who": 0x4a,
"connection-id": 0xcb,
"application-parameters": 0x4c,
"authentication-challenge": 0x4d,
"authentication-response": 0x4e,
"creator-id": 0xcf,
"wan-uuid": 0x50,
"object-class": 0x51,
"session-parameters": 0x52,
"session-sequence-number": 0x93
}
_HEADER_IDS_TO_STRINGS = {}
for key, value in list(_HEADER_STRINGS_TO_IDS.items()):
_HEADER_IDS_TO_STRINGS[value] = key
assert len(_HEADER_IDS_TO_STRINGS) == len(_HEADER_STRINGS_TO_IDS)
# These match the associated strings in httplib.responses, since OBEX response
# codes are matched to HTTP status codes (except for 0x60 and 0x61).
# Note these are the responses *without* the final bit set.
_OBEX_RESPONSES = {
0x10: "Continue",
0x20: "OK",
0x21: "Created",
0x22: "Accepted",
0x23: "Non-Authoritative Information",
0x24: "No Content",
0x25: "Reset Content",
0x26: "Partial Content",
0x30: "Multiple Choices",
0x31: "Moved Permanently",
0x32: "Moved Temporarily", # but is 'Found' (302) in httplib.response???
0x33: "See Other",
0x34: "Not Modified",
0x35: "Use Proxy",
0x40: "Bad Request",
0x41: "Unauthorized",
0x42: "Payment Required",
0x43: "Forbidden",
0x44: "Not Found",
0x45: "Method Not Allowed",
0x46: "Not Acceptable",
0x47: "Proxy Authentication Required",
0x48: "Request Timeout",
0x49: "Conflict",
0x4A: "Gone",
0x48: "Length Required",
0x4C: "Precondition Failed",
0x4D: "Request Entity Too Large",
0x4E: "Request-URI Too Long",
0x4F: "Unsupported Media Type",
0x50: "Internal Server Error",
0x51: "Not Implemented",
0x52: "Bad Gateway",
0x53: "Service Unavailable",
0x54: "Gateway Timeout",
0x55: "HTTP Version Not Supported",
0x60: "Database Full",
0x61: "Database Locked"
}
_obexclientclassdoc = \
"""
An OBEX client class. (Note this is not available on Python for Series 60.)
For example, to connect to an OBEX server and send a file:
>>> import lightblue
>>> client = lightblue.obex.OBEXClient("aa:bb:cc:dd:ee:ff", 10)
>>> client.connect()
>>> client.put({"name": "photo.jpg"}, file("photo.jpg", "rb"))
>>> client.disconnect()
>>>
A client must call connect() to establish a connection before it can send
any other requests.
The connect(), disconnect(), put(), delete(), get() and setpath() methods
all accept the request headers as a dictionary of header-value mappings. The
request headers are used to provide the server with additional information
for the request. For example, this sends a Put request that includes Name,
Type and Length headers in the request headers, to provide details about
the transferred file:
>>> f = file("file.txt")
>>> client.put({"name": "file.txt", "type": "text/plain",
... "length": 5192}, f)
>>>
Here is a list of all the different string header keys that you can use in
the request headers, and the expected type of the value for each header:
- "name" -> a string
- "type" -> a string
- "length" -> an int
- "time" -> a datetime object from the datetime module
- "description" -> a string
- "target" -> a string or buffer
- "http" -> a string or buffer
- "who" -> a string or buffer
- "connection-id" -> an int
- "application-parameters" -> a string or buffer
- "authentication-challenge" -> a string or buffer
- "authentication-response" -> a string or buffer
- "creator-id" -> an int
- "wan-uuid" -> a string or buffer
- "object-class" -> a string or buffer
- "session-parameters" -> a string or buffer
- "session-sequence-number" -> an int less than 256
(The string header keys are not case-sensitive.)
Alternatively, you can use raw header ID values instead of the above
convenience strings. So, the previous example can be rewritten as:
>>> client.put({0x01: "file.txt", 0x42: "text/plain", 0xC3: 5192},
... fileobject)
>>>
This is also useful for inserting custom headers. For example, a PutImage
request for a Basic Imaging client requires the Img-Descriptor (0x71)
header:
>>> client.put({"type": "x-bt/img-img",
... "name": "photo.jpg",
... 0x71: ''},
... file('photo.jpg', 'rb'))
>>>
Notice that the connection-id header is not sent, because this is
automatically included by OBEXClient in the request headers if a
connection-id was received in a previous Connect response.
See the included src/examples/obex_ftp_client.py for an example of using
OBEXClient to implement a File Transfer client for browsing the files on a
remote device.
"""
_obexclientdocs = {
"__init__":
"""
Creates an OBEX client.
Arguments:
- address: the address of the remote device
- channel: the RFCOMM channel of the remote OBEX service
""",
"connect":
"""
Establishes the Bluetooth connection to the remote OBEX server and sends
a Connect request to open the OBEX session. Returns an OBEXResponse
instance containing the server response.
Raises lightblue.obex.OBEXError if the session is already connected, or if
an error occurs during the request.
If the server refuses the Connect request (i.e. if it sends a response code
other than OK/Success), the Bluetooth connection will be closed.
Arguments:
- headers={}: the headers to send for the Connect request
""",
"disconnect":
"""
Sends a Disconnect request to end the OBEX session and closes the Bluetooth
connection to the remote OBEX server. Returns an OBEXResponse
instance containing the server response.
Raises lightblue.obex.OBEXError if connect() has not been called, or if an
error occurs during the request.
Note that you don't need to send any connection-id headers - this is
automatically included if the client received one in a Connect response.
Arguments:
- headers={}: the headers to send for the request
""",
"put":
"""
Sends a Put request. Returns an OBEXResponse instance containing the
server response.
Raises lightblue.obex.OBEXError if connect() has not been called, or if an
error occurs during the request.
Note that you don't need to send any connection-id headers - this is
automatically included if the client received one in a Connect response.
Arguments:
- headers: the headers to send for the request
- fileobj: a file-like object containing the file data to be sent for
the request
For example, to send a file named 'photo.jpg', using the request headers
to notify the server of the file's name, MIME type and length:
>>> client = lightblue.obex.OBEXClient("aa:bb:cc:dd:ee:ff", 10)
>>> client.connect()
>>> client.put({"name": "photo.jpg", "type": "image/jpeg",
"length": 28566}, file("photo.jpg", "rb"))
>>>
""",
"delete":
"""
Sends a Put-Delete request in order to delete a file or folder on the remote
server. Returns an OBEXResponse instance containing the server response.
Raises lightblue.obex.OBEXError if connect() has not been called, or if an
error occurs during the request.
Note that you don't need to send any connection-id headers - this is
automatically included if the client received one in a Connect response.
Arguments:
- headers: the headers to send for the request - you should use the
'name' header to specify the file you want to delete
If the file on the server can't be deleted because it's a read-only file,
you might get an 'Unauthorized' response, like this:
>>> client = lightblue.obex.OBEXClient("aa:bb:cc:dd:ee:ff", 10)
>>> client.connect()
>>> client.delete({"name": "random_file.txt"})
>>>
""",
"get":
"""
Sends a Get request. Returns an OBEXResponse instance containing the server
response.
Raises lightblue.obex.OBEXError if connect() has not been called, or if an
error occurs during the request.
Note that you don't need to send any connection-id headers - this is
automatically included if the client received one in a Connect response.
Arguments:
- headers: the headers to send for the request - you should use these
to specify the file you want to retrieve
- fileobj: a file-like object, to which the received data will be
written
An example:
>>> client = lightblue.obex.OBEXClient("aa:bb:cc:dd:ee:ff", 10)
>>> client.connect()
>>> f = file("received_file.txt", "w+")
>>> client.get({"name": "testfile.txt"}, f)
>>> f.seek(0)
>>> f.read()
'test file'
>>>
""",
"setpath":
"""
Sends a SetPath request in order to set the "current path" on the remote
server for file transfers. Returns an OBEXResponse instance containing the
server response.
Raises lightblue.obex.OBEXError if connect() has not been called, or if an
error occurs during the request.
Note that you don't need to send any connection-id headers - this is
automatically included if the client received one in a Connect response.
Arguments:
- headers: the headers to send for the request - you should use the
'name' header to specify the directory you want to change to
- cdtoparent=False: True if the remote server should move up one
directory before applying the specified directory (i.e. 'cd
../dirname')
- createdirs=False: True if the specified directory should be created
if it doesn't exist (if False, the server will return an error
response if the directory doesn't exist)
For example:
# change to the "images" subdirectory
>>> client.setpath({"name": "images"})
>>>
# change to the parent directory
>>> client.setpath({}, cdtoparent=True)
>>>
# create a subdirectory "My_Files"
>>> client.setpath({"name": "My_Files"}, createdirs=True)
>>>
# change to the root directory - you can use an empty "name" header
# to specify this
>>> client.setpath({"name": ""})
>>>
"""
}
# response constants
CONTINUE = 0x10
OK = 0x20
CREATED = 0x21
ACCEPTED = 0x22
NON_AUTHORITATIVE_INFORMATION = 0x23
NO_CONTENT = 0x24
RESET_CONTENT = 0x25
PARTIAL_CONTENT = 0x26
MULTIPLE_CHOICES = 0x30
MOVED_PERMANENTLY = 0x31
MOVED_TEMPORARILY = 0x32
SEE_OTHER = 0x33
NOT_MODIFIED = 0x34
USE_PROXY = 0x35
BAD_REQUEST = 0x40
UNAUTHORIZED = 0x41
PAYMENT_REQUIRED = 0x42
FORBIDDEN = 0x43
NOT_FOUND = 0x44
METHOD_NOT_ALLOWED = 0x45
NOT_ACCEPTABLE = 0x46
PROXY_AUTHENTICATION_REQUIRED = 0x47
REQUEST_TIME_OUT = 0x48
CONFLICT = 0x49
GONE = 0x4A
LENGTH_REQUIRED = 0x4B
PRECONDITION_FAILED = 0x4C
REQUESTED_ENTITY_TOO_LARGE = 0x4D
REQUEST_URL_TOO_LARGE = 0x4E
UNSUPPORTED_MEDIA_TYPE = 0x4F
INTERNAL_SERVER_ERROR = 0x50
NOT_IMPLEMENTED = 0x51
BAD_GATEWAY = 0x52
SERVICE_UNAVAILABLE = 0x53
GATEWAY_TIMEOUT = 0x54
HTTP_VERSION_NOT_SUPPORTED = 0x55
DATABASE_FULL = 0x60
DATABASE_LOCKED = 0x61
pybluez-0.23/macos/obex.py 0000664 0000000 0000000 00000006555 13601523637 0015562 0 ustar 00root root 0000000 0000000 # Copyright (c) 2009 Bea Lam. All rights reserved.
#
# This file is part of LightBlue.
#
# LightBlue is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# LightBlue is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
# You should have received a copy of the GNU General Public License
# along with LightBlue. If not, see .
"""
Provides an OBEX client class and convenience functions for sending and
receiving files over OBEX.
This module also defines constants for response code values (without the final
bit set). For example:
>>> import lightblue
>>> lightblue.obex.OK
32 # the OK/Success response 0x20 (i.e. 0xA0 without the final bit)
>>> lightblue.obex.FORBIDDEN
67 # the Forbidden response 0x43 (i.e. 0xC3 without the final bit)
"""
# Docstrings for attributes in this module.
_docstrings = {
"sendfile":
"""
Sends a file to a remote device.
Raises lightblue.obex.OBEXError if an error occurred during the request, or
if the request was refused by the remote device.
Arguments:
- address: the address of the remote device
- channel: the RFCOMM channel of the remote OBEX service
- source: a filename or file-like object, containing the data to be
sent. If a file object is given, it must be opened for reading.
Note you can achieve the same thing using OBEXClient with something like
this:
>>> import lightblue
>>> client = lightblue.obex.OBEXClient(address, channel)
>>> client.connect()
>>> putresponse = client.put({"name": "MyFile.txt"}, file("MyFile.txt", 'rb'))
>>> client.disconnect()
>>> if putresponse.code != lightblue.obex.OK:
... raise lightblue.obex.OBEXError("server denied the Put request")
>>>
""",
"recvfile":
"""
Receives a file through an OBEX service.
Arguments:
- sock: the server socket on which the file is to be received. Note
this socket must *not* be listening. Also, an OBEX service should
have been advertised on this socket.
- dest: a filename or file-like object, to which the received data will
be written. If a filename is given, any existing file will be
overwritten. If a file object is given, it must be opened for writing.
For example, to receive a file and save it as "MyFile.txt":
>>> from lightblue import *
>>> s = socket()
>>> s.bind(("", 0))
>>> advertise("My OBEX Service", s, OBEX)
>>> obex.recvfile(s, "MyFile.txt")
"""
}
# import implementation modules
from ._obex import *
from ._obexcommon import *
from . import _obex
from . import _obexcommon
__all__ = _obex.__all__ + _obexcommon.__all__
# set docstrings
localattrs = locals()
for attr in _obex.__all__:
try:
localattrs[attr].__doc__ = _docstrings[attr]
except KeyError:
pass
del attr, localattrs
pybluez-0.23/msbt/ 0000775 0000000 0000000 00000000000 13601523637 0014103 5 ustar 00root root 0000000 0000000 pybluez-0.23/msbt/_msbt.c 0000664 0000000 0000000 00000074123 13601523637 0015362 0 ustar 00root root 0000000 0000000 #ifndef UNICODE
#define UNICODE
#endif
#include
#include
#include
#include
#include
#include
#include
#if 1
static void dbg(const char *fmt, ...)
{
}
#else
static void dbg(const char *fmt, ...)
{
va_list ap;
va_start (ap, fmt);
vprintf (fmt, ap);
va_end (ap);
}
#endif
static void Err_SetFromWSALastError(PyObject *exc)
{
LPVOID lpMsgBuf;
FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, WSAGetLastError(), 0, (LPTSTR) &lpMsgBuf, 0, NULL );
PyErr_SetString( exc, lpMsgBuf );
LocalFree(lpMsgBuf);
}
#define _CHECK_OR_RAISE_WSA(cond) \
if( !(cond) ) { Err_SetFromWSALastError( PyExc_IOError ); return 0; }
static void
ba2str( BTH_ADDR ba, char *addr, size_t len )
{
int i;
unsigned char bytes[6];
for( i=0; i<6; i++ ) {
bytes[5-i] = (unsigned char) ((ba >> (i*8)) & 0xff);
}
sprintf_s( addr, len, "%02X:%02X:%02X:%02X:%02X:%02X",
bytes[0], bytes[1], bytes[2], bytes[3], bytes[4], bytes[5] );
}
static PyObject *
msbt_initwinsock(PyObject *self)
{
WORD wVersionRequested;
WSADATA wsaData;
int status;
wVersionRequested = MAKEWORD( 2, 0 );
status = WSAStartup( wVersionRequested, &wsaData );
if( 0 != status ) {
Err_SetFromWSALastError( PyExc_RuntimeError );
return 0;
}
Py_RETURN_NONE;
}
PyDoc_STRVAR(msbt_initwinsock_doc, "TODO");
static void
dict_set_str_pyobj(PyObject *dict, const char *key, PyObject *valobj)
{
PyObject *keyobj;
keyobj = PyString_FromString( key );
PyDict_SetItem( dict, keyobj, valobj );
Py_DECREF( keyobj );
}
static void
dict_set_strings(PyObject *dict, const char *key, const char *val)
{
PyObject *keyobj, *valobj;
keyobj = PyString_FromString( key );
valobj = PyString_FromString( val );
PyDict_SetItem( dict, keyobj, valobj );
Py_DECREF( keyobj );
Py_DECREF( valobj );
}
static void
dict_set_str_long(PyObject *dict, const char *key, long val)
{
PyObject *keyobj, *valobj;
keyobj = PyString_FromString( key );
valobj = PyInt_FromLong(val);
PyDict_SetItem( dict, keyobj, valobj );
Py_DECREF( keyobj );
Py_DECREF( valobj );
}
static int
str2uuid( const char *uuid_str, GUID *uuid)
{
// Parse uuid128 standard format: 12345678-9012-3456-7890-123456789012
int i;
char buf[20] = { 0 };
strncpy_s(buf, _countof(buf), uuid_str, 8);
uuid->Data1 = strtoul( buf, NULL, 16 );
memset(buf, 0, sizeof(buf));
strncpy_s(buf, _countof(buf), uuid_str+9, 4);
uuid->Data2 = (unsigned short) strtoul( buf, NULL, 16 );
memset(buf, 0, sizeof(buf));
strncpy_s(buf, _countof(buf), uuid_str+14, 4);
uuid->Data3 = (unsigned short) strtoul( buf, NULL, 16 );
memset(buf, 0, sizeof(buf));
strncpy_s(buf, _countof(buf), uuid_str+19, 4);
strncpy_s(buf+4, _countof(buf)-4, uuid_str+24, 12);
for( i=0; i<8; i++ ) {
char buf2[3] = { buf[2*i], buf[2*i+1], 0 };
uuid->Data4[i] = (unsigned char)strtoul( buf2, NULL, 16 );
}
return 0;
}
// ====================== SOCKET FUNCTIONS ========================
static PyObject *
msbt_socket(PyObject *self, PyObject *args)
{
int family = AF_BTH;
int type;
int proto;
int sockfd = -1;
if(!PyArg_ParseTuple(args, "ii", &type, &proto)) return 0;
Py_BEGIN_ALLOW_THREADS;
sockfd = socket( AF_BTH, type, proto );
Py_END_ALLOW_THREADS;
_CHECK_OR_RAISE_WSA( SOCKET_ERROR != sockfd );
return PyInt_FromLong( sockfd );
};
PyDoc_STRVAR(msbt_socket_doc, "TODO");
static PyObject *
msbt_bind(PyObject *self, PyObject *args)
{
wchar_t *addrstr = NULL;
int addrstrlen = -1;
int sockfd = -1;
int port = -1;
char buf[100] = { 0 };
int buf_len = sizeof( buf );
int status;
SOCKADDR_BTH sa = { 0 };
int sa_len = sizeof(sa);
if(!PyArg_ParseTuple(args, "is#i", &sockfd, &addrstr, &addrstrlen, &port))
return 0;
if( addrstrlen == 0 ) {
sa.btAddr = 0;
} else {
_CHECK_OR_RAISE_WSA( NO_ERROR == WSAStringToAddress( addrstr, \
AF_BTH, NULL, (LPSOCKADDR)&sa, &sa_len ) );
}
sa.addressFamily = AF_BTH;
sa.port = port;
Py_BEGIN_ALLOW_THREADS;
status = bind( sockfd, (LPSOCKADDR)&sa, sa_len );
Py_END_ALLOW_THREADS;
_CHECK_OR_RAISE_WSA( NO_ERROR == status );
Py_RETURN_NONE;
}
PyDoc_STRVAR(msbt_bind_doc, "TODO");
static PyObject *
msbt_listen(PyObject *self, PyObject *args)
{
int sockfd = -1;
int backlog = -1;
DWORD status;
if(!PyArg_ParseTuple(args, "ii", &sockfd, &backlog)) return 0;
Py_BEGIN_ALLOW_THREADS;
status = listen(sockfd, backlog);
Py_END_ALLOW_THREADS;
_CHECK_OR_RAISE_WSA( NO_ERROR == status );
Py_RETURN_NONE;
}
PyDoc_STRVAR(msbt_listen_doc, "TODO");
static PyObject *
msbt_accept(PyObject *self, PyObject *args)
{
int sockfd = -1;
int clientfd = -1;
SOCKADDR_BTH ca = { 0 };
int ca_len = sizeof(ca);
PyObject *result = NULL;
char buf[100] = { 0 };
int buf_len = sizeof(buf);
if(!PyArg_ParseTuple(args, "i", &sockfd)) return 0;
Py_BEGIN_ALLOW_THREADS;
clientfd = accept(sockfd, (LPSOCKADDR)&ca, &ca_len);
Py_END_ALLOW_THREADS;
_CHECK_OR_RAISE_WSA( SOCKET_ERROR != clientfd );
ba2str(ca.btAddr, buf, _countof(buf));
result = Py_BuildValue( "isi", clientfd, buf, ca.port );
return result;
};
PyDoc_STRVAR(msbt_accept_doc, "TODO");
static PyObject *
msbt_connect(PyObject *self, PyObject *args)
{
int sockfd = -1;
wchar_t *addrstr = NULL;
int port = -1;
SOCKADDR_BTH sa = { 0 };
int sa_len = sizeof(sa);
DWORD status;
if(!PyArg_ParseTuple(args, "isi", &sockfd, &addrstr, &port)) return 0;
if( SOCKET_ERROR == WSAStringToAddress( addrstr, AF_BTH, NULL,
(LPSOCKADDR)&sa, &sa_len ) ) {
Err_SetFromWSALastError(PyExc_IOError);
return 0;
}
sa.addressFamily = AF_BTH;
sa.port = port;
Py_BEGIN_ALLOW_THREADS;
status = connect(sockfd, (LPSOCKADDR)&sa, sizeof(sa));
Py_END_ALLOW_THREADS;
_CHECK_OR_RAISE_WSA( NO_ERROR == status );
Py_RETURN_NONE;
}
PyDoc_STRVAR(msbt_connect_doc, "TODO");
static PyObject *
msbt_send(PyObject *self, PyObject *args)
{
int sockfd = -1;
char *data = NULL;
int datalen = -1;
int flags = 0;
int sent = 0;
if(!PyArg_ParseTuple(args, "is#|i", &sockfd, &data, &datalen, &flags))
return 0;
Py_BEGIN_ALLOW_THREADS;
sent = send(sockfd, data, datalen, flags);
Py_END_ALLOW_THREADS;
_CHECK_OR_RAISE_WSA( SOCKET_ERROR != sent );
return PyInt_FromLong( sent );
};
PyDoc_STRVAR(msbt_send_doc, "TODO");
static PyObject *
msbt_recv(PyObject *self, PyObject *args)
{
int sockfd = -1;
PyObject *buf = NULL;
int datalen = -1;
int flags = 0;
int received = 0;
if(!PyArg_ParseTuple(args, "ii|i", &sockfd, &datalen, &flags))
return 0;
buf = PyString_FromStringAndSize((char*)0, datalen);
Py_BEGIN_ALLOW_THREADS;
received = recv(sockfd, PyString_AS_STRING(buf), datalen, flags);
Py_END_ALLOW_THREADS;
if( SOCKET_ERROR == received ){
Py_DECREF(buf);
}
_CHECK_OR_RAISE_WSA( SOCKET_ERROR != received );
if( received != datalen ) _PyString_Resize(&buf, received);
return buf;
};
PyDoc_STRVAR(msbt_recv_doc, "TODO");
static PyObject *
msbt_close(PyObject *self, PyObject *args)
{
int sockfd = -1;
int status;
if(!PyArg_ParseTuple( args, "i", &sockfd )) return 0;
Py_BEGIN_ALLOW_THREADS;
status = closesocket(sockfd);
Py_END_ALLOW_THREADS;
Py_RETURN_NONE;
}
PyDoc_STRVAR(msbt_close_doc, "TODO");
static PyObject *
msbt_getpeername(PyObject *self, PyObject *args)
{
int sockfd = -1;
SOCKADDR_BTH sa = { 0 };
int sa_len = sizeof(sa);
char buf[18] = { 0 };
int buf_len = sizeof(buf);
int status;
if(!PyArg_ParseTuple( args, "i", &sockfd )) return 0;
sa.addressFamily = AF_BTH;
Py_BEGIN_ALLOW_THREADS;
status = getpeername( sockfd, (LPSOCKADDR)&sa, &sa_len );
Py_END_ALLOW_THREADS;
_CHECK_OR_RAISE_WSA( NO_ERROR == status );
ba2str( sa.btAddr, buf, buf_len );
return Py_BuildValue( "si", buf, sa.port );
};
PyDoc_STRVAR(msbt_getpeername_doc,
"getpeername() -> address info\n\
\n\
Return the address of the peer to which a socket is connected.\n\
This function works with any address family and it simply returns the \n\
address to which the socket is connected. The getpeername function can be \n\
used only on a connected socket.\n\
For datagram sockets, only the address of a peer specified in a previous \n\
connect call will be returned. Any address specified by a previous sendto \n\
call will not be returned by getpeername.");
static PyObject *
msbt_getsockname(PyObject *self, PyObject *args)
{
int sockfd = -1;
SOCKADDR_BTH sa = { 0 };
int sa_len = sizeof(sa);
char buf[18] = { 0 };
int buf_len = sizeof(buf);
int status;
if(!PyArg_ParseTuple( args, "i", &sockfd )) return 0;
sa.addressFamily = AF_BTH;
Py_BEGIN_ALLOW_THREADS;
status = getsockname( sockfd, (LPSOCKADDR)&sa, &sa_len );
Py_END_ALLOW_THREADS;
_CHECK_OR_RAISE_WSA( NO_ERROR == status );
ba2str( sa.btAddr, buf, buf_len );
return Py_BuildValue( "si", buf, sa.port );
};
PyDoc_STRVAR(msbt_getsockname_doc, "TODO");
static PyObject *
msbt_dup(PyObject *self, PyObject *args)
{
int sockfd = -1;
int newsockfd = -1;
int status;
DWORD pid;
WSAPROTOCOL_INFO pi = { 0 };
if(!PyArg_ParseTuple( args, "i", &sockfd )) return 0;
// prepare to duplicate
pid = GetCurrentProcessId();
status = WSADuplicateSocket( sockfd, pid, &pi );
_CHECK_OR_RAISE_WSA( NO_ERROR == status );
// duplicate!
newsockfd = WSASocket( FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO,
FROM_PROTOCOL_INFO,
&pi, 0, 0 );
_CHECK_OR_RAISE_WSA( INVALID_SOCKET != newsockfd );
return PyInt_FromLong( newsockfd );
}
PyDoc_STRVAR(msbt_dup_doc, "TODO");
// ====================
static int bt_adapter_present()
{
int hwactive = 1;
SOCKADDR_BTH sa = { 0 };
int s = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
sa.addressFamily = AF_BTH;
sa.port = BT_PORT_ANY;
if (s == INVALID_SOCKET)
{
closesocket(s);
return 0;
}
if (SOCKET_ERROR == bind(s, (LPSOCKADDR)&sa, sizeof(sa)))
{
hwactive = 0;
}
closesocket(s);
return hwactive;
}
static PyObject *
msbt_discover_devices(PyObject *self, PyObject *args, PyObject *kwds)
{
BLUETOOTH_DEVICE_INFO device_info;
BLUETOOTH_DEVICE_SEARCH_PARAMS search_criteria;
HBLUETOOTH_DEVICE_FIND found_device;
BOOL next = TRUE;
PyObject * toreturn = NULL;
int duration = 8;
int flush_cache = 1;
static char *keywords[] = {"duration", "flush_cache", 0};
if(!PyArg_ParseTupleAndKeywords(args, kwds, "ii", keywords,
&duration, &flush_cache)) {
return NULL;
}
toreturn = PyList_New(0);
ZeroMemory(&device_info, sizeof(BLUETOOTH_DEVICE_INFO));
ZeroMemory(&search_criteria, sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS));
device_info.dwSize = sizeof(BLUETOOTH_DEVICE_INFO);
search_criteria.dwSize = sizeof(BLUETOOTH_DEVICE_SEARCH_PARAMS);
search_criteria.fReturnAuthenticated = TRUE;
search_criteria.fReturnRemembered = !flush_cache;
search_criteria.fReturnConnected = TRUE;
search_criteria.fReturnUnknown = TRUE;
search_criteria.fIssueInquiry = TRUE;
search_criteria.cTimeoutMultiplier = duration;
search_criteria.hRadio = NULL;
Py_BEGIN_ALLOW_THREADS;
found_device = BluetoothFindFirstDevice(&search_criteria, &device_info);
Py_END_ALLOW_THREADS;
_CHECK_OR_RAISE_WSA(found_device != NULL)
while(next) {
PyObject *tup = NULL;
PyObject *item_tuple = NULL;
char buf[40] = {0};
BTH_ADDR result = device_info.Address.ullLong;
ba2str( result, buf, _countof(buf) );
tup = PyTuple_New(3);
item_tuple = PyString_FromString(buf);
PyTuple_SetItem( tup, 0, item_tuple );
item_tuple = PyUnicode_FromUnicode(
(const Py_UNICODE*)device_info.szName,
wcslen(device_info.szName));
PyTuple_SetItem( tup, 1, item_tuple );
item_tuple = PyInt_FromLong(device_info.ulClassofDevice);
PyTuple_SetItem( tup, 2, item_tuple );
PyList_Append( toreturn, tup );
Py_DECREF( tup );
Py_BEGIN_ALLOW_THREADS;
next = BluetoothFindNextDevice(found_device, &device_info);
Py_END_ALLOW_THREADS;
}
return toreturn;
}
PyDoc_STRVAR(msbt_discover_devices_doc,
"msbt_discover_devices(duration=8, flush_cache=True\n\\n\
Performs a device inquiry. The inquiry will last 1.28 * duration seconds.\
If flush_cache is True, then new inquiry will be performed,\
else cashed devices will be returned(plus paired devices).)");
static PyObject *
msbt_list_local(PyObject *self)
{
HANDLE m_radio = NULL;
HBLUETOOTH_RADIO_FIND m_bt = NULL;
BOOL next = TRUE;
BLUETOOTH_FIND_RADIO_PARAMS
find_radio = {sizeof(BLUETOOTH_FIND_RADIO_PARAMS)};
PyObject * toreturn = PyList_New(0);
Py_BEGIN_ALLOW_THREADS;
m_bt = BluetoothFindFirstRadio(&find_radio, &m_radio);
Py_END_ALLOW_THREADS;
_CHECK_OR_RAISE_WSA(m_bt != NULL);
while(next) {
PyObject *item = NULL;
char buf[40] = {0};
BLUETOOTH_RADIO_INFO m_bt_info = {sizeof(BLUETOOTH_RADIO_INFO), 0,};
// Then get the radio device info....
DWORD mbtinfo_ret = BluetoothGetRadioInfo(m_radio, &m_bt_info);
_CHECK_OR_RAISE_WSA(mbtinfo_ret == ERROR_SUCCESS);
ba2str(m_bt_info.address.ullLong, buf, _countof(buf));
item = PyString_FromString(buf);
PyList_Append(toreturn, item);
Py_DECREF(item);
next = BluetoothFindNextRadio(&find_radio, &m_radio);
}
// No more radio, close the radio handle
_CHECK_OR_RAISE_WSA(BluetoothFindRadioClose(m_bt) == TRUE);
return toreturn;
}
PyDoc_STRVAR(msbt_list_local_doc,
"msbt_list_local - List local BT adapters addresses");
static PyObject *
msbt_lookup_name(PyObject *self, PyObject *args)
{
HANDLE rhandle = NULL;
BLUETOOTH_FIND_RADIO_PARAMS p = { sizeof(p) };
HBLUETOOTH_RADIO_FIND fhandle = NULL;
BLUETOOTH_DEVICE_INFO dinfo = { 0 };
wchar_t *addrstr = NULL;
SOCKADDR_BTH sa = { 0 };
int sa_len = sizeof(sa);
DWORD status;
if(!PyArg_ParseTuple(args,"s",&addrstr)) return 0;
_CHECK_OR_RAISE_WSA( NO_ERROR == WSAStringToAddress( addrstr, \
AF_BTH, NULL, (LPSOCKADDR)&sa, &sa_len ) );
// printf("looking for first radio\n");
fhandle = BluetoothFindFirstRadio(&p, &rhandle);
_CHECK_OR_RAISE_WSA( NULL != fhandle );
// printf("found radio 0x%p\n", rhandle );
dinfo.dwSize = sizeof( dinfo );
dinfo.Address.ullLong = sa.btAddr;
status = BluetoothGetDeviceInfo( rhandle, &dinfo );
_CHECK_OR_RAISE_WSA( status == ERROR_SUCCESS );
// printf("name: %s\n", dinfo.szName );
_CHECK_OR_RAISE_WSA( TRUE == BluetoothFindRadioClose( fhandle ) );
return PyUnicode_FromWideChar( dinfo.szName, wcslen( dinfo.szName ) );
}
PyDoc_STRVAR(msbt_lookup_name_doc, "TODO");
// ======================= SDP FUNCTIONS ======================
static PyObject *
msbt_find_service(PyObject *self, PyObject *args)
{
char *addrstr = NULL;
char *uuidstr = NULL;
// inquiry data structure
DWORD qs_len = sizeof( WSAQUERYSET );
WSAQUERYSET *qs = (WSAQUERYSET*) malloc( qs_len );
DWORD flags = LUP_FLUSHCACHE | LUP_RETURN_ALL;
HANDLE h;
int done = 0;
int status = 0;
PyObject *record = NULL;
PyObject *toreturn = NULL;
GUID uuid = { 0 };
char localAddressBuf[20] = { 0 };
if(!PyArg_ParseTuple(args,"ss", &addrstr, &uuidstr))
return 0;
ZeroMemory( qs, qs_len );
qs->dwSize = sizeof(WSAQUERYSET);
qs->dwNameSpace = NS_BTH;
qs->dwNumberOfCsAddrs = 0;
qs->lpszContext = (LPWSTR) localAddressBuf;
if( 0 == strcmp( addrstr, "localhost" ) ) {
// find the Bluetooth address of the first local adapter.
#if 0
HANDLE rhandle = NULL;
BLUETOOTH_RADIO_INFO info;
BLUETOOTH_FIND_RADIO_PARAMS p = { sizeof(p) };
HBLUETOOTH_RADIO_FIND fhandle = NULL;
printf("looking for first radio\n");
fhandle = BluetoothFindFirstRadio(&p, &rhandle);
_CHECK_OR_RAISE_WSA( NULL != fhandle );
printf("first radio: 0x%p\n", rhandle);
_CHECK_OR_RAISE_WSA( \
TRUE == BluetoothFindRadioClose( fhandle ) );
printf("retrieving radio info on handle 0x%p\n", rhandle);
info.dwSize = sizeof(info);
// XXX why doesn't this work???
_CHECK_OR_RAISE_WSA( \
ERROR_SUCCESS != BluetoothGetRadioInfo( rhandle, &info ) );
ba2str( info.address.ullLong, localAddressBuf, _countof(localAddressBuf) );
#else
// bind a temporary socket and get its Bluetooth address
SOCKADDR_BTH sa = { 0 };
int sa_len = sizeof(sa);
int tmpfd = socket(AF_BTH, SOCK_STREAM, BTHPROTO_RFCOMM);
_CHECK_OR_RAISE_WSA( tmpfd >= 0 );
sa.addressFamily = AF_BTH;
sa.port = BT_PORT_ANY;
_CHECK_OR_RAISE_WSA(NO_ERROR == bind(tmpfd,(LPSOCKADDR)&sa,sa_len) );
_CHECK_OR_RAISE_WSA(NO_ERROR == getsockname(tmpfd, (LPSOCKADDR)&sa,\
&sa_len ) );
ba2str(sa.btAddr, localAddressBuf, _countof(localAddressBuf) );
_close(tmpfd);
#endif
flags |= LUP_RES_SERVICE;
} else {
strcpy_s(localAddressBuf, _countof(localAddressBuf), addrstr);
}
if( strlen(uuidstr) != 36 || uuidstr[8] != '-' || uuidstr[13] != '-'
|| uuidstr[18] != '-' || uuidstr[23] != '-' ) {
PyErr_SetString( PyExc_ValueError, "Invalid UUID!");
return 0;
}
str2uuid( uuidstr, &uuid );
qs->lpServiceClassId = &uuid;
Py_BEGIN_ALLOW_THREADS;
status = WSALookupServiceBegin( qs, flags, &h );
Py_END_ALLOW_THREADS;
if( SOCKET_ERROR == status) {
int err_code = WSAGetLastError();
if( WSASERVICE_NOT_FOUND == err_code ) {
// this device does not advertise any services. return an
// empty list
free( qs );
return PyList_New(0);
} else {
// unexpected error. raise an exception
Err_SetFromWSALastError( PyExc_IOError );
free(qs);
return 0;
}
}
toreturn = PyList_New(0);
// iterate through the inquiry results
while(! done) {
Py_BEGIN_ALLOW_THREADS;
status = WSALookupServiceNext( h, flags, &qs_len, qs );
Py_END_ALLOW_THREADS;
if (NO_ERROR == status) {
int proto;
int port;
PyObject *rawrecord = NULL;
CSADDR_INFO *csinfo = NULL;
record = PyDict_New();
// set host name
dict_set_strings( record, "host", localAddressBuf );
// set service name
dict_set_strings( record, "name", (const char*) qs->lpszServiceInstanceName );
// set description
dict_set_strings( record, "description", (const char*) qs->lpszComment );
// set protocol and port
csinfo = qs->lpcsaBuffer;
if( csinfo != NULL ) {
proto = csinfo->iProtocol;
port = ((SOCKADDR_BTH*)csinfo->RemoteAddr.lpSockaddr)->port;
dict_set_str_long(record, "port", port);
if( proto == BTHPROTO_RFCOMM ) {
dict_set_strings(record, "protocol", "RFCOMM");
} else if( proto == BTHPROTO_L2CAP ) {
dict_set_strings(record, "protocol", "L2CAP");
} else {
dict_set_strings(record, "protocol", "UNKNOWN");
dict_set_str_pyobj(record, "port", Py_None);
}
} else {
dict_set_str_pyobj(record, "port", Py_None);
dict_set_strings(record, "protocol", "UNKNOWN");
}
// add the raw service record to be parsed in python
rawrecord = PyString_FromStringAndSize( qs->lpBlob->pBlobData,
qs->lpBlob->cbSize );
dict_set_str_pyobj(record, "rawrecord", rawrecord);
Py_DECREF(rawrecord);
PyList_Append( toreturn, record );
Py_DECREF( record );
} else {
int error = WSAGetLastError();
if( error == WSAEFAULT ) {
// the qs data structure is too small. allocate a bigger
// buffer and try again.
free( qs );
qs = (WSAQUERYSET*) malloc( qs_len );
} else if( error == WSA_E_NO_MORE ) {
// no more results.
done = 1;
} else {
// unexpected error. raise an exception.
Err_SetFromWSALastError( PyExc_IOError );
Py_DECREF( toreturn );
return 0;
}
}
}
Py_BEGIN_ALLOW_THREADS;
WSALookupServiceEnd( h );
Py_END_ALLOW_THREADS;
free( qs );
return toreturn;
}
PyDoc_STRVAR(msbt_find_service_doc, "TODO");
static PyObject *
msbt_set_service_raw(PyObject *self, PyObject *args)
{
int advertise = 0;
WSAQUERYSET qs = { 0 };
WSAESETSERVICEOP op;
char *record = NULL;
int reclen = -1;
BTH_SET_SERVICE *si = NULL;
int silen = -1;
ULONG sdpVersion = BTH_SDP_VERSION;
BLOB blob = { 0 };
int status = -1;
PyObject *result = NULL;
HANDLE rh = 0;
if(!PyArg_ParseTuple(args, "s#i|i", &record, &reclen, &advertise, &rh))
return 0;
silen = sizeof(BTH_SET_SERVICE) + reclen - 1;
si = (BTH_SET_SERVICE*) malloc(silen);
ZeroMemory( si, silen );
si->pSdpVersion = &sdpVersion;
si->pRecordHandle = &rh;
si->fCodService = 0;
si->Reserved;
si->ulRecordLength = reclen;
memcpy( si->pRecord, record, reclen );
op = advertise ? RNRSERVICE_REGISTER : RNRSERVICE_DELETE;
qs.dwSize = sizeof(qs);
qs.lpBlob = &blob;
qs.dwNameSpace = NS_BTH;
blob.cbSize = silen;
blob.pBlobData = (BYTE*)si;
status = WSASetService( &qs, op, 0 );
free( si );
if( SOCKET_ERROR == status ) {
Err_SetFromWSALastError( PyExc_IOError );
return 0;
}
return PyInt_FromLong( (unsigned long) rh );
}
PyDoc_STRVAR(msbt_set_service_raw_doc, "");
static PyObject *
msbt_set_service(PyObject *self, PyObject *args)
{
int advertise = 0;
WSAQUERYSET qs = { 0 };
WSAESETSERVICEOP op;
SOCKADDR_BTH sa = { 0 };
int sa_len = sizeof(sa);
wchar_t *service_name = NULL;
wchar_t *service_desc = NULL;
char *service_class_id_str = NULL;
CSADDR_INFO sockInfo = { 0 };
GUID uuid = { 0 };
int sockfd;
if(!PyArg_ParseTuple(args, "iisss", &sockfd, &advertise, &service_name,
&service_desc, &service_class_id_str))
return 0;
op = advertise ? RNRSERVICE_REGISTER : RNRSERVICE_DELETE;
if( SOCKET_ERROR == getsockname( sockfd, (SOCKADDR*) &sa, &sa_len ) ) {
Err_SetFromWSALastError( PyExc_IOError );
return 0;
}
sockInfo.iProtocol = BTHPROTO_RFCOMM;
sockInfo.iSocketType = SOCK_STREAM;
sockInfo.LocalAddr.lpSockaddr = (LPSOCKADDR) &sa;
sockInfo.LocalAddr.iSockaddrLength = sizeof(sa);
sockInfo.RemoteAddr.lpSockaddr = (LPSOCKADDR) &sa;
sockInfo.RemoteAddr.iSockaddrLength = sizeof(sa);
qs.dwSize = sizeof(qs);
qs.dwNameSpace = NS_BTH;
qs.lpcsaBuffer = &sockInfo;
qs.lpszServiceInstanceName = service_name;
qs.lpszComment = service_desc;
str2uuid( service_class_id_str, &uuid );
qs.lpServiceClassId = (LPGUID) &uuid;
qs.dwNumberOfCsAddrs = 1;
if( SOCKET_ERROR == WSASetService( &qs, op, 0 ) ) {
Err_SetFromWSALastError( PyExc_IOError );
return 0;
}
Py_RETURN_NONE;
}
PyDoc_STRVAR(msbt_set_service_doc, "");
static PyObject *
msbt_setblocking(PyObject *self, PyObject *args)
{
int sockfd = -1;
int block = -1;
if(!PyArg_ParseTuple(args, "ii", &sockfd, &block)) return 0;
block = !block; //set zero to non-zero and non-zero to zero
ioctlsocket( sockfd, FIONBIO, &block);
Py_RETURN_NONE;
}
PyDoc_STRVAR(msbt_setblocking_doc, "");
static PyObject *
msbt_settimeout(PyObject *self, PyObject *args)
{
int sockfd = -1;
double secondTimeout = -1;
DWORD timeout = -1;
int timeoutLen = sizeof(DWORD);
if(!PyArg_ParseTuple(args, "id", &sockfd, &secondTimeout)) return 0;
timeout = (DWORD) (secondTimeout * 1000);
if(setsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char*)&timeout,
timeoutLen) != 0) {
Err_SetFromWSALastError( PyExc_IOError );
return 0;
}
if(setsockopt(sockfd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout,
timeoutLen) != 0) {
Err_SetFromWSALastError( PyExc_IOError );
return 0;
}
Py_RETURN_NONE;
}
PyDoc_STRVAR(msbt_settimeout_doc, "");
static PyObject *
msbt_gettimeout(PyObject *self, PyObject *args)
{
int sockfd = -1;
DWORD recv_timeout = -1;
int recv_timeoutLen = sizeof(DWORD);
double timeout = -1;
if(!PyArg_ParseTuple(args, "i", &sockfd)) return 0;
if(getsockopt(sockfd, SOL_SOCKET, SO_RCVTIMEO, (char*)&recv_timeout,
&recv_timeoutLen) != 0) {
Err_SetFromWSALastError( PyExc_IOError );
return 0;
}
timeout = (double)recv_timeout / 1000;
return PyFloat_FromDouble(timeout);
}
PyDoc_STRVAR(msbt_gettimeout_doc, "");
/* s.setsockopt() method.
With an integer third argument, sets an integer option.
With a string third argument, sets an option from a buffer;
use optional built-in module 'struct' to encode the string. */
static PyObject *
msbt_setsockopt(PyObject *s, PyObject *args)
{
int sockfd = -1;
int level;
ULONG optname;
int res;
ULONG flag;
if (!PyArg_ParseTuple(args, "iiIi:setsockopt", &sockfd, &level, &optname,
&flag)) {
return 0;
}
res = setsockopt(sockfd, level, optname, (char*) &flag, sizeof(ULONG));
if (res < 0) {
Err_SetFromWSALastError(PyExc_IOError);
return 0;
}
Py_RETURN_NONE;
}
PyDoc_STRVAR(msbt_setsockopt_doc,
"setsockopt(level, option, value)\n\
\n\
Set a socket option. See the Unix manual for level and option.\n\
The value argument can either be an integer or a string.");
/* s.getsockopt() method.
With two arguments, retrieves an integer option.
With a third integer argument, retrieves a string buffer of that size;
use optional built-in module 'struct' to decode the string. */
static PyObject *
msbt_getsockopt(PyObject *s, PyObject *args)
{
int sockfd = -1;
int level;
ULONG optname;
int res;
ULONG flag;
int flagsize = sizeof flag;
if (!PyArg_ParseTuple(args, "iiI", &sockfd, &level, &optname))
return 0;
res = getsockopt(sockfd, level, optname, (void *) &flag, &flagsize);
if (res < 0) {
Err_SetFromWSALastError(PyExc_IOError);
return 0;
}
return PyInt_FromLong(flag);
}
PyDoc_STRVAR(msbt_getsockopt_doc,
"getsockopt(level, option[, buffersize]) -> value\n\
\n\
Get a socket option. See the Unix manual for level and option.\n\
If a nonzero buffersize argument is given, the return value is a\n\
string of that length; otherwise it is an integer.");
// ======================= ADMINISTRATIVE =========================
static PyMethodDef msbt_methods[] = {
{ "initwinsock", (PyCFunction)msbt_initwinsock, METH_NOARGS,
msbt_initwinsock_doc },
{ "socket", (PyCFunction)msbt_socket, METH_VARARGS, msbt_socket_doc },
{ "bind", (PyCFunction)msbt_bind, METH_VARARGS, msbt_bind_doc },
{ "listen", (PyCFunction)msbt_listen, METH_VARARGS, msbt_listen_doc },
{ "accept", (PyCFunction)msbt_accept, METH_VARARGS, msbt_accept_doc },
{ "connect", (PyCFunction)msbt_connect, METH_VARARGS, msbt_connect_doc },
{ "send", (PyCFunction)msbt_send, METH_VARARGS, msbt_send_doc },
{ "recv", (PyCFunction)msbt_recv, METH_VARARGS, msbt_recv_doc },
{ "close", (PyCFunction)msbt_close, METH_VARARGS, msbt_close_doc },
{ "getsockname", (PyCFunction)msbt_getsockname, METH_VARARGS,
msbt_getsockname_doc },
{ "getpeername", (PyCFunction)msbt_getpeername, METH_VARARGS,
msbt_getpeername_doc },
{ "dup", (PyCFunction)msbt_dup, METH_VARARGS, msbt_dup_doc },
{ "discover_devices", (PyCFunction)msbt_discover_devices,
METH_VARARGS | METH_KEYWORDS, msbt_discover_devices_doc },
{ "list_local", (PyCFunction)msbt_list_local,
METH_NOARGS, msbt_list_local_doc },
{ "lookup_name", (PyCFunction)msbt_lookup_name, METH_VARARGS, msbt_lookup_name_doc },
{ "find_service", (PyCFunction)msbt_find_service, METH_VARARGS, msbt_find_service_doc },
{ "set_service", (PyCFunction)msbt_set_service, METH_VARARGS, msbt_set_service_doc },
{ "set_service_raw", (PyCFunction)msbt_set_service_raw, METH_VARARGS, msbt_set_service_raw_doc },
{ "setblocking", (PyCFunction)msbt_setblocking, METH_VARARGS, msbt_setblocking_doc },
{ "settimeout", (PyCFunction)msbt_settimeout, METH_VARARGS, msbt_settimeout_doc },
{ "gettimeout", (PyCFunction)msbt_gettimeout, METH_VARARGS, msbt_gettimeout_doc },
{ "setsockopt", (PyCFunction)msbt_setsockopt, METH_VARARGS, msbt_setsockopt_doc },
{ "getsockopt", (PyCFunction)msbt_getsockopt, METH_VARARGS, msbt_getsockopt_doc },
{ NULL, NULL }
};
PyDoc_STRVAR(msbt_doc, "TODO\n");
#define ADD_INT_CONSTANT(m,a) PyModule_AddIntConstant(m, #a, a)
#if PY_MAJOR_VERSION < 3
PyMODINIT_FUNC
init_msbt(void)
{
PyObject * m = Py_InitModule3("_msbt", msbt_methods, msbt_doc);
#else
PyMODINIT_FUNC
PyInit__msbt(void)
{
PyObject *m;
static struct PyModuleDef moduledef = {
PyModuleDef_HEAD_INIT,
"_msbt",
NULL,
-1,
msbt_methods,
NULL,
NULL,
NULL,
NULL
};
m = PyModule_Create(&moduledef);
#endif
ADD_INT_CONSTANT(m, AF_BTH);
ADD_INT_CONSTANT(m, SOCK_STREAM);
ADD_INT_CONSTANT(m, BTHPROTO_RFCOMM);
ADD_INT_CONSTANT(m, BT_PORT_ANY);
ADD_INT_CONSTANT(m, SOL_RFCOMM);
ADD_INT_CONSTANT(m, SO_BTH_AUTHENTICATE);
ADD_INT_CONSTANT(m, SO_BTH_ENCRYPT);
ADD_INT_CONSTANT(m, SO_BTH_MTU);
ADD_INT_CONSTANT(m, SO_BTH_MTU_MAX);
ADD_INT_CONSTANT(m, SO_BTH_MTU_MIN);
#if PY_MAJOR_VERSION >= 3
return m;
#endif
}
pybluez-0.23/port3/ 0000775 0000000 0000000 00000000000 13601523637 0014205 5 ustar 00root root 0000000 0000000 pybluez-0.23/port3/port3.h 0000664 0000000 0000000 00000001147 13601523637 0015430 0 ustar 00root root 0000000 0000000
#if PY_MAJOR_VERSION >= 3
#define PyInt_FromLong PyLong_FromLong
#define PyString_FromString PyUnicode_FromString
#define PyString_FromStringAndSize PyBytes_FromStringAndSize
#define _PyString_Resize _PyBytes_Resize
#define PyString_AS_STRING PyBytes_AS_STRING
#define PyInt_AsLong PyLong_AsLong
#define PyString_AsString PyBytes_AsString
#define PyInt_Check PyLong_Check
#define PyInt_AS_LONG PyLong_AS_LONG
#define BYTES_FORMAT_CHR "y#"
#else
#ifndef Py_TYPE
#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
#endif
#define BYTES_FORMAT_CHR "s#"
#endif
pybluez-0.23/release_checklist 0000664 0000000 0000000 00000000471 13601523637 0016534 0 ustar 00root root 0000000 0000000 1. update CHANGELOG
2. bump version number in setup.py and in __init__.py
3. check out a clean copy of the repository
git clone https://github.com/pybluez/pybluez.git
3. run python setup.py sdist
4. test installer
5. tag git repo with new release X.XX
6. upload release to https://pypi.python.org/pypi/PyBluez
pybluez-0.23/setup.py 0000775 0000000 0000000 00000011741 13601523637 0014657 0 ustar 00root root 0000000 0000000 #!/usr/bin/env python
import os
import platform
import sys
from setuptools import setup, Extension
# This marks the wheel as always being platform-specific and not pure Python
# See: https://stackoverflow.com/q/45150304/145504
try:
from wheel.bdist_wheel import bdist_wheel as _bdist_wheel
class impure_bdist_wheel(_bdist_wheel):
def finalize_options(self):
_bdist_wheel.finalize_options(self)
self.root_is_pure = False
except ImportError:
# If the wheel module isn't available, no problem -- we're not doing a
# bdist_wheel in that case anyway.
impure_bdist_wheel = None
packages = ['bluetooth']
package_dir = dict()
ext_modules = list()
install_requires = list()
package_data = dict()
eager_resources = list()
zip_safe = True
if sys.platform == 'win32':
ext_modules.append(Extension('bluetooth._msbt',
include_dirs=[".\\port3"],
libraries=["WS2_32", "Irprops"],
sources=['msbt\\_msbt.c']))
# widcomm
WC_BASE = os.path.join(os.getenv('ProgramFiles'), r"Widcomm\BTW DK\SDK")
if os.path.exists(WC_BASE):
ext_modules.append(Extension('bluetooth._widcomm',
include_dirs=["%s\\Inc" % WC_BASE, ".\\port3"],
define_macros=[('_BTWLIB', None)],
library_dirs=["%s\\Release" % WC_BASE],
libraries=["WidcommSdklib", "ws2_32", "version", "user32",
"Advapi32", "Winspool", "ole32", "oleaut32"],
sources=["widcomm\\_widcomm.cpp",
"widcomm\\inquirer.cpp",
"widcomm\\rfcommport.cpp",
"widcomm\\rfcommif.cpp",
"widcomm\\l2capconn.cpp",
"widcomm\\l2capif.cpp",
"widcomm\\sdpservice.cpp",
"widcomm\\util.cpp"]))
elif sys.platform.startswith('linux'):
mod1 = Extension('bluetooth._bluetooth',
include_dirs = ["./port3",],
libraries = ['bluetooth'],
#extra_compile_args=['-O0'],
sources = ['bluez/btmodule.c', 'bluez/btsdp.c'])
ext_modules.append(mod1)
elif sys.platform.startswith("darwin"):
packages.append('lightblue')
package_dir['lightblue'] = 'macos'
zip_safe = False
if sys.version_info >= (3,6):
install_requires += ['pyobjc-core>=6', 'pyobjc-framework-Cocoa>=6']
else:
install_requires += ['pyobjc-core>=3.1,<6', 'pyobjc-framework-Cocoa>=3.1,<6']
# FIXME: This is inelegant, how can we cover the cases?
build_cmds = set(['bdist', 'bdist_egg', 'bdist_wheel'])
if build_cmds & set(sys.argv):
# Build the framework into macos/
import subprocess
subprocess.check_call([
'xcodebuild', 'install',
'-project', 'macos/LightAquaBlue/LightAquaBlue.xcodeproj',
'-scheme', 'LightAquaBlue',
'DSTROOT=' + os.path.join(os.getcwd(), 'macos'),
'INSTALL_PATH=/',
'DEPLOYMENT_LOCATION=YES',
])
# We can't seem to list a directory as package_data, so we will
# recursively add all all files we find
package_data['lightblue'] = []
for path, _, files in os.walk('macos/LightAquaBlue.framework'):
for f in files:
include = os.path.join(path, f)[6:] # trim off macos/
package_data['lightblue'].append(include)
# This should allow us to use the framework from an egg [untested]
eager_resources.append('macos/LightAquaBlue.framework')
else:
raise Exception("This platform (%s) is currently not supported by pybluez."
% sys.platform)
setup(name='PyBluez',
version='0.23',
description='Bluetooth Python extension module',
author="Albert Huang",
author_email="ashuang@alum.mit.edu",
url="http://pybluez.github.io/",
ext_modules=ext_modules,
packages=packages,
# for the python cheese shop
classifiers=['Development Status :: 4 - Beta',
'License :: OSI Approved :: GNU General Public License (GPL)',
'Programming Language :: Python',
'Programming Language :: Python :: 2',
'Programming Language :: Python :: 3',
'Topic :: Communications'],
download_url='https://github.com/pybluez/pybluez',
long_description='Bluetooth Python extension module to allow Python '\
'developers to use system Bluetooth resources. PyBluez works '\
'with GNU/Linux, macOS, and Windows.',
maintainer='Piotr Karulis',
license='GPL',
extras_require={'ble': ['gattlib==0.20150805']},
package_dir=package_dir,
use_2to3=True,
install_requires=install_requires,
package_data=package_data,
eager_resources=eager_resources,
zip_safe=zip_safe,
cmdclass={'bdist_wheel': impure_bdist_wheel},
)
pybluez-0.23/widcomm/ 0000775 0000000 0000000 00000000000 13601523637 0014575 5 ustar 00root root 0000000 0000000 pybluez-0.23/widcomm/_widcomm.cpp 0000664 0000000 0000000 00000016613 13601523637 0017106 0 ustar 00root root 0000000 0000000 #include
#ifndef _BTWLIB
#error "_BTWLIB is not defined"
#endif
#include
#include
#include
#include
#include "inquirer.hpp"
#include "rfcommport.hpp"
#include "l2capconn.hpp"
extern PyTypeObject wcinquirer_type;
extern PyTypeObject wcrfcommport_type;
extern PyTypeObject wcrfcommif_type;
extern PyTypeObject wcl2capif_type;
extern PyTypeObject wcl2capconn_type;
extern PyTypeObject wcsdpservice_type;
static PyMethodDef widcomm_methods[] = {
{ NULL, NULL }
};
extern "C" {
#if PY_MAJOR_VERSION < 3
PyMODINIT_FUNC
init_widcomm(void)
{
PyObject *m;
wcinquirer_type.ob_type = &PyType_Type;
wcrfcommport_type.ob_type = &PyType_Type;
wcrfcommif_type.ob_type = &PyType_Type;
wcl2capif_type.ob_type = &PyType_Type;
wcl2capconn_type.ob_type = &PyType_Type;
wcsdpservice_type.ob_type = &PyType_Type;
m = Py_InitModule("_widcomm", widcomm_methods);
// inquirer
Py_INCREF((PyObject *)&wcinquirer_type);
if (PyModule_AddObject(m, "_WCInquirer",
(PyObject *)&wcinquirer_type) != 0) {
return;
}
// rfcomm port
Py_INCREF((PyObject *)&wcrfcommport_type);
if (PyModule_AddObject(m, "_WCRfCommPort",
(PyObject *)&wcrfcommport_type) != 0) {
return;
}
// rfcomm if
Py_INCREF((PyObject *)&wcrfcommif_type);
if (PyModule_AddObject(m, "_WCRfCommIf",
(PyObject *)&wcrfcommif_type) != 0) {
return;
}
// l2cap if
Py_INCREF((PyObject *)&wcl2capif_type);
if (PyModule_AddObject(m, "_WCL2CapIf",
(PyObject *)&wcl2capif_type) != 0) {
return;
}
// l2cap conn
Py_INCREF((PyObject *)&wcl2capconn_type);
if (PyModule_AddObject(m, "_WCL2CapConn",
(PyObject *)&wcl2capconn_type) != 0) {
return;
}
// sdp service advertisement
Py_INCREF((PyObject *)&wcsdpservice_type);
if (PyModule_AddObject(m, "_WCSdpService",
(PyObject *)&wcsdpservice_type) != 0) {
return;
}
#else
PyMODINIT_FUNC
PyInit__widcomm(void)
{
PyObject *m;
Py_TYPE(&wcinquirer_type) = &PyType_Type;
Py_TYPE(&wcrfcommport_type) = &PyType_Type;
Py_TYPE(&wcrfcommif_type) = &PyType_Type;
Py_TYPE(&wcl2capif_type) = &PyType_Type;
Py_TYPE(&wcl2capconn_type) = &PyType_Type;
Py_TYPE(&wcsdpservice_type) = &PyType_Type;
//m = Py_InitModule("_widcomm", widcomm_methods);
static struct PyModuleDef moduledef = {
PyModuleDef_HEAD_INIT,
"_widcomm",
NULL,
-1,
widcomm_methods,
NULL,
NULL,
NULL,
NULL
};
m = PyModule_Create(&moduledef);
// inquirer
Py_INCREF((PyObject *)&wcinquirer_type);
if (PyModule_AddObject(m, "_WCInquirer",
(PyObject *)&wcinquirer_type) != 0) {
return NULL;
}
// rfcomm port
Py_INCREF((PyObject *)&wcrfcommport_type);
if (PyModule_AddObject(m, "_WCRfCommPort",
(PyObject *)&wcrfcommport_type) != 0) {
return NULL;
}
// rfcomm if
Py_INCREF((PyObject *)&wcrfcommif_type);
if (PyModule_AddObject(m, "_WCRfCommIf",
(PyObject *)&wcrfcommif_type) != 0) {
return NULL;
}
// l2cap if
Py_INCREF((PyObject *)&wcl2capif_type);
if (PyModule_AddObject(m, "_WCL2CapIf",
(PyObject *)&wcl2capif_type) != 0) {
return NULL;
}
// l2cap conn
Py_INCREF((PyObject *)&wcl2capconn_type);
if (PyModule_AddObject(m, "_WCL2CapConn",
(PyObject *)&wcl2capconn_type) != 0) {
return NULL;
}
// sdp service advertisement
Py_INCREF((PyObject *)&wcsdpservice_type);
if (PyModule_AddObject(m, "_WCSdpService",
(PyObject *)&wcsdpservice_type) != 0) {
return NULL;
}
#endif
#define ADD_INT_CONST(m, a) PyModule_AddIntConstant(m, #a, a)
ADD_INT_CONST(m, RFCOMM_DEFAULT_MTU);
// CRfCommPort::PORT_RETURN_CODE enum
PyModule_AddIntConstant(m, "RFCOMM_SUCCESS", CRfCommPort::SUCCESS);
PyModule_AddIntConstant(m, "RFCOMM_ALREADY_OPENED", CRfCommPort::ALREADY_OPENED);
PyModule_AddIntConstant(m, "RFCOMM_NOT_OPENED", CRfCommPort::NOT_OPENED);
PyModule_AddIntConstant(m, "RFCOMM_HANDLE_ERROR", CRfCommPort::HANDLE_ERROR);
PyModule_AddIntConstant(m, "RFCOMM_LINE_ERR", CRfCommPort::LINE_ERR);
PyModule_AddIntConstant(m, "RFCOMM_START_FAILED", CRfCommPort::START_FAILED);
PyModule_AddIntConstant(m, "RFCOMM_PAR_NEG_FAILED", CRfCommPort::PAR_NEG_FAILED);
PyModule_AddIntConstant(m, "RFCOMM_PORT_NEG_FAILED", CRfCommPort::PORT_NEG_FAILED);
PyModule_AddIntConstant(m, "RFCOMM_PEER_CONNECTION_FAILED", CRfCommPort::PEER_CONNECTION_FAILED);
PyModule_AddIntConstant(m, "RFCOMM_PEER_TIMEOUT", CRfCommPort::PEER_TIMEOUT);
PyModule_AddIntConstant(m, "RFCOMM_INVALID_PARAMETER", CRfCommPort::INVALID_PARAMETER);
PyModule_AddIntConstant(m, "RFCOMM_UNKNOWN_ERROR", CRfCommPort::UNKNOWN_ERROR);
ADD_INT_CONST (m, PORT_EV_RXFLAG);
ADD_INT_CONST (m, PORT_EV_TXEMPTY);
ADD_INT_CONST (m, PORT_EV_CTS);
ADD_INT_CONST (m, PORT_EV_DSR);
ADD_INT_CONST (m, PORT_EV_RLSD);
ADD_INT_CONST (m, PORT_EV_BREAK);
ADD_INT_CONST (m, PORT_EV_ERR);
ADD_INT_CONST (m, PORT_EV_RING);
ADD_INT_CONST (m, PORT_EV_CTSS);
ADD_INT_CONST (m, PORT_EV_DSRS);
ADD_INT_CONST (m, PORT_EV_RLSDS);
ADD_INT_CONST (m, PORT_EV_OVERRUN);
ADD_INT_CONST (m, PORT_EV_TXCHAR);
ADD_INT_CONST (m, PORT_EV_CONNECTED);
ADD_INT_CONST (m, PORT_EV_CONNECT_ERR);
ADD_INT_CONST (m, PORT_EV_FC);
ADD_INT_CONST (m, PORT_EV_FCS);
ADD_INT_CONST (m, BTM_SEC_NONE);
ADD_INT_CONST (m, BTM_SEC_IN_AUTHORIZE);
ADD_INT_CONST (m, BTM_SEC_IN_AUTHENTICATE);
ADD_INT_CONST (m, BTM_SEC_IN_ENCRYPT);
ADD_INT_CONST (m, BTM_SEC_OUT_AUTHORIZE);
ADD_INT_CONST (m, BTM_SEC_OUT_AUTHENTICATE);
ADD_INT_CONST (m, BTM_SEC_OUT_ENCRYPT);
ADD_INT_CONST (m, BTM_SEC_BOND);
PyModule_AddIntConstant(m, "INQ_DEVICE_RESPONDED",
WCInquirer::DEVICE_RESPONDED);
PyModule_AddIntConstant(m, "INQ_INQUIRY_COMPLETE",
WCInquirer::INQUIRY_COMPLETE);
PyModule_AddIntConstant(m, "INQ_DISCOVERY_COMPLETE",
WCInquirer::DISCOVERY_COMPLETE);
PyModule_AddIntConstant(m, "INQ_STACK_STATUS_CHANGE",
WCInquirer::STACK_STATUS_CHAGE);
PyModule_AddIntConstant(m, "RFCOMM_DATA_RECEIVED",
WCRfCommPort::DATA_RECEIVED);
PyModule_AddIntConstant(m, "RFCOMM_EVENT_RECEIVED",
WCRfCommPort::EVENT_RECEIVED);
PyModule_AddIntConstant(m, "L2CAP_DATA_RECEIVED",
WCL2CapConn::DATA_RECEIVED);
PyModule_AddIntConstant(m, "L2CAP_INCOMING_CONNECTION",
WCL2CapConn::INCOMING_CONNECTION);
PyModule_AddIntConstant(m, "L2CAP_REMOTE_DISCONNECTED",
WCL2CapConn::REMOTE_DISCONNECTED);
PyModule_AddIntConstant(m, "L2CAP_CONNECTED",
WCL2CapConn::CONNECTED);
ADD_INT_CONST (m, SDP_OK);
ADD_INT_CONST (m, SDP_COULD_NOT_ADD_RECORD);
ADD_INT_CONST (m, SDP_INVALID_RECORD);
ADD_INT_CONST (m, SDP_INVALID_PARAMETERS);
#if PY_MAJOR_VERSION >= 3
return m;
#endif
}
} // extern "C"
pybluez-0.23/widcomm/inquirer.cpp 0000664 0000000 0000000 00000041515 13601523637 0017145 0 ustar 00root root 0000000 0000000 #include
#include
#include
#include
#include
#include "util.h"
#include
#include "inquirer.hpp"
static inline void
dbg (const char *fmt, ...)
{
return;
va_list ap;
va_start (ap, fmt);
vfprintf (stderr, fmt, ap);
va_end (ap);
}
static void
dict_set_str_pyobj(PyObject *dict, const char *key, PyObject *valobj)
{
PyObject *keyobj;
keyobj = PyString_FromString (key);
PyDict_SetItem (dict, keyobj, valobj);
Py_DECREF (keyobj);
}
static void
dict_set_strings(PyObject *dict, const char *key, const char *val)
{
PyObject *keyobj, *valobj;
keyobj = PyString_FromString (key);
valobj = PyString_FromString (val);
PyDict_SetItem (dict, keyobj, valobj);
Py_DECREF (keyobj);
Py_DECREF (valobj);
}
static void
dict_set_str_long(PyObject *dict, const char *key, long val)
{
PyObject *keyobj, *valobj;
keyobj = PyString_FromString (key);
valobj = PyInt_FromLong(val);
PyDict_SetItem (dict, keyobj, valobj);
Py_DECREF (keyobj);
Py_DECREF (valobj);
}
WCInquirer::WCInquirer (PyObject *wcinq)
{
this->wcinq = wcinq;
this->serverfd = socket (AF_INET, SOCK_STREAM, 0);
this->threadfd = socket (AF_INET, SOCK_STREAM, 0);
int status = SOCKET_ERROR;
struct sockaddr_in saddr = { 0, };
for (int i=0; i<10; i++) {
this->sockport = 3000 + (unsigned short) (20000 *
(rand () / (RAND_MAX + 1.0)));
saddr.sin_family = AF_INET;
saddr.sin_port = htons (this->sockport);
saddr.sin_addr.s_addr = inet_addr ("127.0.0.1");
status = bind (this->serverfd, (struct sockaddr*) &saddr,
sizeof (saddr));
if (0 == status) break;
}
assert (0 == status);
// instruct server socket to accept one connection
status = listen (this->serverfd, 1);
// TODO error checking
// // connect the client socket to the server socket
// status = connect (this->threadfd, (struct sockaddr*) &saddr,
// sizeof (saddr));
// // TODO error checking
}
WCInquirer::~WCInquirer ()
{
closesocket (this->threadfd);
}
int
WCInquirer::AcceptClient ()
{
struct sockaddr_in useless;
int useless_sz = sizeof (useless);
this->threadfd =
accept (this->serverfd, (struct sockaddr*)&useless, &useless_sz);
if (this->threadfd >= 0) {
// put sockets into nonblocking mode
unsigned long nonblocking = 1;
ioctlsocket (this->threadfd, FIONBIO, &nonblocking);
closesocket (this->serverfd);
return 0;
}
return -1;
}
#pragma pack(push)
#pragma pack(1)
typedef struct {
int msg_type;
unsigned char bda[6];
unsigned char devClass[3];
unsigned char bdName[248];
int bConnected;
} device_responded_msg_t;
void
WCInquirer::OnDeviceResponded (BD_ADDR bda, DEV_CLASS devClass,
BD_NAME bdName, BOOL bConnected)
{
dbg ("%s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__);
device_responded_msg_t msg;
memset (&msg, 0, sizeof (msg));
msg.msg_type = DEVICE_RESPONDED;
memcpy (msg.bda, bda, BD_ADDR_LEN);
memcpy (msg.devClass, devClass, sizeof (devClass));
memcpy (msg.bdName, bdName, strlen ((char*)bdName));
msg.bConnected = bConnected;
send (this->threadfd, reinterpret_cast (&msg),
sizeof (msg), 0);
}
typedef struct {
int msg_type;
int success;
short num_responses;
} inquiry_complete_msg_t;
void
WCInquirer::OnInquiryComplete (BOOL success, short num_responses)
{
dbg ("%s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__);
inquiry_complete_msg_t msg;
msg.msg_type = INQUIRY_COMPLETE;
msg.success = success;
msg.num_responses = num_responses;
send (this->threadfd, reinterpret_cast (&msg),
sizeof (msg), 0);
}
typedef struct {
int msg_type;
} discovery_complete_msg_t;
void
WCInquirer::OnDiscoveryComplete ()
{
dbg ("%s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__);
discovery_complete_msg_t msg;
msg.msg_type = DISCOVERY_COMPLETE;
send (this->threadfd, reinterpret_cast