pax_global_header00006660000000000000000000000064136015236370014520gustar00rootroot0000000000000052 comment=0998c40ebad69b3c8e2b3e90f1fd0c0879ce6a57 pybluez-0.23/000077500000000000000000000000001360152363700131365ustar00rootroot00000000000000pybluez-0.23/.github/000077500000000000000000000000001360152363700144765ustar00rootroot00000000000000pybluez-0.23/.github/ISSUE_TEMPLATE.md000066400000000000000000000007211360152363700172030ustar00rootroot00000000000000*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.yml000066400000000000000000000015521360152363700163340ustar00rootroot00000000000000# 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/000077500000000000000000000000001360152363700165335ustar00rootroot00000000000000pybluez-0.23/.github/workflows/build.yml000066400000000000000000000037221360152363700203610ustar00rootroot00000000000000name: 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/.gitignore000066400000000000000000000002221360152363700151220ustar00rootroot00000000000000*.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/CHANGELOG000066400000000000000000000235671360152363700143650ustar00rootroot00000000000000PyBluez 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/COPYING000066400000000000000000000431051360152363700141740ustar00rootroot00000000000000 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.in000066400000000000000000000007301360152363700146740ustar00rootroot00000000000000include 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.md000066400000000000000000000105031360152363700144140ustar00rootroot00000000000000PyBluez ======= [![Build Status](https://github.com/pybluez/pybluez/workflows/Build/badge.svg)](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/000077500000000000000000000000001360152363700151435ustar00rootroot00000000000000pybluez-0.23/bluetooth/__init__.py000066400000000000000000000250051360152363700172560ustar00rootroot00000000000000import 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.py000066400000000000000000000000271360152363700162560ustar00rootroot00000000000000from gattlib import * pybluez-0.23/bluetooth/bluez.py000066400000000000000000000577351360152363700166570ustar00rootroot00000000000000import 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.py000066400000000000000000000321471360152363700173420ustar00rootroot00000000000000import 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.py000066400000000000000000000103521360152363700166200ustar00rootroot00000000000000import 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.py000066400000000000000000000223551360152363700164710ustar00rootroot00000000000000from 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.py000066400000000000000000000715711360152363700171670ustar00rootroot00000000000000from .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/000077500000000000000000000000001360152363700142575ustar00rootroot00000000000000pybluez-0.23/bluez/btmodule.c000066400000000000000000003341661360152363700162530ustar00rootroot00000000000000/* 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.h000066400000000000000000000023621360152363700162460ustar00rootroot00000000000000#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.c000066400000000000000000000331461360152363700155460ustar00rootroot00000000000000#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.h000066400000000000000000000005651360152363700155520ustar00rootroot00000000000000#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/000077500000000000000000000000001360152363700140665ustar00rootroot00000000000000pybluez-0.23/docs/Makefile000066400000000000000000000167601360152363700155400ustar00rootroot00000000000000## 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/000077500000000000000000000000001360152363700155145ustar00rootroot00000000000000pybluez-0.23/docs/_static/.nofile000066400000000000000000000000001360152363700167570ustar00rootroot00000000000000pybluez-0.23/docs/_templates/000077500000000000000000000000001360152363700162235ustar00rootroot00000000000000pybluez-0.23/docs/_templates/.nofile000066400000000000000000000000001360152363700174660ustar00rootroot00000000000000pybluez-0.23/docs/api/000077500000000000000000000000001360152363700146375ustar00rootroot00000000000000pybluez-0.23/docs/api/advertise_service.rst000066400000000000000000000001451360152363700210770ustar00rootroot00000000000000advertise_service ----------------- .. currentmodule:: bluetooth .. autofunction:: advertise_servicepybluez-0.23/docs/api/bluetooth_socket.rst000066400000000000000000000003161360152363700207460ustar00rootroot00000000000000BluetoothSocket --------------- .. todo:: Add documentation for the BluetoothSocket methods. .. currentmodule:: bluetooth .. autoclass:: BluetoothSocket :show-inheritance: :members: :undoc-members:pybluez-0.23/docs/api/device_discoverer.rst000066400000000000000000000003361360152363700210570ustar00rootroot00000000000000DeviceDiscoverer ---------------- .. 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.rst000066400000000000000000000001421360152363700207060ustar00rootroot00000000000000discover_devices ---------------- .. currentmodule:: bluetooth .. autofunction:: discover_devicespybluez-0.23/docs/api/find_service.rst000066400000000000000000000001261360152363700200300ustar00rootroot00000000000000find_service ------------ .. currentmodule:: bluetooth .. autofunction:: find_servicepybluez-0.23/docs/api/index.rst000066400000000000000000000007231360152363700165020ustar00rootroot00000000000000.. _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.rst000066400000000000000000000001231360152363700176760ustar00rootroot00000000000000lookup_name ----------- .. currentmodule:: bluetooth .. autofunction:: lookup_namepybluez-0.23/docs/api/stop_advertising.rst000066400000000000000000000001421360152363700207520ustar00rootroot00000000000000stop_advertising ---------------- .. currentmodule:: bluetooth .. autofunction:: stop_advertisingpybluez-0.23/docs/conf.py000066400000000000000000000073551360152363700153770ustar00rootroot00000000000000# 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.rst000066400000000000000000000041561360152363700173350ustar00rootroot00000000000000======================= 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/issuespybluez-0.23/docs/contributors.rst000066400000000000000000000033271360152363700173620ustar00rootroot00000000000000============ 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.rst000066400000000000000000000015211360152363700157260ustar00rootroot00000000000000======= 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.rst000066400000000000000000000051351360152363700162720ustar00rootroot00000000000000.. _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.rst000066400000000000000000000015411360152363700162430ustar00rootroot00000000000000======= 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 SIGNpybluez-0.23/docs/make.bat000066400000000000000000000155151360152363700155020ustar00rootroot00000000000000@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 ) :endpybluez-0.23/docs/requirements.txt000066400000000000000000000000541360152363700173510ustar00rootroot00000000000000sphinx recommonmark sphinx_rtd_theme easydevpybluez-0.23/docs/user/000077500000000000000000000000001360152363700150445ustar00rootroot00000000000000pybluez-0.23/docs/user/intro.rst000066400000000000000000000002021360152363700167230ustar00rootroot00000000000000.. orphan page while we develop it. This stops sphinx raising a toctree warning. :orphan: ************ Introduction ************pybluez-0.23/examples/000077500000000000000000000000001360152363700147545ustar00rootroot00000000000000pybluez-0.23/examples/advanced/000077500000000000000000000000001360152363700165215ustar00rootroot00000000000000pybluez-0.23/examples/advanced/inquiry-with-rssi.py000066400000000000000000000122551360152363700225270ustar00rootroot00000000000000#!/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.py000066400000000000000000000032701360152363700202150ustar00rootroot00000000000000#!/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.py000066400000000000000000000025351360152363700230110ustar00rootroot00000000000000#!/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.py000066400000000000000000000013671360152363700230430ustar00rootroot00000000000000#!/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.py000066400000000000000000000003441360152363700223150ustar00rootroot00000000000000#!/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.py000066400000000000000000000062311360152363700226470ustar00rootroot00000000000000#!/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/000077500000000000000000000000001360152363700155165ustar00rootroot00000000000000pybluez-0.23/examples/ble/beacon.py000066400000000000000000000006301360152363700173160ustar00rootroot00000000000000#!/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.py000066400000000000000000000015721360152363700203300ustar00rootroot00000000000000#!/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.py000066400000000000000000000020471360152363700200060ustar00rootroot00000000000000#!/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.py000066400000000000000000000004311360152363700170120ustar00rootroot00000000000000#!/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/000077500000000000000000000000001360152363700167355ustar00rootroot00000000000000pybluez-0.23/examples/bluezchat/bluezchat.glade000066400000000000000000000135051360152363700217200ustar00rootroot00000000000000 True bluez chat 240 320 True True True True GTK_SHADOW_IN True True False True True True _Quit True True True S_can True 1 True True _Chat True 2 1 True True GTK_SHADOW_IN True True 1 True True text: False False True True * 3 1 True True _Send True False False 2 2 pybluez-0.23/examples/bluezchat/bluezchat.gladep000066400000000000000000000004271360152363700220770ustar00rootroot00000000000000 Bluezchat bluezchat FALSE pybluez-0.23/examples/bluezchat/bluezchat.py000077500000000000000000000136651360152363700213060ustar00rootroot00000000000000#!/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/000077500000000000000000000000001360152363700162455ustar00rootroot00000000000000pybluez-0.23/examples/simple/asynchronous-inquiry.py000066400000000000000000000040241360152363700230500ustar00rootroot00000000000000#!/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.py000066400000000000000000000013401360152363700203150ustar00rootroot00000000000000#!/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.py000066400000000000000000000014161360152363700210210ustar00rootroot00000000000000#!/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.py000066400000000000000000000014751360152363700210560ustar00rootroot00000000000000#!/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.py000066400000000000000000000024651360152363700213650ustar00rootroot00000000000000#!/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.py000066400000000000000000000022641360152363700214120ustar00rootroot00000000000000#!/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.py000066400000000000000000000021561360152363700207100ustar00rootroot00000000000000#!/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/000077500000000000000000000000001360152363700154125ustar00rootroot00000000000000pybluez-0.23/legacy_docs/epydoc.css000066400000000000000000000104561360152363700174150ustar00rootroot00000000000000 /* 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.html000066400000000000000000000006061360152363700174110ustar00rootroot00000000000000 API Documentation pybluez-0.23/legacy_docs/private/000077500000000000000000000000001360152363700170645ustar00rootroot00000000000000pybluez-0.23/legacy_docs/private/bluetooth-module.html000066400000000000000000003670121360152363700232530ustar00rootroot00000000000000 bluetooth
Module bluetooth
[show private | hide private]
[frames | no frames]

Module bluetooth

PyBluez - Bluetooth extension module
Classes
BluetoothSocket BluetoothSocket
DeviceDiscoverer DeviceDiscoverer

Exceptions
BluetoothError  

Function Summary
  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.
  get_available_port(protocol)
deprecated.
  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
  set_l2cap_mtu(sock, mtu)
set_l2cap_mtu( sock, mtu )
  set_packet_timeout(address, timeout)
set_packet_timeout( address, timeout )
  stop_advertising(sock)
Instructs the local SDP server to stop advertising the service associated with sock.

Variable Summary
str ADVANCED_AUDIO_CLASS = '110d'
tuple ADVANCED_AUDIO_PROFILE = ('110d', 256)
str AUDIO_SINK_CLASS = '110b'
tuple AUDIO_SINK_PROFILE = ('110b', 256)
str AUDIO_SOURCE_CLASS = '110a'
tuple AUDIO_SOURCE_PROFILE = ('110a', 256)
str AV_CLASS = '112c'
tuple AV_PROFILE = ('112c', 256)
str AV_REMOTE_CLASS = '110e'
tuple AV_REMOTE_PROFILE = ('110e', 256)
str AV_REMOTE_TARGET_CLASS = '110c'
tuple AV_REMOTE_TARGET_PROFILE = ('110c', 256)
str BASIC_PRINTING_CLASS = '1122'
tuple BASIC_PRINTING_PROFILE = ('1122', 256)
str BROWSE_GRP_DESC_CLASS = '1001'
tuple BROWSE_GRP_DESC_PROFILE = ('1001', 256)
str CIP_CLASS = '1128'
tuple CIP_PROFILE = ('1128', 256)
str CORDLESS_TELEPHONY_CLASS = '1109'
tuple CORDLESS_TELEPHONY_PROFILE = ('1109', 256)
str DIALUP_NET_CLASS = '1103'
tuple DIALUP_NET_PROFILE = ('1103', 256)
str DIRECT_PRINTING_CLASS = '1118'
tuple DIRECT_PRINTING_PROFILE = ('1118', 256)
str DIRECT_PRT_REFOBJS_CLASS = '1120'
tuple DIRECT_PRT_REFOBJS_PROFILE = ('1120', 256)
str FAX_CLASS = '1111'
tuple FAX_PROFILE = ('1111', 256)
str GENERIC_AUDIO_CLASS = '1203'
tuple GENERIC_AUDIO_PROFILE = ('1203', 256)
str GENERIC_FILETRANS_CLASS = '1202'
tuple GENERIC_FILETRANS_PROFILE = ('1202', 256)
str GENERIC_NETWORKING_CLASS = '1201'
tuple GENERIC_NETWORKING_PROFILE = ('1201', 256)
str GENERIC_TELEPHONY_CLASS = '1204'
tuple GENERIC_TELEPHONY_PROFILE = ('1204', 256)
str GN_CLASS = '1117'
tuple GN_PROFILE = ('1117', 256)
str HANDSFREE_AGW_CLASS = '111f'
tuple HANDSFREE_AGW_PROFILE = ('111f', 256)
str HANDSFREE_CLASS = '111e'
tuple HANDSFREE_PROFILE = ('111e', 256)
str HCR_CLASS = '1125'
str HCR_PRINT_CLASS = '1126'
tuple HCR_PRINT_PROFILE = ('1126', 256)
tuple HCR_PROFILE = ('1127', 256)
str HCR_SCAN_CLASS = '1127'
tuple HCR_SCAN_PROFILE = ('1127', 256)
str HEADSET_AGW_CLASS = '1112'
tuple HEADSET_AGW_PROFILE = ('1112', 256)
str HEADSET_CLASS = '1108'
tuple HEADSET_PROFILE = ('1108', 256)
str HID_CLASS = '1124'
tuple HID_PROFILE = ('1124', 256)
str IMAGING_ARCHIVE_CLASS = '111c'
tuple IMAGING_ARCHIVE_PROFILE = ('111c', 256)
str IMAGING_CLASS = '111a'
tuple IMAGING_PROFILE = ('111a', 256)
str IMAGING_REFOBJS_CLASS = '111d'
tuple IMAGING_REFOBJS_PROFILE = ('111d', 256)
str IMAGING_RESPONDER_CLASS = '111b'
tuple IMAGING_RESPONDER_PROFILE = ('111b', 256)
str INTERCOM_CLASS = '1110'
tuple INTERCOM_PROFILE = ('1110', 256)
str IRMC_SYNC_CLASS = '1104'
str IRMC_SYNC_CMD_CLASS = '1107'
tuple IRMC_SYNC_CMD_PROFILE = ('1107', 256)
tuple IRMC_SYNC_PROFILE = ('1104', 256)
int L2CAP = 3                                                                     
str LAN_ACCESS_CLASS = '1102'
tuple LAN_ACCESS_PROFILE = ('1102', 256)
str NAP_CLASS = '1116'
tuple NAP_PROFILE = ('1116', 256)
str OBEX_FILETRANS_CLASS = '1106'
tuple OBEX_FILETRANS_PROFILE = ('1106', 256)
str OBEX_OBJPUSH_CLASS = '1105'
tuple OBEX_OBJPUSH_PROFILE = ('1105', 256)
str PANU_CLASS = '1115'
tuple PANU_PROFILE = ('1115', 256)
str PNP_INFO_CLASS = '1200'
tuple PNP_INFO_PROFILE = ('1200', 256)
int PORT_ANY = 0                                                                     
str PRINTING_STATUS_CLASS = '1123'
tuple PRINTING_STATUS_PROFILE = ('1123', 256)
str PUBLIC_BROWSE_GROUP = '1002'
str REFERENCE_PRINTING_CLASS = '1119'
tuple REFERENCE_PRINTING_PROFILE = ('1119', 256)
str REFLECTED_UI_CLASS = '1121'
tuple REFLECTED_UI_PROFILE = ('1121', 256)
int RFCOMM = 0                                                                     
str SAP_CLASS = '112d'
tuple SAP_PROFILE = ('112d', 256)
str SDP_SERVER_CLASS = '1000'
tuple SDP_SERVER_PROFILE = ('1000', 256)
str SERIAL_PORT_CLASS = '1101'
tuple SERIAL_PORT_PROFILE = ('1101', 256)
str UDI_MT_CLASS = '112a'
tuple UDI_MT_PROFILE = ('112a', 256)
str UDI_TA_CLASS = '112b'
tuple UDI_TA_PROFILE = ('112b', 256)
str UPNP_CLASS = '1205'
str UPNP_IP_CLASS = '1206'
tuple UPNP_IP_PROFILE = ('1206', 256)
str UPNP_L2CAP_CLASS = '1302'
tuple UPNP_L2CAP_PROFILE = ('1302', 256)
str UPNP_LAP_CLASS = '1301'
tuple UPNP_LAP_PROFILE = ('1301', 256)
str UPNP_PAN_CLASS = '1300'
tuple UPNP_PAN_PROFILE = ('1300', 256)
tuple UPNP_PROFILE = ('1205', 256)
str VIDEO_CONF_CLASS = '110f'
str VIDEO_CONF_GW_CLASS = '1129'
tuple VIDEO_CONF_GW_PROFILE = ('1129', 256)
tuple VIDEO_CONF_PROFILE = ('110f', 256)
str VIDEO_SINK_CLASS = '1304'
tuple VIDEO_SINK_PROFILE = ('1304', 256)
str VIDEO_SOURCE_CLASS = '1303'
tuple VIDEO_SOURCE_PROFILE = ('1303', 256)
str WAP_CLASS = '1113'
str WAP_CLIENT_CLASS = '1114'
tuple WAP_CLIENT_PROFILE = ('1114', 256)
tuple WAP_PROFILE = ('1113', 256)

Function Details

advertise_service(sock, name, service_id='', service_classes=[], profiles=[], provider='', description='')

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)

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.

Variable Details

ADVANCED_AUDIO_CLASS

Type:
str
Value:
'110d'                                                                 

ADVANCED_AUDIO_PROFILE

Type:
tuple
Value:
('110d', 256)                                                          

AUDIO_SINK_CLASS

Type:
str
Value:
'110b'                                                                 

AUDIO_SINK_PROFILE

Type:
tuple
Value:
('110b', 256)                                                          

AUDIO_SOURCE_CLASS

Type:
str
Value:
'110a'                                                                 

AUDIO_SOURCE_PROFILE

Type:
tuple
Value:
('110a', 256)                                                          

AV_CLASS

Type:
str
Value:
'112c'                                                                 

AV_PROFILE

Type:
tuple
Value:
('112c', 256)                                                          

AV_REMOTE_CLASS

Type:
str
Value:
'110e'                                                                 

AV_REMOTE_PROFILE

Type:
tuple
Value:
('110e', 256)                                                          

AV_REMOTE_TARGET_CLASS

Type:
str
Value:
'110c'                                                                 

AV_REMOTE_TARGET_PROFILE

Type:
tuple
Value:
('110c', 256)                                                          

BASIC_PRINTING_CLASS

Type:
str
Value:
'1122'                                                                 

BASIC_PRINTING_PROFILE

Type:
tuple
Value:
('1122', 256)                                                          

BROWSE_GRP_DESC_CLASS

Type:
str
Value:
'1001'                                                                 

BROWSE_GRP_DESC_PROFILE

Type:
tuple
Value:
('1001', 256)                                                          

CIP_CLASS

Type:
str
Value:
'1128'                                                                 

CIP_PROFILE

Type:
tuple
Value:
('1128', 256)                                                          

CORDLESS_TELEPHONY_CLASS

Type:
str
Value:
'1109'                                                                 

CORDLESS_TELEPHONY_PROFILE

Type:
tuple
Value:
('1109', 256)                                                          

DIALUP_NET_CLASS

Type:
str
Value:
'1103'                                                                 

DIALUP_NET_PROFILE

Type:
tuple
Value:
('1103', 256)                                                          

DIRECT_PRINTING_CLASS

Type:
str
Value:
'1118'                                                                 

DIRECT_PRINTING_PROFILE

Type:
tuple
Value:
('1118', 256)                                                          

DIRECT_PRT_REFOBJS_CLASS

Type:
str
Value:
'1120'                                                                 

DIRECT_PRT_REFOBJS_PROFILE

Type:
tuple
Value:
('1120', 256)                                                          

FAX_CLASS

Type:
str
Value:
'1111'                                                                 

FAX_PROFILE

Type:
tuple
Value:
('1111', 256)                                                          

GENERIC_AUDIO_CLASS

Type:
str
Value:
'1203'                                                                 

GENERIC_AUDIO_PROFILE

Type:
tuple
Value:
('1203', 256)                                                          

GENERIC_FILETRANS_CLASS

Type:
str
Value:
'1202'                                                                 

GENERIC_FILETRANS_PROFILE

Type:
tuple
Value:
('1202', 256)                                                          

GENERIC_NETWORKING_CLASS

Type:
str
Value:
'1201'                                                                 

GENERIC_NETWORKING_PROFILE

Type:
tuple
Value:
('1201', 256)                                                          

GENERIC_TELEPHONY_CLASS

Type:
str
Value:
'1204'                                                                 

GENERIC_TELEPHONY_PROFILE

Type:
tuple
Value:
('1204', 256)                                                          

GN_CLASS

Type:
str
Value:
'1117'                                                                 

GN_PROFILE

Type:
tuple
Value:
('1117', 256)                                                          

HANDSFREE_AGW_CLASS

Type:
str
Value:
'111f'                                                                 

HANDSFREE_AGW_PROFILE

Type:
tuple
Value:
('111f', 256)                                                          

HANDSFREE_CLASS

Type:
str
Value:
'111e'                                                                 

HANDSFREE_PROFILE

Type:
tuple
Value:
('111e', 256)                                                          

HCR_CLASS

Type:
str
Value:
'1125'                                                                 

HCR_PRINT_CLASS

Type:
str
Value:
'1126'                                                                 

HCR_PRINT_PROFILE

Type:
tuple
Value:
('1126', 256)                                                          

HCR_PROFILE

Type:
tuple
Value:
('1127', 256)                                                          

HCR_SCAN_CLASS

Type:
str
Value:
'1127'                                                                 

HCR_SCAN_PROFILE

Type:
tuple
Value:
('1127', 256)                                                          

HEADSET_AGW_CLASS

Type:
str
Value:
'1112'                                                                 

HEADSET_AGW_PROFILE

Type:
tuple
Value:
('1112', 256)                                                          

HEADSET_CLASS

Type:
str
Value:
'1108'                                                                 

HEADSET_PROFILE

Type:
tuple
Value:
('1108', 256)                                                          

HID_CLASS

Type:
str
Value:
'1124'                                                                 

HID_PROFILE

Type:
tuple
Value:
('1124', 256)                                                          

IMAGING_ARCHIVE_CLASS

Type:
str
Value:
'111c'                                                                 

IMAGING_ARCHIVE_PROFILE

Type:
tuple
Value:
('111c', 256)                                                          

IMAGING_CLASS

Type:
str
Value:
'111a'                                                                 

IMAGING_PROFILE

Type:
tuple
Value:
('111a', 256)                                                          

IMAGING_REFOBJS_CLASS

Type:
str
Value:
'111d'                                                                 

IMAGING_REFOBJS_PROFILE

Type:
tuple
Value:
('111d', 256)                                                          

IMAGING_RESPONDER_CLASS

Type:
str
Value:
'111b'                                                                 

IMAGING_RESPONDER_PROFILE

Type:
tuple
Value:
('111b', 256)                                                          

INTERCOM_CLASS

Type:
str
Value:
'1110'                                                                 

INTERCOM_PROFILE

Type:
tuple
Value:
('1110', 256)                                                          

IRMC_SYNC_CLASS

Type:
str
Value:
'1104'                                                                 

IRMC_SYNC_CMD_CLASS

Type:
str
Value:
'1107'                                                                 

IRMC_SYNC_CMD_PROFILE

Type:
tuple
Value:
('1107', 256)                                                          

IRMC_SYNC_PROFILE

Type:
tuple
Value:
('1104', 256)                                                          

L2CAP

Type:
int
Value:
3                                                                     

LAN_ACCESS_CLASS

Type:
str
Value:
'1102'                                                                 

LAN_ACCESS_PROFILE

Type:
tuple
Value:
('1102', 256)                                                          

NAP_CLASS

Type:
str
Value:
'1116'                                                                 

NAP_PROFILE

Type:
tuple
Value:
('1116', 256)                                                          

OBEX_FILETRANS_CLASS

Type:
str
Value:
'1106'                                                                 

OBEX_FILETRANS_PROFILE

Type:
tuple
Value:
('1106', 256)                                                          

OBEX_OBJPUSH_CLASS

Type:
str
Value:
'1105'                                                                 

OBEX_OBJPUSH_PROFILE

Type:
tuple
Value:
('1105', 256)                                                          

PANU_CLASS

Type:
str
Value:
'1115'                                                                 

PANU_PROFILE

Type:
tuple
Value:
('1115', 256)                                                          

PNP_INFO_CLASS

Type:
str
Value:
'1200'                                                                 

PNP_INFO_PROFILE

Type:
tuple
Value:
('1200', 256)                                                          

PORT_ANY

Type:
int
Value:
0                                                                     

PRINTING_STATUS_CLASS

Type:
str
Value:
'1123'                                                                 

PRINTING_STATUS_PROFILE

Type:
tuple
Value:
('1123', 256)                                                          

PUBLIC_BROWSE_GROUP

Type:
str
Value:
'1002'                                                                 

REFERENCE_PRINTING_CLASS

Type:
str
Value:
'1119'                                                                 

REFERENCE_PRINTING_PROFILE

Type:
tuple
Value:
('1119', 256)                                                          

REFLECTED_UI_CLASS

Type:
str
Value:
'1121'                                                                 

REFLECTED_UI_PROFILE

Type:
tuple
Value:
('1121', 256)                                                          

RFCOMM

Type:
int
Value:
0                                                                     

SAP_CLASS

Type:
str
Value:
'112d'                                                                 

SAP_PROFILE

Type:
tuple
Value:
('112d', 256)                                                          

SDP_SERVER_CLASS

Type:
str
Value:
'1000'                                                                 

SDP_SERVER_PROFILE

Type:
tuple
Value:
('1000', 256)                                                          

SERIAL_PORT_CLASS

Type:
str
Value:
'1101'                                                                 

SERIAL_PORT_PROFILE

Type:
tuple
Value:
('1101', 256)                                                          

UDI_MT_CLASS

Type:
str
Value:
'112a'                                                                 

UDI_MT_PROFILE

Type:
tuple
Value:
('112a', 256)                                                          

UDI_TA_CLASS

Type:
str
Value:
'112b'                                                                 

UDI_TA_PROFILE

Type:
tuple
Value:
('112b', 256)                                                          

UPNP_CLASS

Type:
str
Value:
'1205'                                                                 

UPNP_IP_CLASS

Type:
str
Value:
'1206'                                                                 

UPNP_IP_PROFILE

Type:
tuple
Value:
('1206', 256)                                                          

UPNP_L2CAP_CLASS

Type:
str
Value:
'1302'                                                                 

UPNP_L2CAP_PROFILE

Type:
tuple
Value:
('1302', 256)                                                          

UPNP_LAP_CLASS

Type:
str
Value:
'1301'                                                                 

UPNP_LAP_PROFILE

Type:
tuple
Value:
('1301', 256)                                                          

UPNP_PAN_CLASS

Type:
str
Value:
'1300'                                                                 

UPNP_PAN_PROFILE

Type:
tuple
Value:
('1300', 256)                                                          

UPNP_PROFILE

Type:
tuple
Value:
('1205', 256)                                                          

VIDEO_CONF_CLASS

Type:
str
Value:
'110f'                                                                 

VIDEO_CONF_GW_CLASS

Type:
str
Value:
'1129'                                                                 

VIDEO_CONF_GW_PROFILE

Type:
tuple
Value:
('1129', 256)                                                          

VIDEO_CONF_PROFILE

Type:
tuple
Value:
('110f', 256)                                                          

VIDEO_SINK_CLASS

Type:
str
Value:
'1304'                                                                 

VIDEO_SINK_PROFILE

Type:
tuple
Value:
('1304', 256)                                                          

VIDEO_SOURCE_CLASS

Type:
str
Value:
'1303'                                                                 

VIDEO_SOURCE_PROFILE

Type:
tuple
Value:
('1303', 256)                                                          

WAP_CLASS

Type:
str
Value:
'1113'                                                                 

WAP_CLIENT_CLASS

Type:
str
Value:
'1114'                                                                 

WAP_CLIENT_PROFILE

Type:
tuple
Value:
('1114', 256)                                                          

WAP_PROFILE

Type:
tuple
Value:
('1113', 256)                                                          

Generated by Epydoc 2.1 on Tue May 9 02:23:39 2006 http://epydoc.sf.net
pybluez-0.23/legacy_docs/private/bluetooth.BluetoothError-class.html000066400000000000000000000114261360152363700260440ustar00rootroot00000000000000 bluetooth.BluetoothError
Module bluetooth :: Class BluetoothError
[show private | hide private]
[frames | no frames]

Class BluetoothError

Exception --+            
            |            
StandardError --+        
                |        
 EnvironmentError --+    
                    |    
              IOError --+
                        |
                       BluetoothError


Method Summary
    Inherited from EnvironmentError
  __init__(...)
  __str__(...)
    Inherited from Exception
  __getitem__(...)

Generated by Epydoc 2.1 on Tue May 9 02:23:39 2006 http://epydoc.sf.net
pybluez-0.23/legacy_docs/private/bluetooth.BluetoothSocket-class.html000066400000000000000000000542071360152363700262070ustar00rootroot00000000000000 bluetooth.BluetoothSocket
Module bluetooth :: Class BluetoothSocket
[show private | hide private]
[frames | no frames]

Class BluetoothSocket


BluetoothSocket

availability: GNU/Linux, Windows XP
Method Summary
  __init__(self, proto, _sock)
Create a new Bluetooth socket that uses the specified transport protocol.
  accept(self)
accept() -> (BluetoothSocket, addrport)
  bind(self, addrport)
bind(addrport) availability: GNU/Linux, Windows XP Bind the socket to a local adapter and port.
  close(self)
close()
  connect(self, addrport)
connect(addrport)
  dup(self)
dup() -> socket object
  fileno(self)
fileno() -> integer
  getpeername(self)
getpeername() -> address info
  getsockname(self)
getsockname() -> address info
  getsockopt(self, level, option, buffersize)
getsockopt(level, option[, buffersize]) -> value
  gettimouet(self, timeout)
gettimeout() -> timeout
  listen(self, backlog)
listen(backlog)
  makefile(self)
makefile([mode[, buffersize]]) -> file object
  recv(self, buffersize, flags)
recv(buffersize[, flags]) -> data
  send(self, data, flags)
send(data[, flags]) -> count
  sendall(self, data, flags)
sendall(data[, flags])
  setblocking(self, blocking)
setblocking(flag)
  setsockopt(self, level, option, value)
setsockopt(level, option, value)
  settimeout(self, timeout)
settimeout(timeout)
  shutdown(self, flag)
shutdown(flag)

Method Details

__init__(self, proto=0, _sock=None)
(Constructor)

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).

Generated by Epydoc 2.1 on Tue May 9 02:23:40 2006 http://epydoc.sf.net
pybluez-0.23/legacy_docs/private/bluetooth.DeviceDiscoverer-class.html000066400000000000000000000271561360152363700263210ustar00rootroot00000000000000 bluetooth.DeviceDiscoverer
Module bluetooth :: Class DeviceDiscoverer
[show private | hide private]
[frames | no frames]

Class DeviceDiscoverer


DeviceDiscoverer

availability: GNU/Linux

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()
Method Summary
  __init__(self)
TODO
  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.

device_discovered(self, address, device_class, 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

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

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.

Generated by Epydoc 2.1 on Tue May 9 02:23:39 2006 http://epydoc.sf.net
pybluez-0.23/legacy_docs/private/epydoc.css000066400000000000000000000104561360152363700210670ustar00rootroot00000000000000 /* 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/private/exceptions.EnvironmentError-class.html000066400000000000000000000107251360152363700265600ustar00rootroot00000000000000 exceptions.EnvironmentError
Module exceptions :: Class EnvironmentError
[show private | hide private]
[frames | no frames]

Class EnvironmentError

Exception --+    
            |    
StandardError --+
                |
               EnvironmentError

Known Subclasses:
IOError

Base class for I/O related errors.
Method Summary
  __init__(...)
  __str__(...)
    Inherited from Exception
  __getitem__(...)

Generated by Epydoc 2.1 on Tue May 9 02:23:39 2006 http://epydoc.sf.net
pybluez-0.23/legacy_docs/private/exceptions.Exception-class.html000066400000000000000000000100401360152363700251660ustar00rootroot00000000000000 exceptions.Exception
Module exceptions :: Class Exception
[show private | hide private]
[frames | no frames]

Class Exception

Known Subclasses:
StandardError

Common base class for all exceptions.
Method Summary
  __init__(...)
  __getitem__(...)
  __str__(...)

Generated by Epydoc 2.1 on Tue May 9 02:23:39 2006 http://epydoc.sf.net
pybluez-0.23/legacy_docs/private/exceptions.IOError-class.html000066400000000000000000000113501360152363700245560ustar00rootroot00000000000000 exceptions.IOError
Module exceptions :: Class IOError
[show private | hide private]
[frames | no frames]

Class IOError

Exception --+        
            |        
StandardError --+    
                |    
 EnvironmentError --+
                    |
                   IOError

Known Subclasses:
BluetoothError

I/O operation failed.
Method Summary
    Inherited from EnvironmentError
  __init__(...)
  __str__(...)
    Inherited from Exception
  __getitem__(...)

Generated by Epydoc 2.1 on Tue May 9 02:23:39 2006 http://epydoc.sf.net
pybluez-0.23/legacy_docs/private/exceptions.StandardError-class.html000066400000000000000000000106621360152363700260140ustar00rootroot00000000000000 exceptions.StandardError
Module exceptions :: Class StandardError
[show private | hide private]
[frames | no frames]

Class StandardError

Exception --+
            |
           StandardError

Known Subclasses:
EnvironmentError

Base class for all standard Python exceptions.
Method Summary
    Inherited from Exception
  __init__(...)
  __getitem__(...)
  __str__(...)

Generated by Epydoc 2.1 on Tue May 9 02:23:39 2006 http://epydoc.sf.net
pybluez-0.23/legacy_docs/private/frames.html000066400000000000000000000005611360152363700212310ustar00rootroot00000000000000 API Documentation pybluez-0.23/legacy_docs/private/help.html000066400000000000000000000230761360152363700207120ustar00rootroot00000000000000 Help
[show private | hide private]
[frames | no frames]

API Documentation

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.

Generated by Epydoc 2.1 on Tue May 9 02:23:40 2006 http://epydoc.sf.net
pybluez-0.23/legacy_docs/private/index.html000066400000000000000000000005611360152363700210630ustar00rootroot00000000000000 API Documentation pybluez-0.23/legacy_docs/private/indices.html000066400000000000000000001152011360152363700213700ustar00rootroot00000000000000 Index
[show private | hide private]
[frames | no frames]

Identifier Index
__getitem__ Method in class exceptions.Exception
__init__ Method in class bluetooth.BluetoothSocket
__init__ Method in class bluetooth.DeviceDiscoverer
__init__ Method in class exceptions.EnvironmentError
__init__ Method in class exceptions.Exception
__str__ Method in class exceptions.EnvironmentError
__str__ Method in class exceptions.Exception
accept Method in class bluetooth.BluetoothSocket
ADVANCED_AUDIO_CLASS Variable in module bluetooth
ADVANCED_AUDIO_PROFILE Variable in module bluetooth
advertise_service Function in module bluetooth
AUDIO_SINK_CLASS Variable in module bluetooth
AUDIO_SINK_PROFILE Variable in module bluetooth
AUDIO_SOURCE_CLASS Variable in module bluetooth
AUDIO_SOURCE_PROFILE Variable in module bluetooth
AV_CLASS Variable in module bluetooth
AV_PROFILE Variable in module bluetooth
AV_REMOTE_CLASS Variable in module bluetooth
AV_REMOTE_PROFILE Variable in module bluetooth
AV_REMOTE_TARGET_CLASS Variable in module bluetooth
AV_REMOTE_TARGET_PROFILE Variable in module bluetooth
BASIC_PRINTING_CLASS Variable in module bluetooth
BASIC_PRINTING_PROFILE Variable in module bluetooth
bind Method in class bluetooth.BluetoothSocket
bluetooth Module
BluetoothError Class in module bluetooth
BluetoothSocket Class in module bluetooth
BROWSE_GRP_DESC_CLASS Variable in module bluetooth
BROWSE_GRP_DESC_PROFILE Variable in module bluetooth
cancel_inquiry Method in class bluetooth.DeviceDiscoverer
CIP_CLASS Variable in module bluetooth
CIP_PROFILE Variable in module bluetooth
close Method in class bluetooth.BluetoothSocket
connect Method in class bluetooth.BluetoothSocket
CORDLESS_TELEPHONY_CLASS Variable in module bluetooth
CORDLESS_TELEPHONY_PROFILE Variable in module bluetooth
device_discovered Method in class bluetooth.DeviceDiscoverer
DeviceDiscoverer Class in module bluetooth
DIALUP_NET_CLASS Variable in module bluetooth
DIALUP_NET_PROFILE Variable in module bluetooth
DIRECT_PRINTING_CLASS Variable in module bluetooth
DIRECT_PRINTING_PROFILE Variable in module bluetooth
DIRECT_PRT_REFOBJS_CLASS Variable in module bluetooth
DIRECT_PRT_REFOBJS_PROFILE Variable in module bluetooth
discover_devices Function in module bluetooth
dup Method in class bluetooth.BluetoothSocket
EnvironmentError Class in module exceptions
Exception Class in module exceptions
FAX_CLASS Variable in module bluetooth
FAX_PROFILE Variable in module bluetooth
fileno Method in class bluetooth.BluetoothSocket
fileno Method in class bluetooth.DeviceDiscoverer
find_devices Method in class bluetooth.DeviceDiscoverer
find_service Function in module bluetooth
GENERIC_AUDIO_CLASS Variable in module bluetooth
GENERIC_AUDIO_PROFILE Variable in module bluetooth
GENERIC_FILETRANS_CLASS Variable in module bluetooth
GENERIC_FILETRANS_PROFILE Variable in module bluetooth
GENERIC_NETWORKING_CLASS Variable in module bluetooth
GENERIC_NETWORKING_PROFILE Variable in module bluetooth
GENERIC_TELEPHONY_CLASS Variable in module bluetooth
GENERIC_TELEPHONY_PROFILE Variable in module bluetooth
get_available_port Function in module bluetooth
getpeername Method in class bluetooth.BluetoothSocket
getsockname Method in class bluetooth.BluetoothSocket
getsockopt Method in class bluetooth.BluetoothSocket
gettimouet Method in class bluetooth.BluetoothSocket
GN_CLASS Variable in module bluetooth
GN_PROFILE Variable in module bluetooth
HANDSFREE_AGW_CLASS Variable in module bluetooth
HANDSFREE_AGW_PROFILE Variable in module bluetooth
HANDSFREE_CLASS Variable in module bluetooth
HANDSFREE_PROFILE Variable in module bluetooth
HCR_CLASS Variable in module bluetooth
HCR_PRINT_CLASS Variable in module bluetooth
HCR_PRINT_PROFILE Variable in module bluetooth
HCR_PROFILE Variable in module bluetooth
HCR_SCAN_CLASS Variable in module bluetooth
HCR_SCAN_PROFILE Variable in module bluetooth
HEADSET_AGW_CLASS Variable in module bluetooth
HEADSET_AGW_PROFILE Variable in module bluetooth
HEADSET_CLASS Variable in module bluetooth
HEADSET_PROFILE Variable in module bluetooth
HID_CLASS Variable in module bluetooth
HID_PROFILE Variable in module bluetooth
IMAGING_ARCHIVE_CLASS Variable in module bluetooth
IMAGING_ARCHIVE_PROFILE Variable in module bluetooth
IMAGING_CLASS Variable in module bluetooth
IMAGING_PROFILE Variable in module bluetooth
IMAGING_REFOBJS_CLASS Variable in module bluetooth
IMAGING_REFOBJS_PROFILE Variable in module bluetooth
IMAGING_RESPONDER_CLASS Variable in module bluetooth
IMAGING_RESPONDER_PROFILE Variable in module bluetooth
inquiry_complete Method in class bluetooth.DeviceDiscoverer
INTERCOM_CLASS Variable in module bluetooth
INTERCOM_PROFILE Variable in module bluetooth
IOError Class in module exceptions
IRMC_SYNC_CLASS Variable in module bluetooth
IRMC_SYNC_CMD_CLASS Variable in module bluetooth
IRMC_SYNC_CMD_PROFILE Variable in module bluetooth
IRMC_SYNC_PROFILE Variable in module bluetooth
is_valid_address Function in module bluetooth
is_valid_uuid Function in module bluetooth
L2CAP Variable in module bluetooth
LAN_ACCESS_CLASS Variable in module bluetooth
LAN_ACCESS_PROFILE Variable in module bluetooth
listen Method in class bluetooth.BluetoothSocket
lookup_name Function in module bluetooth
makefile Method in class bluetooth.BluetoothSocket
NAP_CLASS Variable in module bluetooth
NAP_PROFILE Variable in module bluetooth
OBEX_FILETRANS_CLASS Variable in module bluetooth
OBEX_FILETRANS_PROFILE Variable in module bluetooth
OBEX_OBJPUSH_CLASS Variable in module bluetooth
OBEX_OBJPUSH_PROFILE Variable in module bluetooth
PANU_CLASS Variable in module bluetooth
PANU_PROFILE Variable in module bluetooth
PNP_INFO_CLASS Variable in module bluetooth
PNP_INFO_PROFILE Variable in module bluetooth
PORT_ANY Variable in module bluetooth
pre_inquiry Method in class bluetooth.DeviceDiscoverer
PRINTING_STATUS_CLASS Variable in module bluetooth
PRINTING_STATUS_PROFILE Variable in module bluetooth
process_event Method in class bluetooth.DeviceDiscoverer
process_inquiry Method in class bluetooth.DeviceDiscoverer
PUBLIC_BROWSE_GROUP Variable in module bluetooth
recv Method in class bluetooth.BluetoothSocket
REFERENCE_PRINTING_CLASS Variable in module bluetooth
REFERENCE_PRINTING_PROFILE Variable in module bluetooth
REFLECTED_UI_CLASS Variable in module bluetooth
REFLECTED_UI_PROFILE Variable in module bluetooth
RFCOMM Variable in module bluetooth
SAP_CLASS Variable in module bluetooth
SAP_PROFILE Variable in module bluetooth
SDP_SERVER_CLASS Variable in module bluetooth
SDP_SERVER_PROFILE Variable in module bluetooth
send Method in class bluetooth.BluetoothSocket
sendall Method in class bluetooth.BluetoothSocket
SERIAL_PORT_CLASS Variable in module bluetooth
SERIAL_PORT_PROFILE Variable in module bluetooth
set_l2cap_mtu Function in module bluetooth
set_packet_timeout Function in module bluetooth
setblocking Method in class bluetooth.BluetoothSocket
setsockopt Method in class bluetooth.BluetoothSocket
settimeout Method in class bluetooth.BluetoothSocket
shutdown Method in class bluetooth.BluetoothSocket
StandardError Class in module exceptions
stop_advertising Function in module bluetooth
UDI_MT_CLASS Variable in module bluetooth
UDI_MT_PROFILE Variable in module bluetooth
UDI_TA_CLASS Variable in module bluetooth
UDI_TA_PROFILE Variable in module bluetooth
UPNP_CLASS Variable in module bluetooth
UPNP_IP_CLASS Variable in module bluetooth
UPNP_IP_PROFILE Variable in module bluetooth
UPNP_L2CAP_CLASS Variable in module bluetooth
UPNP_L2CAP_PROFILE Variable in module bluetooth
UPNP_LAP_CLASS Variable in module bluetooth
UPNP_LAP_PROFILE Variable in module bluetooth
UPNP_PAN_CLASS Variable in module bluetooth
UPNP_PAN_PROFILE Variable in module bluetooth
UPNP_PROFILE Variable in module bluetooth
VIDEO_CONF_CLASS Variable in module bluetooth
VIDEO_CONF_GW_CLASS Variable in module bluetooth
VIDEO_CONF_GW_PROFILE Variable in module bluetooth
VIDEO_CONF_PROFILE Variable in module bluetooth
VIDEO_SINK_CLASS Variable in module bluetooth
VIDEO_SINK_PROFILE Variable in module bluetooth
VIDEO_SOURCE_CLASS Variable in module bluetooth
VIDEO_SOURCE_PROFILE Variable in module bluetooth
WAP_CLASS Variable in module bluetooth
WAP_CLIENT_CLASS Variable in module bluetooth
WAP_CLIENT_PROFILE Variable in module bluetooth
WAP_PROFILE Variable in module bluetooth

Generated by Epydoc 2.1 on Tue May 9 02:23:40 2006 http://epydoc.sf.net
pybluez-0.23/legacy_docs/private/toc-bluetooth-module.html000066400000000000000000000334431360152363700240340ustar00rootroot00000000000000 bluetooth
bluetooth

Classes
BluetoothSocket
DeviceDiscoverer

Exceptions
BluetoothError

Functions
advertise_service
discover_devices
find_service
get_available_port
is_valid_address
is_valid_uuid
lookup_name
set_l2cap_mtu
set_packet_timeout
stop_advertising

Variables
ADVANCED_AUDIO_CLASS
ADVANCED_AUDIO_PROFILE
AUDIO_SINK_CLASS
AUDIO_SINK_PROFILE
AUDIO_SOURCE_CLASS
AUDIO_SOURCE_PROFILE
AV_CLASS
AV_PROFILE
AV_REMOTE_CLASS
AV_REMOTE_PROFILE
AV_REMOTE_TARGET_CLASS
AV_REMOTE_TARGET_PROFILE
BASIC_PRINTING_CLASS
BASIC_PRINTING_PROFILE
BROWSE_GRP_DESC_CLASS
BROWSE_GRP_DESC_PROFILE
CIP_CLASS
CIP_PROFILE
CORDLESS_TELEPHONY_CLASS
CORDLESS_TELEPHONY_PROFILE
DIALUP_NET_CLASS
DIALUP_NET_PROFILE
DIRECT_PRINTING_CLASS
DIRECT_PRINTING_PROFILE
DIRECT_PRT_REFOBJS_CLASS
DIRECT_PRT_REFOBJS_PROFILE
FAX_CLASS
FAX_PROFILE
GENERIC_AUDIO_CLASS
GENERIC_AUDIO_PROFILE
GENERIC_FILETRANS_CLASS
GENERIC_FILETRANS_PROFILE
GENERIC_NETWORKING_CLASS
GENERIC_NETWORKING_PROFILE
GENERIC_TELEPHONY_CLASS
GENERIC_TELEPHONY_PROFILE
GN_CLASS
GN_PROFILE
HANDSFREE_AGW_CLASS
HANDSFREE_AGW_PROFILE
HANDSFREE_CLASS
HANDSFREE_PROFILE
HCR_CLASS
HCR_PRINT_CLASS
HCR_PRINT_PROFILE
HCR_PROFILE
HCR_SCAN_CLASS
HCR_SCAN_PROFILE
HEADSET_AGW_CLASS
HEADSET_AGW_PROFILE
HEADSET_CLASS
HEADSET_PROFILE
HID_CLASS
HID_PROFILE
IMAGING_ARCHIVE_CLASS
IMAGING_ARCHIVE_PROFILE
IMAGING_CLASS
IMAGING_PROFILE
IMAGING_REFOBJS_CLASS
IMAGING_REFOBJS_PROFILE
IMAGING_RESPONDER_CLASS
IMAGING_RESPONDER_PROFILE
INTERCOM_CLASS
INTERCOM_PROFILE
IRMC_SYNC_CLASS
IRMC_SYNC_CMD_CLASS
IRMC_SYNC_CMD_PROFILE
IRMC_SYNC_PROFILE
L2CAP
LAN_ACCESS_CLASS
LAN_ACCESS_PROFILE
NAP_CLASS
NAP_PROFILE
OBEX_FILETRANS_CLASS
OBEX_FILETRANS_PROFILE
OBEX_OBJPUSH_CLASS
OBEX_OBJPUSH_PROFILE
PANU_CLASS
PANU_PROFILE
PNP_INFO_CLASS
PNP_INFO_PROFILE
PORT_ANY
PRINTING_STATUS_CLASS
PRINTING_STATUS_PROFILE
PUBLIC_BROWSE_GROUP
REFERENCE_PRINTING_CLASS
REFERENCE_PRINTING_PROFILE
REFLECTED_UI_CLASS
REFLECTED_UI_PROFILE
RFCOMM
SAP_CLASS
SAP_PROFILE
SDP_SERVER_CLASS
SDP_SERVER_PROFILE
SERIAL_PORT_CLASS
SERIAL_PORT_PROFILE
UDI_MT_CLASS
UDI_MT_PROFILE
UDI_TA_CLASS
UDI_TA_PROFILE
UPNP_CLASS
UPNP_IP_CLASS
UPNP_IP_PROFILE
UPNP_L2CAP_CLASS
UPNP_L2CAP_PROFILE
UPNP_LAP_CLASS
UPNP_LAP_PROFILE
UPNP_PAN_CLASS
UPNP_PAN_PROFILE
UPNP_PROFILE
VIDEO_CONF_CLASS
VIDEO_CONF_GW_CLASS
VIDEO_CONF_GW_PROFILE
VIDEO_CONF_PROFILE
VIDEO_SINK_CLASS
VIDEO_SINK_PROFILE
VIDEO_SOURCE_CLASS
VIDEO_SOURCE_PROFILE
WAP_CLASS
WAP_CLIENT_CLASS
WAP_CLIENT_PROFILE
WAP_PROFILE


[show private | hide private] pybluez-0.23/legacy_docs/private/toc-everything.html000066400000000000000000000334721360152363700227320ustar00rootroot00000000000000 Everything
Everything

All Classes
bluetooth.BluetoothSocket
bluetooth.DeviceDiscoverer

All Exceptions
bluetooth.BluetoothError

All Functions
advertise_service
discover_devices
find_service
get_available_port
is_valid_address
is_valid_uuid
lookup_name
set_l2cap_mtu
set_packet_timeout
stop_advertising

All Variables
ADVANCED_AUDIO_CLASS
ADVANCED_AUDIO_PROFILE
AUDIO_SINK_CLASS
AUDIO_SINK_PROFILE
AUDIO_SOURCE_CLASS
AUDIO_SOURCE_PROFILE
AV_CLASS
AV_PROFILE
AV_REMOTE_CLASS
AV_REMOTE_PROFILE
AV_REMOTE_TARGET_CLASS
AV_REMOTE_TARGET_PROFILE
BASIC_PRINTING_CLASS
BASIC_PRINTING_PROFILE
BROWSE_GRP_DESC_CLASS
BROWSE_GRP_DESC_PROFILE
CIP_CLASS
CIP_PROFILE
CORDLESS_TELEPHONY_CLASS
CORDLESS_TELEPHONY_PROFILE
DIALUP_NET_CLASS
DIALUP_NET_PROFILE
DIRECT_PRINTING_CLASS
DIRECT_PRINTING_PROFILE
DIRECT_PRT_REFOBJS_CLASS
DIRECT_PRT_REFOBJS_PROFILE
FAX_CLASS
FAX_PROFILE
GENERIC_AUDIO_CLASS
GENERIC_AUDIO_PROFILE
GENERIC_FILETRANS_CLASS
GENERIC_FILETRANS_PROFILE
GENERIC_NETWORKING_CLASS
GENERIC_NETWORKING_PROFILE
GENERIC_TELEPHONY_CLASS
GENERIC_TELEPHONY_PROFILE
GN_CLASS
GN_PROFILE
HANDSFREE_AGW_CLASS
HANDSFREE_AGW_PROFILE
HANDSFREE_CLASS
HANDSFREE_PROFILE
HCR_CLASS
HCR_PRINT_CLASS
HCR_PRINT_PROFILE
HCR_PROFILE
HCR_SCAN_CLASS
HCR_SCAN_PROFILE
HEADSET_AGW_CLASS
HEADSET_AGW_PROFILE
HEADSET_CLASS
HEADSET_PROFILE
HID_CLASS
HID_PROFILE
IMAGING_ARCHIVE_CLASS
IMAGING_ARCHIVE_PROFILE
IMAGING_CLASS
IMAGING_PROFILE
IMAGING_REFOBJS_CLASS
IMAGING_REFOBJS_PROFILE
IMAGING_RESPONDER_CLASS
IMAGING_RESPONDER_PROFILE
INTERCOM_CLASS
INTERCOM_PROFILE
IRMC_SYNC_CLASS
IRMC_SYNC_CMD_CLASS
IRMC_SYNC_CMD_PROFILE
IRMC_SYNC_PROFILE
L2CAP
LAN_ACCESS_CLASS
LAN_ACCESS_PROFILE
NAP_CLASS
NAP_PROFILE
OBEX_FILETRANS_CLASS
OBEX_FILETRANS_PROFILE
OBEX_OBJPUSH_CLASS
OBEX_OBJPUSH_PROFILE
PANU_CLASS
PANU_PROFILE
PNP_INFO_CLASS
PNP_INFO_PROFILE
PORT_ANY
PRINTING_STATUS_CLASS
PRINTING_STATUS_PROFILE
PUBLIC_BROWSE_GROUP
REFERENCE_PRINTING_CLASS
REFERENCE_PRINTING_PROFILE
REFLECTED_UI_CLASS
REFLECTED_UI_PROFILE
RFCOMM
SAP_CLASS
SAP_PROFILE
SDP_SERVER_CLASS
SDP_SERVER_PROFILE
SERIAL_PORT_CLASS
SERIAL_PORT_PROFILE
UDI_MT_CLASS
UDI_MT_PROFILE
UDI_TA_CLASS
UDI_TA_PROFILE
UPNP_CLASS
UPNP_IP_CLASS
UPNP_IP_PROFILE
UPNP_L2CAP_CLASS
UPNP_L2CAP_PROFILE
UPNP_LAP_CLASS
UPNP_LAP_PROFILE
UPNP_PAN_CLASS
UPNP_PAN_PROFILE
UPNP_PROFILE
VIDEO_CONF_CLASS
VIDEO_CONF_GW_CLASS
VIDEO_CONF_GW_PROFILE
VIDEO_CONF_PROFILE
VIDEO_SINK_CLASS
VIDEO_SINK_PROFILE
VIDEO_SOURCE_CLASS
VIDEO_SOURCE_PROFILE
WAP_CLASS
WAP_CLIENT_CLASS
WAP_CLIENT_PROFILE
WAP_PROFILE


[show private | hide private] pybluez-0.23/legacy_docs/private/toc.html000066400000000000000000000017321360152363700205420ustar00rootroot00000000000000 Table of Contents
Table of Contents

Everything

Packages

Modules
bluetooth


[show private | hide private] pybluez-0.23/legacy_docs/private/trees.html000066400000000000000000000075421360152363700211040ustar00rootroot00000000000000 Module and Class Hierarchies
[show private | hide private]
[frames | no frames]

Module Hierarchy

  • bluetooth: PyBluez - Bluetooth extension module

Class Hierarchy

Generated by Epydoc 2.1 on Tue May 9 02:23:40 2006 http://epydoc.sf.net
pybluez-0.23/legacy_docs/public/000077500000000000000000000000001360152363700166705ustar00rootroot00000000000000pybluez-0.23/legacy_docs/public/bluetooth-module.html000066400000000000000000003670131360152363700230600ustar00rootroot00000000000000 bluetooth
Module bluetooth
[show private | hide private]
[frames | no frames]

Module bluetooth

PyBluez - Bluetooth extension module
Classes
BluetoothSocket BluetoothSocket
DeviceDiscoverer DeviceDiscoverer

Exceptions
BluetoothError  

Function Summary
  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.
  get_available_port(protocol)
deprecated.
  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
  set_l2cap_mtu(sock, mtu)
set_l2cap_mtu( sock, mtu )
  set_packet_timeout(address, timeout)
set_packet_timeout( address, timeout )
  stop_advertising(sock)
Instructs the local SDP server to stop advertising the service associated with sock.

Variable Summary
str ADVANCED_AUDIO_CLASS = '110d'
tuple ADVANCED_AUDIO_PROFILE = ('110d', 256)
str AUDIO_SINK_CLASS = '110b'
tuple AUDIO_SINK_PROFILE = ('110b', 256)
str AUDIO_SOURCE_CLASS = '110a'
tuple AUDIO_SOURCE_PROFILE = ('110a', 256)
str AV_CLASS = '112c'
tuple AV_PROFILE = ('112c', 256)
str AV_REMOTE_CLASS = '110e'
tuple AV_REMOTE_PROFILE = ('110e', 256)
str AV_REMOTE_TARGET_CLASS = '110c'
tuple AV_REMOTE_TARGET_PROFILE = ('110c', 256)
str BASIC_PRINTING_CLASS = '1122'
tuple BASIC_PRINTING_PROFILE = ('1122', 256)
str BROWSE_GRP_DESC_CLASS = '1001'
tuple BROWSE_GRP_DESC_PROFILE = ('1001', 256)
str CIP_CLASS = '1128'
tuple CIP_PROFILE = ('1128', 256)
str CORDLESS_TELEPHONY_CLASS = '1109'
tuple CORDLESS_TELEPHONY_PROFILE = ('1109', 256)
str DIALUP_NET_CLASS = '1103'
tuple DIALUP_NET_PROFILE = ('1103', 256)
str DIRECT_PRINTING_CLASS = '1118'
tuple DIRECT_PRINTING_PROFILE = ('1118', 256)
str DIRECT_PRT_REFOBJS_CLASS = '1120'
tuple DIRECT_PRT_REFOBJS_PROFILE = ('1120', 256)
str FAX_CLASS = '1111'
tuple FAX_PROFILE = ('1111', 256)
str GENERIC_AUDIO_CLASS = '1203'
tuple GENERIC_AUDIO_PROFILE = ('1203', 256)
str GENERIC_FILETRANS_CLASS = '1202'
tuple GENERIC_FILETRANS_PROFILE = ('1202', 256)
str GENERIC_NETWORKING_CLASS = '1201'
tuple GENERIC_NETWORKING_PROFILE = ('1201', 256)
str GENERIC_TELEPHONY_CLASS = '1204'
tuple GENERIC_TELEPHONY_PROFILE = ('1204', 256)
str GN_CLASS = '1117'
tuple GN_PROFILE = ('1117', 256)
str HANDSFREE_AGW_CLASS = '111f'
tuple HANDSFREE_AGW_PROFILE = ('111f', 256)
str HANDSFREE_CLASS = '111e'
tuple HANDSFREE_PROFILE = ('111e', 256)
str HCR_CLASS = '1125'
str HCR_PRINT_CLASS = '1126'
tuple HCR_PRINT_PROFILE = ('1126', 256)
tuple HCR_PROFILE = ('1127', 256)
str HCR_SCAN_CLASS = '1127'
tuple HCR_SCAN_PROFILE = ('1127', 256)
str HEADSET_AGW_CLASS = '1112'
tuple HEADSET_AGW_PROFILE = ('1112', 256)
str HEADSET_CLASS = '1108'
tuple HEADSET_PROFILE = ('1108', 256)
str HID_CLASS = '1124'
tuple HID_PROFILE = ('1124', 256)
str IMAGING_ARCHIVE_CLASS = '111c'
tuple IMAGING_ARCHIVE_PROFILE = ('111c', 256)
str IMAGING_CLASS = '111a'
tuple IMAGING_PROFILE = ('111a', 256)
str IMAGING_REFOBJS_CLASS = '111d'
tuple IMAGING_REFOBJS_PROFILE = ('111d', 256)
str IMAGING_RESPONDER_CLASS = '111b'
tuple IMAGING_RESPONDER_PROFILE = ('111b', 256)
str INTERCOM_CLASS = '1110'
tuple INTERCOM_PROFILE = ('1110', 256)
str IRMC_SYNC_CLASS = '1104'
str IRMC_SYNC_CMD_CLASS = '1107'
tuple IRMC_SYNC_CMD_PROFILE = ('1107', 256)
tuple IRMC_SYNC_PROFILE = ('1104', 256)
int L2CAP = 3                                                                     
str LAN_ACCESS_CLASS = '1102'
tuple LAN_ACCESS_PROFILE = ('1102', 256)
str NAP_CLASS = '1116'
tuple NAP_PROFILE = ('1116', 256)
str OBEX_FILETRANS_CLASS = '1106'
tuple OBEX_FILETRANS_PROFILE = ('1106', 256)
str OBEX_OBJPUSH_CLASS = '1105'
tuple OBEX_OBJPUSH_PROFILE = ('1105', 256)
str PANU_CLASS = '1115'
tuple PANU_PROFILE = ('1115', 256)
str PNP_INFO_CLASS = '1200'
tuple PNP_INFO_PROFILE = ('1200', 256)
int PORT_ANY = 0                                                                     
str PRINTING_STATUS_CLASS = '1123'
tuple PRINTING_STATUS_PROFILE = ('1123', 256)
str PUBLIC_BROWSE_GROUP = '1002'
str REFERENCE_PRINTING_CLASS = '1119'
tuple REFERENCE_PRINTING_PROFILE = ('1119', 256)
str REFLECTED_UI_CLASS = '1121'
tuple REFLECTED_UI_PROFILE = ('1121', 256)
int RFCOMM = 0                                                                     
str SAP_CLASS = '112d'
tuple SAP_PROFILE = ('112d', 256)
str SDP_SERVER_CLASS = '1000'
tuple SDP_SERVER_PROFILE = ('1000', 256)
str SERIAL_PORT_CLASS = '1101'
tuple SERIAL_PORT_PROFILE = ('1101', 256)
str UDI_MT_CLASS = '112a'
tuple UDI_MT_PROFILE = ('112a', 256)
str UDI_TA_CLASS = '112b'
tuple UDI_TA_PROFILE = ('112b', 256)
str UPNP_CLASS = '1205'
str UPNP_IP_CLASS = '1206'
tuple UPNP_IP_PROFILE = ('1206', 256)
str UPNP_L2CAP_CLASS = '1302'
tuple UPNP_L2CAP_PROFILE = ('1302', 256)
str UPNP_LAP_CLASS = '1301'
tuple UPNP_LAP_PROFILE = ('1301', 256)
str UPNP_PAN_CLASS = '1300'
tuple UPNP_PAN_PROFILE = ('1300', 256)
tuple UPNP_PROFILE = ('1205', 256)
str VIDEO_CONF_CLASS = '110f'
str VIDEO_CONF_GW_CLASS = '1129'
tuple VIDEO_CONF_GW_PROFILE = ('1129', 256)
tuple VIDEO_CONF_PROFILE = ('110f', 256)
str VIDEO_SINK_CLASS = '1304'
tuple VIDEO_SINK_PROFILE = ('1304', 256)
str VIDEO_SOURCE_CLASS = '1303'
tuple VIDEO_SOURCE_PROFILE = ('1303', 256)
str WAP_CLASS = '1113'
str WAP_CLIENT_CLASS = '1114'
tuple WAP_CLIENT_PROFILE = ('1114', 256)
tuple WAP_PROFILE = ('1113', 256)

Function Details

advertise_service(sock, name, service_id='', service_classes=[], profiles=[], provider='', description='')

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)

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.

Variable Details

ADVANCED_AUDIO_CLASS

Type:
str
Value:
'110d'                                                                 

ADVANCED_AUDIO_PROFILE

Type:
tuple
Value:
('110d', 256)                                                          

AUDIO_SINK_CLASS

Type:
str
Value:
'110b'                                                                 

AUDIO_SINK_PROFILE

Type:
tuple
Value:
('110b', 256)                                                          

AUDIO_SOURCE_CLASS

Type:
str
Value:
'110a'                                                                 

AUDIO_SOURCE_PROFILE

Type:
tuple
Value:
('110a', 256)                                                          

AV_CLASS

Type:
str
Value:
'112c'                                                                 

AV_PROFILE

Type:
tuple
Value:
('112c', 256)                                                          

AV_REMOTE_CLASS

Type:
str
Value:
'110e'                                                                 

AV_REMOTE_PROFILE

Type:
tuple
Value:
('110e', 256)                                                          

AV_REMOTE_TARGET_CLASS

Type:
str
Value:
'110c'                                                                 

AV_REMOTE_TARGET_PROFILE

Type:
tuple
Value:
('110c', 256)                                                          

BASIC_PRINTING_CLASS

Type:
str
Value:
'1122'                                                                 

BASIC_PRINTING_PROFILE

Type:
tuple
Value:
('1122', 256)                                                          

BROWSE_GRP_DESC_CLASS

Type:
str
Value:
'1001'                                                                 

BROWSE_GRP_DESC_PROFILE

Type:
tuple
Value:
('1001', 256)                                                          

CIP_CLASS

Type:
str
Value:
'1128'                                                                 

CIP_PROFILE

Type:
tuple
Value:
('1128', 256)                                                          

CORDLESS_TELEPHONY_CLASS

Type:
str
Value:
'1109'                                                                 

CORDLESS_TELEPHONY_PROFILE

Type:
tuple
Value:
('1109', 256)                                                          

DIALUP_NET_CLASS

Type:
str
Value:
'1103'                                                                 

DIALUP_NET_PROFILE

Type:
tuple
Value:
('1103', 256)                                                          

DIRECT_PRINTING_CLASS

Type:
str
Value:
'1118'                                                                 

DIRECT_PRINTING_PROFILE

Type:
tuple
Value:
('1118', 256)                                                          

DIRECT_PRT_REFOBJS_CLASS

Type:
str
Value:
'1120'                                                                 

DIRECT_PRT_REFOBJS_PROFILE

Type:
tuple
Value:
('1120', 256)                                                          

FAX_CLASS

Type:
str
Value:
'1111'                                                                 

FAX_PROFILE

Type:
tuple
Value:
('1111', 256)                                                          

GENERIC_AUDIO_CLASS

Type:
str
Value:
'1203'                                                                 

GENERIC_AUDIO_PROFILE

Type:
tuple
Value:
('1203', 256)                                                          

GENERIC_FILETRANS_CLASS

Type:
str
Value:
'1202'                                                                 

GENERIC_FILETRANS_PROFILE

Type:
tuple
Value:
('1202', 256)                                                          

GENERIC_NETWORKING_CLASS

Type:
str
Value:
'1201'                                                                 

GENERIC_NETWORKING_PROFILE

Type:
tuple
Value:
('1201', 256)                                                          

GENERIC_TELEPHONY_CLASS

Type:
str
Value:
'1204'                                                                 

GENERIC_TELEPHONY_PROFILE

Type:
tuple
Value:
('1204', 256)                                                          

GN_CLASS

Type:
str
Value:
'1117'                                                                 

GN_PROFILE

Type:
tuple
Value:
('1117', 256)                                                          

HANDSFREE_AGW_CLASS

Type:
str
Value:
'111f'                                                                 

HANDSFREE_AGW_PROFILE

Type:
tuple
Value:
('111f', 256)                                                          

HANDSFREE_CLASS

Type:
str
Value:
'111e'                                                                 

HANDSFREE_PROFILE

Type:
tuple
Value:
('111e', 256)                                                          

HCR_CLASS

Type:
str
Value:
'1125'                                                                 

HCR_PRINT_CLASS

Type:
str
Value:
'1126'                                                                 

HCR_PRINT_PROFILE

Type:
tuple
Value:
('1126', 256)                                                          

HCR_PROFILE

Type:
tuple
Value:
('1127', 256)                                                          

HCR_SCAN_CLASS

Type:
str
Value:
'1127'                                                                 

HCR_SCAN_PROFILE

Type:
tuple
Value:
('1127', 256)                                                          

HEADSET_AGW_CLASS

Type:
str
Value:
'1112'                                                                 

HEADSET_AGW_PROFILE

Type:
tuple
Value:
('1112', 256)                                                          

HEADSET_CLASS

Type:
str
Value:
'1108'                                                                 

HEADSET_PROFILE

Type:
tuple
Value:
('1108', 256)                                                          

HID_CLASS

Type:
str
Value:
'1124'                                                                 

HID_PROFILE

Type:
tuple
Value:
('1124', 256)                                                          

IMAGING_ARCHIVE_CLASS

Type:
str
Value:
'111c'                                                                 

IMAGING_ARCHIVE_PROFILE

Type:
tuple
Value:
('111c', 256)                                                          

IMAGING_CLASS

Type:
str
Value:
'111a'                                                                 

IMAGING_PROFILE

Type:
tuple
Value:
('111a', 256)                                                          

IMAGING_REFOBJS_CLASS

Type:
str
Value:
'111d'                                                                 

IMAGING_REFOBJS_PROFILE

Type:
tuple
Value:
('111d', 256)                                                          

IMAGING_RESPONDER_CLASS

Type:
str
Value:
'111b'                                                                 

IMAGING_RESPONDER_PROFILE

Type:
tuple
Value:
('111b', 256)                                                          

INTERCOM_CLASS

Type:
str
Value:
'1110'                                                                 

INTERCOM_PROFILE

Type:
tuple
Value:
('1110', 256)                                                          

IRMC_SYNC_CLASS

Type:
str
Value:
'1104'                                                                 

IRMC_SYNC_CMD_CLASS

Type:
str
Value:
'1107'                                                                 

IRMC_SYNC_CMD_PROFILE

Type:
tuple
Value:
('1107', 256)                                                          

IRMC_SYNC_PROFILE

Type:
tuple
Value:
('1104', 256)                                                          

L2CAP

Type:
int
Value:
3                                                                     

LAN_ACCESS_CLASS

Type:
str
Value:
'1102'                                                                 

LAN_ACCESS_PROFILE

Type:
tuple
Value:
('1102', 256)                                                          

NAP_CLASS

Type:
str
Value:
'1116'                                                                 

NAP_PROFILE

Type:
tuple
Value:
('1116', 256)                                                          

OBEX_FILETRANS_CLASS

Type:
str
Value:
'1106'                                                                 

OBEX_FILETRANS_PROFILE

Type:
tuple
Value:
('1106', 256)                                                          

OBEX_OBJPUSH_CLASS

Type:
str
Value:
'1105'                                                                 

OBEX_OBJPUSH_PROFILE

Type:
tuple
Value:
('1105', 256)                                                          

PANU_CLASS

Type:
str
Value:
'1115'                                                                 

PANU_PROFILE

Type:
tuple
Value:
('1115', 256)                                                          

PNP_INFO_CLASS

Type:
str
Value:
'1200'                                                                 

PNP_INFO_PROFILE

Type:
tuple
Value:
('1200', 256)                                                          

PORT_ANY

Type:
int
Value:
0                                                                     

PRINTING_STATUS_CLASS

Type:
str
Value:
'1123'                                                                 

PRINTING_STATUS_PROFILE

Type:
tuple
Value:
('1123', 256)                                                          

PUBLIC_BROWSE_GROUP

Type:
str
Value:
'1002'                                                                 

REFERENCE_PRINTING_CLASS

Type:
str
Value:
'1119'                                                                 

REFERENCE_PRINTING_PROFILE

Type:
tuple
Value:
('1119', 256)                                                          

REFLECTED_UI_CLASS

Type:
str
Value:
'1121'                                                                 

REFLECTED_UI_PROFILE

Type:
tuple
Value:
('1121', 256)                                                          

RFCOMM

Type:
int
Value:
0                                                                     

SAP_CLASS

Type:
str
Value:
'112d'                                                                 

SAP_PROFILE

Type:
tuple
Value:
('112d', 256)                                                          

SDP_SERVER_CLASS

Type:
str
Value:
'1000'                                                                 

SDP_SERVER_PROFILE

Type:
tuple
Value:
('1000', 256)                                                          

SERIAL_PORT_CLASS

Type:
str
Value:
'1101'                                                                 

SERIAL_PORT_PROFILE

Type:
tuple
Value:
('1101', 256)                                                          

UDI_MT_CLASS

Type:
str
Value:
'112a'                                                                 

UDI_MT_PROFILE

Type:
tuple
Value:
('112a', 256)                                                          

UDI_TA_CLASS

Type:
str
Value:
'112b'                                                                 

UDI_TA_PROFILE

Type:
tuple
Value:
('112b', 256)                                                          

UPNP_CLASS

Type:
str
Value:
'1205'                                                                 

UPNP_IP_CLASS

Type:
str
Value:
'1206'                                                                 

UPNP_IP_PROFILE

Type:
tuple
Value:
('1206', 256)                                                          

UPNP_L2CAP_CLASS

Type:
str
Value:
'1302'                                                                 

UPNP_L2CAP_PROFILE

Type:
tuple
Value:
('1302', 256)                                                          

UPNP_LAP_CLASS

Type:
str
Value:
'1301'                                                                 

UPNP_LAP_PROFILE

Type:
tuple
Value:
('1301', 256)                                                          

UPNP_PAN_CLASS

Type:
str
Value:
'1300'                                                                 

UPNP_PAN_PROFILE

Type:
tuple
Value:
('1300', 256)                                                          

UPNP_PROFILE

Type:
tuple
Value:
('1205', 256)                                                          

VIDEO_CONF_CLASS

Type:
str
Value:
'110f'                                                                 

VIDEO_CONF_GW_CLASS

Type:
str
Value:
'1129'                                                                 

VIDEO_CONF_GW_PROFILE

Type:
tuple
Value:
('1129', 256)                                                          

VIDEO_CONF_PROFILE

Type:
tuple
Value:
('110f', 256)                                                          

VIDEO_SINK_CLASS

Type:
str
Value:
'1304'                                                                 

VIDEO_SINK_PROFILE

Type:
tuple
Value:
('1304', 256)                                                          

VIDEO_SOURCE_CLASS

Type:
str
Value:
'1303'                                                                 

VIDEO_SOURCE_PROFILE

Type:
tuple
Value:
('1303', 256)                                                          

WAP_CLASS

Type:
str
Value:
'1113'                                                                 

WAP_CLIENT_CLASS

Type:
str
Value:
'1114'                                                                 

WAP_CLIENT_PROFILE

Type:
tuple
Value:
('1114', 256)                                                          

WAP_PROFILE

Type:
tuple
Value:
('1113', 256)                                                          

Generated by Epydoc 2.1 on Tue May 9 02:23:39 2006 http://epydoc.sf.net
pybluez-0.23/legacy_docs/public/bluetooth.BluetoothError-class.html000066400000000000000000000114271360152363700256510ustar00rootroot00000000000000 bluetooth.BluetoothError
Module bluetooth :: Class BluetoothError
[show private | hide private]
[frames | no frames]

Class BluetoothError

Exception --+            
            |            
StandardError --+        
                |        
 EnvironmentError --+    
                    |    
              IOError --+
                        |
                       BluetoothError


Method Summary
    Inherited from EnvironmentError
  __init__(...)
  __str__(...)
    Inherited from Exception
  __getitem__(...)

Generated by Epydoc 2.1 on Tue May 9 02:23:39 2006 http://epydoc.sf.net
pybluez-0.23/legacy_docs/public/bluetooth.BluetoothSocket-class.html000066400000000000000000000542101360152363700260050ustar00rootroot00000000000000 bluetooth.BluetoothSocket
Module bluetooth :: Class BluetoothSocket
[show private | hide private]
[frames | no frames]

Class BluetoothSocket


BluetoothSocket

availability: GNU/Linux, Windows XP
Method Summary
  __init__(self, proto, _sock)
Create a new Bluetooth socket that uses the specified transport protocol.
  accept(self)
accept() -> (BluetoothSocket, addrport)
  bind(self, addrport)
bind(addrport) availability: GNU/Linux, Windows XP Bind the socket to a local adapter and port.
  close(self)
close()
  connect(self, addrport)
connect(addrport)
  dup(self)
dup() -> socket object
  fileno(self)
fileno() -> integer
  getpeername(self)
getpeername() -> address info
  getsockname(self)
getsockname() -> address info
  getsockopt(self, level, option, buffersize)
getsockopt(level, option[, buffersize]) -> value
  gettimouet(self, timeout)
gettimeout() -> timeout
  listen(self, backlog)
listen(backlog)
  makefile(self)
makefile([mode[, buffersize]]) -> file object
  recv(self, buffersize, flags)
recv(buffersize[, flags]) -> data
  send(self, data, flags)
send(data[, flags]) -> count
  sendall(self, data, flags)
sendall(data[, flags])
  setblocking(self, blocking)
setblocking(flag)
  setsockopt(self, level, option, value)
setsockopt(level, option, value)
  settimeout(self, timeout)
settimeout(timeout)
  shutdown(self, flag)
shutdown(flag)

Method Details

__init__(self, proto=0, _sock=None)
(Constructor)

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).

Generated by Epydoc 2.1 on Tue May 9 02:23:40 2006 http://epydoc.sf.net
pybluez-0.23/legacy_docs/public/bluetooth.DeviceDiscoverer-class.html000066400000000000000000000271571360152363700261260ustar00rootroot00000000000000 bluetooth.DeviceDiscoverer
Module bluetooth :: Class DeviceDiscoverer
[show private | hide private]
[frames | no frames]

Class DeviceDiscoverer


DeviceDiscoverer

availability: GNU/Linux

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()
Method Summary
  __init__(self)
TODO
  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.

device_discovered(self, address, device_class, 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

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

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.

Generated by Epydoc 2.1 on Tue May 9 02:23:39 2006 http://epydoc.sf.net
pybluez-0.23/legacy_docs/public/epydoc.css000066400000000000000000000104561360152363700206730ustar00rootroot00000000000000 /* 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/public/exceptions.EnvironmentError-class.html000066400000000000000000000107261360152363700263650ustar00rootroot00000000000000 exceptions.EnvironmentError
Module exceptions :: Class EnvironmentError
[show private | hide private]
[frames | no frames]

Class EnvironmentError

Exception --+    
            |    
StandardError --+
                |
               EnvironmentError

Known Subclasses:
IOError

Base class for I/O related errors.
Method Summary
  __init__(...)
  __str__(...)
    Inherited from Exception
  __getitem__(...)

Generated by Epydoc 2.1 on Tue May 9 02:23:39 2006 http://epydoc.sf.net
pybluez-0.23/legacy_docs/public/exceptions.Exception-class.html000066400000000000000000000100411360152363700247730ustar00rootroot00000000000000 exceptions.Exception
Module exceptions :: Class Exception
[show private | hide private]
[frames | no frames]

Class Exception

Known Subclasses:
StandardError

Common base class for all exceptions.
Method Summary
  __init__(...)
  __getitem__(...)
  __str__(...)

Generated by Epydoc 2.1 on Tue May 9 02:23:39 2006 http://epydoc.sf.net
pybluez-0.23/legacy_docs/public/exceptions.IOError-class.html000066400000000000000000000113511360152363700243630ustar00rootroot00000000000000 exceptions.IOError
Module exceptions :: Class IOError
[show private | hide private]
[frames | no frames]

Class IOError

Exception --+        
            |        
StandardError --+    
                |    
 EnvironmentError --+
                    |
                   IOError

Known Subclasses:
BluetoothError

I/O operation failed.
Method Summary
    Inherited from EnvironmentError
  __init__(...)
  __str__(...)
    Inherited from Exception
  __getitem__(...)

Generated by Epydoc 2.1 on Tue May 9 02:23:39 2006 http://epydoc.sf.net
pybluez-0.23/legacy_docs/public/exceptions.StandardError-class.html000066400000000000000000000106631360152363700256210ustar00rootroot00000000000000 exceptions.StandardError
Module exceptions :: Class StandardError
[show private | hide private]
[frames | no frames]

Class StandardError

Exception --+
            |
           StandardError

Known Subclasses:
EnvironmentError

Base class for all standard Python exceptions.
Method Summary
    Inherited from Exception
  __init__(...)
  __getitem__(...)
  __str__(...)

Generated by Epydoc 2.1 on Tue May 9 02:23:39 2006 http://epydoc.sf.net
pybluez-0.23/legacy_docs/public/frames.html000066400000000000000000000005611360152363700210350ustar00rootroot00000000000000 API Documentation pybluez-0.23/legacy_docs/public/help.html000066400000000000000000000230771360152363700205170ustar00rootroot00000000000000 Help
[show private | hide private]
[frames | no frames]

API Documentation

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.

Generated by Epydoc 2.1 on Tue May 9 02:23:40 2006 http://epydoc.sf.net
pybluez-0.23/legacy_docs/public/index.html000066400000000000000000000005611360152363700206670ustar00rootroot00000000000000 API Documentation pybluez-0.23/legacy_docs/public/indices.html000066400000000000000000001152021360152363700211750ustar00rootroot00000000000000 Index
[show private | hide private]
[frames | no frames]

Identifier Index
__getitem__ Method in class exceptions.Exception
__init__ Method in class bluetooth.BluetoothSocket
__init__ Method in class bluetooth.DeviceDiscoverer
__init__ Method in class exceptions.EnvironmentError
__init__ Method in class exceptions.Exception
__str__ Method in class exceptions.EnvironmentError
__str__ Method in class exceptions.Exception
accept Method in class bluetooth.BluetoothSocket
ADVANCED_AUDIO_CLASS Variable in module bluetooth
ADVANCED_AUDIO_PROFILE Variable in module bluetooth
advertise_service Function in module bluetooth
AUDIO_SINK_CLASS Variable in module bluetooth
AUDIO_SINK_PROFILE Variable in module bluetooth
AUDIO_SOURCE_CLASS Variable in module bluetooth
AUDIO_SOURCE_PROFILE Variable in module bluetooth
AV_CLASS Variable in module bluetooth
AV_PROFILE Variable in module bluetooth
AV_REMOTE_CLASS Variable in module bluetooth
AV_REMOTE_PROFILE Variable in module bluetooth
AV_REMOTE_TARGET_CLASS Variable in module bluetooth
AV_REMOTE_TARGET_PROFILE Variable in module bluetooth
BASIC_PRINTING_CLASS Variable in module bluetooth
BASIC_PRINTING_PROFILE Variable in module bluetooth
bind Method in class bluetooth.BluetoothSocket
bluetooth Module
BluetoothError Class in module bluetooth
BluetoothSocket Class in module bluetooth
BROWSE_GRP_DESC_CLASS Variable in module bluetooth
BROWSE_GRP_DESC_PROFILE Variable in module bluetooth
cancel_inquiry Method in class bluetooth.DeviceDiscoverer
CIP_CLASS Variable in module bluetooth
CIP_PROFILE Variable in module bluetooth
close Method in class bluetooth.BluetoothSocket
connect Method in class bluetooth.BluetoothSocket
CORDLESS_TELEPHONY_CLASS Variable in module bluetooth
CORDLESS_TELEPHONY_PROFILE Variable in module bluetooth
device_discovered Method in class bluetooth.DeviceDiscoverer
DeviceDiscoverer Class in module bluetooth
DIALUP_NET_CLASS Variable in module bluetooth
DIALUP_NET_PROFILE Variable in module bluetooth
DIRECT_PRINTING_CLASS Variable in module bluetooth
DIRECT_PRINTING_PROFILE Variable in module bluetooth
DIRECT_PRT_REFOBJS_CLASS Variable in module bluetooth
DIRECT_PRT_REFOBJS_PROFILE Variable in module bluetooth
discover_devices Function in module bluetooth
dup Method in class bluetooth.BluetoothSocket
EnvironmentError Class in module exceptions
Exception Class in module exceptions
FAX_CLASS Variable in module bluetooth
FAX_PROFILE Variable in module bluetooth
fileno Method in class bluetooth.BluetoothSocket
fileno Method in class bluetooth.DeviceDiscoverer
find_devices Method in class bluetooth.DeviceDiscoverer
find_service Function in module bluetooth
GENERIC_AUDIO_CLASS Variable in module bluetooth
GENERIC_AUDIO_PROFILE Variable in module bluetooth
GENERIC_FILETRANS_CLASS Variable in module bluetooth
GENERIC_FILETRANS_PROFILE Variable in module bluetooth
GENERIC_NETWORKING_CLASS Variable in module bluetooth
GENERIC_NETWORKING_PROFILE Variable in module bluetooth
GENERIC_TELEPHONY_CLASS Variable in module bluetooth
GENERIC_TELEPHONY_PROFILE Variable in module bluetooth
get_available_port Function in module bluetooth
getpeername Method in class bluetooth.BluetoothSocket
getsockname Method in class bluetooth.BluetoothSocket
getsockopt Method in class bluetooth.BluetoothSocket
gettimouet Method in class bluetooth.BluetoothSocket
GN_CLASS Variable in module bluetooth
GN_PROFILE Variable in module bluetooth
HANDSFREE_AGW_CLASS Variable in module bluetooth
HANDSFREE_AGW_PROFILE Variable in module bluetooth
HANDSFREE_CLASS Variable in module bluetooth
HANDSFREE_PROFILE Variable in module bluetooth
HCR_CLASS Variable in module bluetooth
HCR_PRINT_CLASS Variable in module bluetooth
HCR_PRINT_PROFILE Variable in module bluetooth
HCR_PROFILE Variable in module bluetooth
HCR_SCAN_CLASS Variable in module bluetooth
HCR_SCAN_PROFILE Variable in module bluetooth
HEADSET_AGW_CLASS Variable in module bluetooth
HEADSET_AGW_PROFILE Variable in module bluetooth
HEADSET_CLASS Variable in module bluetooth
HEADSET_PROFILE Variable in module bluetooth
HID_CLASS Variable in module bluetooth
HID_PROFILE Variable in module bluetooth
IMAGING_ARCHIVE_CLASS Variable in module bluetooth
IMAGING_ARCHIVE_PROFILE Variable in module bluetooth
IMAGING_CLASS Variable in module bluetooth
IMAGING_PROFILE Variable in module bluetooth
IMAGING_REFOBJS_CLASS Variable in module bluetooth
IMAGING_REFOBJS_PROFILE Variable in module bluetooth
IMAGING_RESPONDER_CLASS Variable in module bluetooth
IMAGING_RESPONDER_PROFILE Variable in module bluetooth
inquiry_complete Method in class bluetooth.DeviceDiscoverer
INTERCOM_CLASS Variable in module bluetooth
INTERCOM_PROFILE Variable in module bluetooth
IOError Class in module exceptions
IRMC_SYNC_CLASS Variable in module bluetooth
IRMC_SYNC_CMD_CLASS Variable in module bluetooth
IRMC_SYNC_CMD_PROFILE Variable in module bluetooth
IRMC_SYNC_PROFILE Variable in module bluetooth
is_valid_address Function in module bluetooth
is_valid_uuid Function in module bluetooth
L2CAP Variable in module bluetooth
LAN_ACCESS_CLASS Variable in module bluetooth
LAN_ACCESS_PROFILE Variable in module bluetooth
listen Method in class bluetooth.BluetoothSocket
lookup_name Function in module bluetooth
makefile Method in class bluetooth.BluetoothSocket
NAP_CLASS Variable in module bluetooth
NAP_PROFILE Variable in module bluetooth
OBEX_FILETRANS_CLASS Variable in module bluetooth
OBEX_FILETRANS_PROFILE Variable in module bluetooth
OBEX_OBJPUSH_CLASS Variable in module bluetooth
OBEX_OBJPUSH_PROFILE Variable in module bluetooth
PANU_CLASS Variable in module bluetooth
PANU_PROFILE Variable in module bluetooth
PNP_INFO_CLASS Variable in module bluetooth
PNP_INFO_PROFILE Variable in module bluetooth
PORT_ANY Variable in module bluetooth
pre_inquiry Method in class bluetooth.DeviceDiscoverer
PRINTING_STATUS_CLASS Variable in module bluetooth
PRINTING_STATUS_PROFILE Variable in module bluetooth
process_event Method in class bluetooth.DeviceDiscoverer
process_inquiry Method in class bluetooth.DeviceDiscoverer
PUBLIC_BROWSE_GROUP Variable in module bluetooth
recv Method in class bluetooth.BluetoothSocket
REFERENCE_PRINTING_CLASS Variable in module bluetooth
REFERENCE_PRINTING_PROFILE Variable in module bluetooth
REFLECTED_UI_CLASS Variable in module bluetooth
REFLECTED_UI_PROFILE Variable in module bluetooth
RFCOMM Variable in module bluetooth
SAP_CLASS Variable in module bluetooth
SAP_PROFILE Variable in module bluetooth
SDP_SERVER_CLASS Variable in module bluetooth
SDP_SERVER_PROFILE Variable in module bluetooth
send Method in class bluetooth.BluetoothSocket
sendall Method in class bluetooth.BluetoothSocket
SERIAL_PORT_CLASS Variable in module bluetooth
SERIAL_PORT_PROFILE Variable in module bluetooth
set_l2cap_mtu Function in module bluetooth
set_packet_timeout Function in module bluetooth
setblocking Method in class bluetooth.BluetoothSocket
setsockopt Method in class bluetooth.BluetoothSocket
settimeout Method in class bluetooth.BluetoothSocket
shutdown Method in class bluetooth.BluetoothSocket
StandardError Class in module exceptions
stop_advertising Function in module bluetooth
UDI_MT_CLASS Variable in module bluetooth
UDI_MT_PROFILE Variable in module bluetooth
UDI_TA_CLASS Variable in module bluetooth
UDI_TA_PROFILE Variable in module bluetooth
UPNP_CLASS Variable in module bluetooth
UPNP_IP_CLASS Variable in module bluetooth
UPNP_IP_PROFILE Variable in module bluetooth
UPNP_L2CAP_CLASS Variable in module bluetooth
UPNP_L2CAP_PROFILE Variable in module bluetooth
UPNP_LAP_CLASS Variable in module bluetooth
UPNP_LAP_PROFILE Variable in module bluetooth
UPNP_PAN_CLASS Variable in module bluetooth
UPNP_PAN_PROFILE Variable in module bluetooth
UPNP_PROFILE Variable in module bluetooth
VIDEO_CONF_CLASS Variable in module bluetooth
VIDEO_CONF_GW_CLASS Variable in module bluetooth
VIDEO_CONF_GW_PROFILE Variable in module bluetooth
VIDEO_CONF_PROFILE Variable in module bluetooth
VIDEO_SINK_CLASS Variable in module bluetooth
VIDEO_SINK_PROFILE Variable in module bluetooth
VIDEO_SOURCE_CLASS Variable in module bluetooth
VIDEO_SOURCE_PROFILE Variable in module bluetooth
WAP_CLASS Variable in module bluetooth
WAP_CLIENT_CLASS Variable in module bluetooth
WAP_CLIENT_PROFILE Variable in module bluetooth
WAP_PROFILE Variable in module bluetooth

Generated by Epydoc 2.1 on Tue May 9 02:23:40 2006 http://epydoc.sf.net
pybluez-0.23/legacy_docs/public/toc-bluetooth-module.html000066400000000000000000000334441360152363700236410ustar00rootroot00000000000000 bluetooth
bluetooth

Classes
BluetoothSocket
DeviceDiscoverer

Exceptions
BluetoothError

Functions
advertise_service
discover_devices
find_service
get_available_port
is_valid_address
is_valid_uuid
lookup_name
set_l2cap_mtu
set_packet_timeout
stop_advertising

Variables
ADVANCED_AUDIO_CLASS
ADVANCED_AUDIO_PROFILE
AUDIO_SINK_CLASS
AUDIO_SINK_PROFILE
AUDIO_SOURCE_CLASS
AUDIO_SOURCE_PROFILE
AV_CLASS
AV_PROFILE
AV_REMOTE_CLASS
AV_REMOTE_PROFILE
AV_REMOTE_TARGET_CLASS
AV_REMOTE_TARGET_PROFILE
BASIC_PRINTING_CLASS
BASIC_PRINTING_PROFILE
BROWSE_GRP_DESC_CLASS
BROWSE_GRP_DESC_PROFILE
CIP_CLASS
CIP_PROFILE
CORDLESS_TELEPHONY_CLASS
CORDLESS_TELEPHONY_PROFILE
DIALUP_NET_CLASS
DIALUP_NET_PROFILE
DIRECT_PRINTING_CLASS
DIRECT_PRINTING_PROFILE
DIRECT_PRT_REFOBJS_CLASS
DIRECT_PRT_REFOBJS_PROFILE
FAX_CLASS
FAX_PROFILE
GENERIC_AUDIO_CLASS
GENERIC_AUDIO_PROFILE
GENERIC_FILETRANS_CLASS
GENERIC_FILETRANS_PROFILE
GENERIC_NETWORKING_CLASS
GENERIC_NETWORKING_PROFILE
GENERIC_TELEPHONY_CLASS
GENERIC_TELEPHONY_PROFILE
GN_CLASS
GN_PROFILE
HANDSFREE_AGW_CLASS
HANDSFREE_AGW_PROFILE
HANDSFREE_CLASS
HANDSFREE_PROFILE
HCR_CLASS
HCR_PRINT_CLASS
HCR_PRINT_PROFILE
HCR_PROFILE
HCR_SCAN_CLASS
HCR_SCAN_PROFILE
HEADSET_AGW_CLASS
HEADSET_AGW_PROFILE
HEADSET_CLASS
HEADSET_PROFILE
HID_CLASS
HID_PROFILE
IMAGING_ARCHIVE_CLASS
IMAGING_ARCHIVE_PROFILE
IMAGING_CLASS
IMAGING_PROFILE
IMAGING_REFOBJS_CLASS
IMAGING_REFOBJS_PROFILE
IMAGING_RESPONDER_CLASS
IMAGING_RESPONDER_PROFILE
INTERCOM_CLASS
INTERCOM_PROFILE
IRMC_SYNC_CLASS
IRMC_SYNC_CMD_CLASS
IRMC_SYNC_CMD_PROFILE
IRMC_SYNC_PROFILE
L2CAP
LAN_ACCESS_CLASS
LAN_ACCESS_PROFILE
NAP_CLASS
NAP_PROFILE
OBEX_FILETRANS_CLASS
OBEX_FILETRANS_PROFILE
OBEX_OBJPUSH_CLASS
OBEX_OBJPUSH_PROFILE
PANU_CLASS
PANU_PROFILE
PNP_INFO_CLASS
PNP_INFO_PROFILE
PORT_ANY
PRINTING_STATUS_CLASS
PRINTING_STATUS_PROFILE
PUBLIC_BROWSE_GROUP
REFERENCE_PRINTING_CLASS
REFERENCE_PRINTING_PROFILE
REFLECTED_UI_CLASS
REFLECTED_UI_PROFILE
RFCOMM
SAP_CLASS
SAP_PROFILE
SDP_SERVER_CLASS
SDP_SERVER_PROFILE
SERIAL_PORT_CLASS
SERIAL_PORT_PROFILE
UDI_MT_CLASS
UDI_MT_PROFILE
UDI_TA_CLASS
UDI_TA_PROFILE
UPNP_CLASS
UPNP_IP_CLASS
UPNP_IP_PROFILE
UPNP_L2CAP_CLASS
UPNP_L2CAP_PROFILE
UPNP_LAP_CLASS
UPNP_LAP_PROFILE
UPNP_PAN_CLASS
UPNP_PAN_PROFILE
UPNP_PROFILE
VIDEO_CONF_CLASS
VIDEO_CONF_GW_CLASS
VIDEO_CONF_GW_PROFILE
VIDEO_CONF_PROFILE
VIDEO_SINK_CLASS
VIDEO_SINK_PROFILE
VIDEO_SOURCE_CLASS
VIDEO_SOURCE_PROFILE
WAP_CLASS
WAP_CLIENT_CLASS
WAP_CLIENT_PROFILE
WAP_PROFILE


[show private | hide private] pybluez-0.23/legacy_docs/public/toc-everything.html000066400000000000000000000334731360152363700225370ustar00rootroot00000000000000 Everything
Everything

All Classes
bluetooth.BluetoothSocket
bluetooth.DeviceDiscoverer

All Exceptions
bluetooth.BluetoothError

All Functions
advertise_service
discover_devices
find_service
get_available_port
is_valid_address
is_valid_uuid
lookup_name
set_l2cap_mtu
set_packet_timeout
stop_advertising

All Variables
ADVANCED_AUDIO_CLASS
ADVANCED_AUDIO_PROFILE
AUDIO_SINK_CLASS
AUDIO_SINK_PROFILE
AUDIO_SOURCE_CLASS
AUDIO_SOURCE_PROFILE
AV_CLASS
AV_PROFILE
AV_REMOTE_CLASS
AV_REMOTE_PROFILE
AV_REMOTE_TARGET_CLASS
AV_REMOTE_TARGET_PROFILE
BASIC_PRINTING_CLASS
BASIC_PRINTING_PROFILE
BROWSE_GRP_DESC_CLASS
BROWSE_GRP_DESC_PROFILE
CIP_CLASS
CIP_PROFILE
CORDLESS_TELEPHONY_CLASS
CORDLESS_TELEPHONY_PROFILE
DIALUP_NET_CLASS
DIALUP_NET_PROFILE
DIRECT_PRINTING_CLASS
DIRECT_PRINTING_PROFILE
DIRECT_PRT_REFOBJS_CLASS
DIRECT_PRT_REFOBJS_PROFILE
FAX_CLASS
FAX_PROFILE
GENERIC_AUDIO_CLASS
GENERIC_AUDIO_PROFILE
GENERIC_FILETRANS_CLASS
GENERIC_FILETRANS_PROFILE
GENERIC_NETWORKING_CLASS
GENERIC_NETWORKING_PROFILE
GENERIC_TELEPHONY_CLASS
GENERIC_TELEPHONY_PROFILE
GN_CLASS
GN_PROFILE
HANDSFREE_AGW_CLASS
HANDSFREE_AGW_PROFILE
HANDSFREE_CLASS
HANDSFREE_PROFILE
HCR_CLASS
HCR_PRINT_CLASS
HCR_PRINT_PROFILE
HCR_PROFILE
HCR_SCAN_CLASS
HCR_SCAN_PROFILE
HEADSET_AGW_CLASS
HEADSET_AGW_PROFILE
HEADSET_CLASS
HEADSET_PROFILE
HID_CLASS
HID_PROFILE
IMAGING_ARCHIVE_CLASS
IMAGING_ARCHIVE_PROFILE
IMAGING_CLASS
IMAGING_PROFILE
IMAGING_REFOBJS_CLASS
IMAGING_REFOBJS_PROFILE
IMAGING_RESPONDER_CLASS
IMAGING_RESPONDER_PROFILE
INTERCOM_CLASS
INTERCOM_PROFILE
IRMC_SYNC_CLASS
IRMC_SYNC_CMD_CLASS
IRMC_SYNC_CMD_PROFILE
IRMC_SYNC_PROFILE
L2CAP
LAN_ACCESS_CLASS
LAN_ACCESS_PROFILE
NAP_CLASS
NAP_PROFILE
OBEX_FILETRANS_CLASS
OBEX_FILETRANS_PROFILE
OBEX_OBJPUSH_CLASS
OBEX_OBJPUSH_PROFILE
PANU_CLASS
PANU_PROFILE
PNP_INFO_CLASS
PNP_INFO_PROFILE
PORT_ANY
PRINTING_STATUS_CLASS
PRINTING_STATUS_PROFILE
PUBLIC_BROWSE_GROUP
REFERENCE_PRINTING_CLASS
REFERENCE_PRINTING_PROFILE
REFLECTED_UI_CLASS
REFLECTED_UI_PROFILE
RFCOMM
SAP_CLASS
SAP_PROFILE
SDP_SERVER_CLASS
SDP_SERVER_PROFILE
SERIAL_PORT_CLASS
SERIAL_PORT_PROFILE
UDI_MT_CLASS
UDI_MT_PROFILE
UDI_TA_CLASS
UDI_TA_PROFILE
UPNP_CLASS
UPNP_IP_CLASS
UPNP_IP_PROFILE
UPNP_L2CAP_CLASS
UPNP_L2CAP_PROFILE
UPNP_LAP_CLASS
UPNP_LAP_PROFILE
UPNP_PAN_CLASS
UPNP_PAN_PROFILE
UPNP_PROFILE
VIDEO_CONF_CLASS
VIDEO_CONF_GW_CLASS
VIDEO_CONF_GW_PROFILE
VIDEO_CONF_PROFILE
VIDEO_SINK_CLASS
VIDEO_SINK_PROFILE
VIDEO_SOURCE_CLASS
VIDEO_SOURCE_PROFILE
WAP_CLASS
WAP_CLIENT_CLASS
WAP_CLIENT_PROFILE
WAP_PROFILE


[show private | hide private] pybluez-0.23/legacy_docs/public/toc.html000066400000000000000000000017331360152363700203470ustar00rootroot00000000000000 Table of Contents
Table of Contents

Everything

Packages

Modules
bluetooth


[show private | hide private] pybluez-0.23/legacy_docs/public/trees.html000066400000000000000000000075431360152363700207110ustar00rootroot00000000000000 Module and Class Hierarchies
[show private | hide private]
[frames | no frames]

Module Hierarchy

  • bluetooth: PyBluez - Bluetooth extension module

Class Hierarchy

Generated by Epydoc 2.1 on Tue May 9 02:23:40 2006 http://epydoc.sf.net
pybluez-0.23/macos/000077500000000000000000000000001360152363700142405ustar00rootroot00000000000000pybluez-0.23/macos/LightAquaBlue/000077500000000000000000000000001360152363700167275ustar00rootroot00000000000000pybluez-0.23/macos/LightAquaBlue/BBBluetoothChannelDelegate.h000066400000000000000000000031661360152363700242030ustar00rootroot00000000000000/* * 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.m000066400000000000000000000054721360152363700242120ustar00rootroot00000000000000/* * 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.h000066400000000000000000000300441360152363700230670ustar00rootroot00000000000000/* * 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.m000066400000000000000000000276361360152363700231110ustar00rootroot00000000000000/* * 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.h000066400000000000000000000233531360152363700231240ustar00rootroot00000000000000/* * 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.m000066400000000000000000000205601360152363700231260ustar00rootroot00000000000000/* * 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.h000066400000000000000000000026501360152363700214610ustar00rootroot00000000000000/* * 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.m000066400000000000000000000025531360152363700214700ustar00rootroot00000000000000/* * 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.h000066400000000000000000000116041360152363700231420ustar00rootroot00000000000000/* * 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.m000066400000000000000000000230421360152363700231460ustar00rootroot00000000000000/* * 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.h000066400000000000000000000114421360152363700216300ustar00rootroot00000000000000/* * 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.m000077500000000000000000000277641360152363700216560ustar00rootroot00000000000000/* * 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.h000066400000000000000000000066621360152363700214240ustar00rootroot00000000000000/* * 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.m000066400000000000000000000565771360152363700214430ustar00rootroot00000000000000/* * 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.h000066400000000000000000000064461360152363700227220ustar00rootroot00000000000000/* * 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.m000066400000000000000000000765101360152363700227260ustar00rootroot00000000000000/* * 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.h000066400000000000000000000036171360152363700215670ustar00rootroot00000000000000/* * 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.m000066400000000000000000000121741360152363700215720ustar00rootroot00000000000000/* * 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.h000066400000000000000000000046431360152363700227440ustar00rootroot00000000000000/* * 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.m000066400000000000000000000117571360152363700227550ustar00rootroot00000000000000/* * 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.h000066400000000000000000000025041360152363700234320ustar00rootroot00000000000000/* * 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.m000066400000000000000000000042041360152363700234360ustar00rootroot00000000000000/* * 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.h000066400000000000000000000024341360152363700236350ustar00rootroot00000000000000/* * 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.m000066400000000000000000000037371360152363700236510ustar00rootroot00000000000000/* * 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/000077500000000000000000000000001360152363700215205ustar00rootroot00000000000000pybluez-0.23/macos/LightAquaBlue/BridgeSupport/LightAquaBlue.bridgesupport000066400000000000000000000071741360152363700270330ustar00rootroot00000000000000 pybluez-0.23/macos/LightAquaBlue/English.lproj/000077500000000000000000000000001360152363700214455ustar00rootroot00000000000000pybluez-0.23/macos/LightAquaBlue/English.lproj/InfoPlist.strings000066400000000000000000000000001360152363700247550ustar00rootroot00000000000000pybluez-0.23/macos/LightAquaBlue/Info.plist000066400000000000000000000014071360152363700207010ustar00rootroot00000000000000 CFBundleDevelopmentRegion English CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIconFile CFBundleIdentifier $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType FMWK CFBundleSignature ???? CFBundleVersion 1.0 NSPrincipalClass pybluez-0.23/macos/LightAquaBlue/LightAquaBlue.h000066400000000000000000000010511360152363700215640ustar00rootroot00000000000000#import #import #import #import #import #import #import #import #import #import #import #import pybluez-0.23/macos/LightAquaBlue/LightAquaBlue.xcodeproj/000077500000000000000000000000001360152363700234125ustar00rootroot00000000000000pybluez-0.23/macos/LightAquaBlue/LightAquaBlue.xcodeproj/blam.mode1v3000066400000000000000000001166741360152363700255440ustar00rootroot00000000000000 ActivePerspectiveName Project AllowedModules BundleLoadPath MaxInstances n Module PBXSmartGroupTreeModule Name Groups and Files Outline View BundleLoadPath MaxInstances n Module PBXNavigatorGroup Name Editor BundleLoadPath MaxInstances n Module XCTaskListModule Name Task List BundleLoadPath MaxInstances n Module XCDetailModule Name File and Smart Group Detail Viewer BundleLoadPath MaxInstances 1 Module PBXBuildResultsModule Name Detailed Build Results Viewer BundleLoadPath MaxInstances 1 Module PBXProjectFindModule Name Project Batch Find Tool BundleLoadPath MaxInstances n Module XCProjectFormatConflictsModule Name Project Format Conflicts List BundleLoadPath MaxInstances n Module PBXBookmarksModule Name Bookmarks Tool BundleLoadPath MaxInstances n Module PBXClassBrowserModule Name Class Browser BundleLoadPath MaxInstances n Module PBXCVSModule Name Source Code Control Tool BundleLoadPath MaxInstances n Module PBXDebugBreakpointsModule Name Debug Breakpoints Tool BundleLoadPath MaxInstances n Module XCDockableInspector Name Inspector BundleLoadPath MaxInstances n Module PBXOpenQuicklyModule Name Open Quickly Tool BundleLoadPath MaxInstances 1 Module PBXDebugSessionModule Name Debugger BundleLoadPath MaxInstances 1 Module PBXDebugCLIModule Name Debug Console BundleLoadPath MaxInstances n Module XCSnapshotModule Name Snapshots Tool BundlePath /Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources Description DefaultDescriptionKey DockingSystemVisible Extension mode1v3 FavBarConfig PBXProjectModuleGUID 669281F20E296950008CB8B0 XCBarModuleItemNames XCBarModuleItems FirstTimeWindowDisplayed Identifier com.apple.perspectives.project.mode1v3 MajorVersion 33 MinorVersion 0 Name Default Notifications OpenEditors PerspectiveWidths -1 -1 Perspectives ChosenToolbarItems active-target-popup active-buildstyle-popup action NSToolbarFlexibleSpaceItem buildOrClean build-and-goOrGo com.apple.ide.PBXToolbarStopButton get-info toggle-editor NSToolbarFlexibleSpaceItem com.apple.pbx.toolbar.searchfield ControllerClassBaseName IconName WindowOfProjectWithEditor Identifier perspective.project IsVertical Layout ContentConfiguration PBXBottomSmartGroupGIDs 1C37FBAC04509CD000000102 1C37FAAC04509CD000000102 1C08E77C0454961000C914BD 1C37FABC05509CD000000102 1C37FABC05539CD112110102 E2644B35053B69B200211256 1C37FABC04509CD000100104 1CC0EA4004350EF90044410B 1CC0EA4004350EF90041110B PBXProjectModuleGUID 1CE0B1FE06471DED0097A5F4 PBXProjectModuleLabel Files PBXProjectStructureProvided yes PBXSmartGroupTreeModuleColumnData PBXSmartGroupTreeModuleColumnWidthsKey 186 PBXSmartGroupTreeModuleColumnsKey_v4 MainColumn PBXSmartGroupTreeModuleOutlineStateKey_v7 PBXSmartGroupTreeModuleOutlineStateExpansionKey 0867D691FE84028FC02AAC07 089C1665FE841158C02AAC07 0867D69AFE84028FC02AAC07 1058C7B2FEA5585E11CA2CBB 034768DFFF38A50411DB9C8B 1C37FABC05509CD000000102 PBXSmartGroupTreeModuleOutlineStateSelectionKey 5 4 0 PBXSmartGroupTreeModuleOutlineStateVisibleRectKey {{0, 0}, {186, 533}} PBXTopSmartGroupGIDs XCIncludePerspectivesSwitch XCSharingToken com.apple.Xcode.GFSharingToken GeometryConfiguration Frame {{0, 0}, {203, 551}} GroupTreeTableConfiguration MainColumn 186 RubberWindowFrame 149 115 922 592 0 0 1280 778 Module PBXSmartGroupTreeModule Proportion 203pt Dock ContentConfiguration PBXProjectModuleGUID 1CE0B20306471E060097A5F4 PBXProjectModuleLabel LightAquaBlue.bridgesupport PBXSplitModuleInNavigatorKey Split0 PBXProjectModuleGUID 1CE0B20406471E060097A5F4 PBXProjectModuleLabel LightAquaBlue.bridgesupport _historyCapacity 0 bookmark 6692821F0E468045008CB8B0 history 669282050E297147008CB8B0 669282060E297147008CB8B0 669282070E297147008CB8B0 669282080E297147008CB8B0 6692821B0E468045008CB8B0 6692821C0E468045008CB8B0 prevStack 6692820A0E297147008CB8B0 6692820B0E297147008CB8B0 6692820C0E297147008CB8B0 6692820D0E297147008CB8B0 6692820E0E297147008CB8B0 6692820F0E297147008CB8B0 669282100E297147008CB8B0 669282110E297147008CB8B0 669282120E297147008CB8B0 669282130E297147008CB8B0 669282140E297147008CB8B0 669282150E297147008CB8B0 6692821E0E468045008CB8B0 SplitCount 1 StatusBarVisibility GeometryConfiguration Frame {{0, 0}, {714, 332}} RubberWindowFrame 149 115 922 592 0 0 1280 778 Module PBXNavigatorGroup Proportion 332pt BecomeActive ContentConfiguration PBXProjectModuleGUID 1CE0B20506471E060097A5F4 PBXProjectModuleLabel Detail GeometryConfiguration Frame {{0, 337}, {714, 214}} RubberWindowFrame 149 115 922 592 0 0 1280 778 Module XCDetailModule Proportion 214pt Proportion 714pt Name Project ServiceClasses XCModuleDock PBXSmartGroupTreeModule XCModuleDock PBXNavigatorGroup XCDetailModule TableOfContents 669282020E296AB4008CB8B0 1CE0B1FE06471DED0097A5F4 669282030E296AB4008CB8B0 1CE0B20306471E060097A5F4 1CE0B20506471E060097A5F4 ToolbarConfiguration xcode.toolbar.config.defaultV3 ControllerClassBaseName IconName WindowOfProject Identifier perspective.morph IsVertical 0 Layout BecomeActive 1 ContentConfiguration PBXBottomSmartGroupGIDs 1C37FBAC04509CD000000102 1C37FAAC04509CD000000102 1C08E77C0454961000C914BD 1C37FABC05509CD000000102 1C37FABC05539CD112110102 E2644B35053B69B200211256 1C37FABC04509CD000100104 1CC0EA4004350EF90044410B 1CC0EA4004350EF90041110B PBXProjectModuleGUID 11E0B1FE06471DED0097A5F4 PBXProjectModuleLabel Files PBXProjectStructureProvided yes PBXSmartGroupTreeModuleColumnData PBXSmartGroupTreeModuleColumnWidthsKey 186 PBXSmartGroupTreeModuleColumnsKey_v4 MainColumn PBXSmartGroupTreeModuleOutlineStateKey_v7 PBXSmartGroupTreeModuleOutlineStateExpansionKey 29B97314FDCFA39411CA2CEA 1C37FABC05509CD000000102 PBXSmartGroupTreeModuleOutlineStateSelectionKey 0 PBXSmartGroupTreeModuleOutlineStateVisibleRectKey {{0, 0}, {186, 337}} PBXTopSmartGroupGIDs XCIncludePerspectivesSwitch 1 XCSharingToken com.apple.Xcode.GFSharingToken GeometryConfiguration Frame {{0, 0}, {203, 355}} GroupTreeTableConfiguration MainColumn 186 RubberWindowFrame 373 269 690 397 0 0 1440 878 Module PBXSmartGroupTreeModule Proportion 100% Name Morph PreferredWidth 300 ServiceClasses XCModuleDock PBXSmartGroupTreeModule TableOfContents 11E0B1FE06471DED0097A5F4 ToolbarConfiguration xcode.toolbar.config.default.shortV3 PerspectivesBarVisible ShelfIsVisible SourceDescription file at '/Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources/XCPerspectivesSpecificationMode1.xcperspec' StatusbarIsVisible TimeStamp 0.0 ToolbarDisplayMode 1 ToolbarIsVisible ToolbarSizeMode 1 Type Perspectives UpdateMessage The 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 '%@'? WindowJustification 5 WindowOrderList /Users/blam/code/lightblue/trunk/src/mac/LightAquaBlue/LightAquaBlue.xcodeproj WindowString 149 115 922 592 0 0 1280 778 WindowToolsV3 Identifier windowTool.build Layout Dock ContentConfiguration PBXProjectModuleGUID 1CD0528F0623707200166675 PBXProjectModuleLabel <No Editor> PBXSplitModuleInNavigatorKey Split0 PBXProjectModuleGUID 1CD052900623707200166675 SplitCount 1 StatusBarVisibility 1 GeometryConfiguration Frame {{0, 0}, {500, 215}} RubberWindowFrame 192 257 500 500 0 0 1280 1002 Module PBXNavigatorGroup Proportion 218pt BecomeActive 1 ContentConfiguration PBXProjectModuleGUID XCMainBuildResultsModuleGUID PBXProjectModuleLabel Build GeometryConfiguration Frame {{0, 222}, {500, 236}} RubberWindowFrame 192 257 500 500 0 0 1280 1002 Module PBXBuildResultsModule Proportion 236pt Proportion 458pt Name Build Results ServiceClasses PBXBuildResultsModule StatusbarIsVisible 1 TableOfContents 1C78EAA5065D492600B07095 1C78EAA6065D492600B07095 1CD0528F0623707200166675 XCMainBuildResultsModuleGUID ToolbarConfiguration xcode.toolbar.config.buildV3 WindowString 192 257 500 500 0 0 1280 1002 Identifier windowTool.debugger Layout Dock ContentConfiguration Debugger HorizontalSplitView _collapsingFrameDimension 0.0 _indexOfCollapsedView 0 _percentageOfCollapsedView 0.0 isCollapsed yes sizes {{0, 0}, {317, 164}} {{317, 0}, {377, 164}} VerticalSplitView _collapsingFrameDimension 0.0 _indexOfCollapsedView 0 _percentageOfCollapsedView 0.0 isCollapsed yes sizes {{0, 0}, {694, 164}} {{0, 164}, {694, 216}} LauncherConfigVersion 8 PBXProjectModuleGUID 1C162984064C10D400B95A72 PBXProjectModuleLabel Debug - GLUTExamples (Underwater) GeometryConfiguration DebugConsoleDrawerSize {100, 120} DebugConsoleVisible None DebugConsoleWindowFrame {{200, 200}, {500, 300}} DebugSTDIOWindowFrame {{200, 200}, {500, 300}} Frame {{0, 0}, {694, 380}} RubberWindowFrame 321 238 694 422 0 0 1440 878 Module PBXDebugSessionModule Proportion 100% Proportion 100% Name Debugger ServiceClasses PBXDebugSessionModule StatusbarIsVisible 1 TableOfContents 1CD10A99069EF8BA00B06720 1C0AD2AB069F1E9B00FABCE6 1C162984064C10D400B95A72 1C0AD2AC069F1E9B00FABCE6 ToolbarConfiguration xcode.toolbar.config.debugV3 WindowString 321 238 694 422 0 0 1440 878 WindowToolGUID 1CD10A99069EF8BA00B06720 WindowToolIsVisible 0 Identifier windowTool.find Layout Dock Dock ContentConfiguration PBXProjectModuleGUID 1CDD528C0622207200134675 PBXProjectModuleLabel <No Editor> PBXSplitModuleInNavigatorKey Split0 PBXProjectModuleGUID 1CD0528D0623707200166675 SplitCount 1 StatusBarVisibility 1 GeometryConfiguration Frame {{0, 0}, {781, 167}} RubberWindowFrame 62 385 781 470 0 0 1440 878 Module PBXNavigatorGroup Proportion 781pt Proportion 50% BecomeActive 1 ContentConfiguration PBXProjectModuleGUID 1CD0528E0623707200166675 PBXProjectModuleLabel Project Find GeometryConfiguration Frame {{8, 0}, {773, 254}} RubberWindowFrame 62 385 781 470 0 0 1440 878 Module PBXProjectFindModule Proportion 50% Proportion 428pt Name Project Find ServiceClasses PBXProjectFindModule StatusbarIsVisible 1 TableOfContents 1C530D57069F1CE1000CFCEE 1C530D58069F1CE1000CFCEE 1C530D59069F1CE1000CFCEE 1CDD528C0622207200134675 1C530D5A069F1CE1000CFCEE 1CE0B1FE06471DED0097A5F4 1CD0528E0623707200166675 WindowString 62 385 781 470 0 0 1440 878 WindowToolGUID 1C530D57069F1CE1000CFCEE WindowToolIsVisible 0 Identifier MENUSEPARATOR Identifier windowTool.debuggerConsole Layout Dock BecomeActive 1 ContentConfiguration PBXProjectModuleGUID 1C78EAAC065D492600B07095 PBXProjectModuleLabel Debugger Console GeometryConfiguration Frame {{0, 0}, {650, 250}} RubberWindowFrame 516 632 650 250 0 0 1680 1027 Module PBXDebugCLIModule Proportion 209pt Proportion 209pt Name Debugger Console ServiceClasses PBXDebugCLIModule StatusbarIsVisible 1 TableOfContents 1C78EAAD065D492600B07095 1C78EAAE065D492600B07095 1C78EAAC065D492600B07095 ToolbarConfiguration xcode.toolbar.config.consoleV3 WindowString 650 41 650 250 0 0 1280 1002 WindowToolGUID 1C78EAAD065D492600B07095 WindowToolIsVisible 0 Identifier windowTool.snapshots Layout Dock Module XCSnapshotModule Proportion 100% Proportion 100% Name Snapshots ServiceClasses XCSnapshotModule StatusbarIsVisible Yes ToolbarConfiguration xcode.toolbar.config.snapshots WindowString 315 824 300 550 0 0 1440 878 WindowToolIsVisible Yes Identifier windowTool.scm Layout Dock ContentConfiguration PBXProjectModuleGUID 1C78EAB2065D492600B07095 PBXProjectModuleLabel <No Editor> PBXSplitModuleInNavigatorKey Split0 PBXProjectModuleGUID 1C78EAB3065D492600B07095 SplitCount 1 StatusBarVisibility 1 GeometryConfiguration Frame {{0, 0}, {452, 0}} RubberWindowFrame 743 379 452 308 0 0 1280 1002 Module PBXNavigatorGroup Proportion 0pt BecomeActive 1 ContentConfiguration PBXProjectModuleGUID 1CD052920623707200166675 PBXProjectModuleLabel SCM GeometryConfiguration ConsoleFrame {{0, 259}, {452, 0}} Frame {{0, 7}, {452, 259}} RubberWindowFrame 743 379 452 308 0 0 1280 1002 TableConfiguration Status 30 FileName 199 Path 197.09500122070312 TableFrame {{0, 0}, {452, 250}} Module PBXCVSModule Proportion 262pt Proportion 266pt Name SCM ServiceClasses PBXCVSModule StatusbarIsVisible 1 TableOfContents 1C78EAB4065D492600B07095 1C78EAB5065D492600B07095 1C78EAB2065D492600B07095 1CD052920623707200166675 ToolbarConfiguration xcode.toolbar.config.scm WindowString 743 379 452 308 0 0 1280 1002 Identifier windowTool.breakpoints IsVertical 0 Layout Dock BecomeActive 1 ContentConfiguration PBXBottomSmartGroupGIDs 1C77FABC04509CD000000102 PBXProjectModuleGUID 1CE0B1FE06471DED0097A5F4 PBXProjectModuleLabel Files PBXProjectStructureProvided no PBXSmartGroupTreeModuleColumnData PBXSmartGroupTreeModuleColumnWidthsKey 168 PBXSmartGroupTreeModuleColumnsKey_v4 MainColumn PBXSmartGroupTreeModuleOutlineStateKey_v7 PBXSmartGroupTreeModuleOutlineStateExpansionKey 1C77FABC04509CD000000102 PBXSmartGroupTreeModuleOutlineStateSelectionKey 0 PBXSmartGroupTreeModuleOutlineStateVisibleRectKey {{0, 0}, {168, 350}} PBXTopSmartGroupGIDs XCIncludePerspectivesSwitch 0 GeometryConfiguration Frame {{0, 0}, {185, 368}} GroupTreeTableConfiguration MainColumn 168 RubberWindowFrame 315 424 744 409 0 0 1440 878 Module PBXSmartGroupTreeModule Proportion 185pt ContentConfiguration PBXProjectModuleGUID 1CA1AED706398EBD00589147 PBXProjectModuleLabel Detail GeometryConfiguration Frame {{190, 0}, {554, 368}} RubberWindowFrame 315 424 744 409 0 0 1440 878 Module XCDetailModule Proportion 554pt Proportion 368pt MajorVersion 3 MinorVersion 0 Name Breakpoints ServiceClasses PBXSmartGroupTreeModule XCDetailModule StatusbarIsVisible 1 TableOfContents 1CDDB66807F98D9800BB5817 1CDDB66907F98D9800BB5817 1CE0B1FE06471DED0097A5F4 1CA1AED706398EBD00589147 ToolbarConfiguration xcode.toolbar.config.breakpointsV3 WindowString 315 424 744 409 0 0 1440 878 WindowToolGUID 1CDDB66807F98D9800BB5817 WindowToolIsVisible 1 Identifier windowTool.debugAnimator Layout Dock Module PBXNavigatorGroup Proportion 100% Proportion 100% Name Debug Visualizer ServiceClasses PBXNavigatorGroup StatusbarIsVisible 1 ToolbarConfiguration xcode.toolbar.config.debugAnimatorV3 WindowString 100 100 700 500 0 0 1280 1002 Identifier windowTool.bookmarks Layout Dock Module PBXBookmarksModule Proportion 100% Proportion 100% Name Bookmarks ServiceClasses PBXBookmarksModule StatusbarIsVisible 0 WindowString 538 42 401 187 0 0 1280 1002 Identifier windowTool.projectFormatConflicts Layout Dock Module XCProjectFormatConflictsModule Proportion 100% Proportion 100% Name Project Format Conflicts ServiceClasses XCProjectFormatConflictsModule StatusbarIsVisible 0 WindowContentMinSize 450 300 WindowString 50 850 472 307 0 0 1440 877 Identifier windowTool.classBrowser Layout Dock BecomeActive 1 ContentConfiguration OptionsSetName Hierarchy, all classes PBXProjectModuleGUID 1CA6456E063B45B4001379D8 PBXProjectModuleLabel Class Browser - NSObject GeometryConfiguration ClassesFrame {{0, 0}, {374, 96}} ClassesTreeTableConfiguration PBXClassNameColumnIdentifier 208 PBXClassBookColumnIdentifier 22 Frame {{0, 0}, {630, 331}} MembersFrame {{0, 105}, {374, 395}} MembersTreeTableConfiguration PBXMemberTypeIconColumnIdentifier 22 PBXMemberNameColumnIdentifier 216 PBXMemberTypeColumnIdentifier 97 PBXMemberBookColumnIdentifier 22 PBXModuleWindowStatusBarHidden2 1 RubberWindowFrame 385 179 630 352 0 0 1440 878 Module PBXClassBrowserModule Proportion 332pt Proportion 332pt Name Class Browser ServiceClasses PBXClassBrowserModule StatusbarIsVisible 0 TableOfContents 1C0AD2AF069F1E9B00FABCE6 1C0AD2B0069F1E9B00FABCE6 1CA6456E063B45B4001379D8 ToolbarConfiguration xcode.toolbar.config.classbrowser WindowString 385 179 630 352 0 0 1440 878 WindowToolGUID 1C0AD2AF069F1E9B00FABCE6 WindowToolIsVisible 0 Identifier windowTool.refactoring IncludeInToolsMenu 0 Layout Dock BecomeActive 1 GeometryConfiguration Frame {0, 0}, {500, 335} RubberWindowFrame {0, 0}, {500, 335} Module XCRefactoringModule Proportion 100% Proportion 100% Name Refactoring ServiceClasses XCRefactoringModule WindowString 200 200 500 356 0 0 1920 1200 pybluez-0.23/macos/LightAquaBlue/LightAquaBlue.xcodeproj/project.pbxproj000066400000000000000000000625741360152363700265040ustar00rootroot00000000000000// !$*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/000077500000000000000000000000001360152363700274105ustar00rootroot00000000000000contents.xcworkspacedata000066400000000000000000000002071360152363700342720ustar00rootroot00000000000000pybluez-0.23/macos/LightAquaBlue/LightAquaBlue.xcodeproj/project.xcworkspace pybluez-0.23/macos/LightAquaBlue/LightAquaBlue.xcodeproj/project.xcworkspace/xcshareddata/000077500000000000000000000000001360152363700320435ustar00rootroot00000000000000IDEWorkspaceChecks.plist000066400000000000000000000003561360152363700364460ustar00rootroot00000000000000pybluez-0.23/macos/LightAquaBlue/LightAquaBlue.xcodeproj/project.xcworkspace/xcshareddata IDEDidComputeMac32BitWarning WorkspaceSettings.xcsettings000066400000000000000000000002651360152363700375630ustar00rootroot00000000000000pybluez-0.23/macos/LightAquaBlue/LightAquaBlue.xcodeproj/project.xcworkspace/xcshareddata pybluez-0.23/macos/LightAquaBlue/LightAquaBlue_Prefix.pch000066400000000000000000000002361360152363700234300ustar00rootroot00000000000000// // Prefix header for all source files of the 'LightAquaBlue' target in the 'LightAquaBlue' project. // #ifdef __OBJC__ #import #endif pybluez-0.23/macos/LightAquaBlue/OBEXFileTransferDictionary.plist000066400000000000000000000035401360152363700250760ustar00rootroot00000000000000 0001 - ServiceClassIDList EQY= 0004 - ProtocolDescriptorList AQA= AAM= DataElementSize 1 DataElementType 1 DataElementValue 3 AAg= 0005 - BrowseGroupList* EAI= 0006 - LanguageBaseAttributeIDList* DataElementSize 2 DataElementType 1 DataElementValue 25966 DataElementSize 2 DataElementType 1 DataElementValue 106 DataElementSize 2 DataElementType 1 DataElementValue 256 0009 - BluetoothProfileDescriptorList EQY= DataElementSize 2 DataElementType 1 DataElementValue 256 0303 - Supported Formats List DataElementType 1 DataElementValue /w== pybluez-0.23/macos/LightAquaBlue/OBEXObjectPushDictionary.plist000066400000000000000000000035401360152363700245600ustar00rootroot00000000000000 0001 - ServiceClassIDList EQU= 0004 - ProtocolDescriptorList AQA= AAM= DataElementSize 1 DataElementType 1 DataElementValue 3 AAg= 0005 - BrowseGroupList* EAI= 0006 - LanguageBaseAttributeIDList* DataElementSize 2 DataElementType 1 DataElementValue 25966 DataElementSize 2 DataElementType 1 DataElementValue 106 DataElementSize 2 DataElementType 1 DataElementValue 256 0009 - BluetoothProfileDescriptorList EQU= DataElementSize 2 DataElementType 1 DataElementValue 256 0303 - Supported Formats List DataElementType 1 DataElementValue /w== pybluez-0.23/macos/LightAquaBlue/SerialPortDictionary.plist000066400000000000000000000034561360152363700241260ustar00rootroot00000000000000 0001 - ServiceClassIDList EQE= 0004 - ProtocolDescriptorList AQA= AAM= DataElementSize 1 DataElementType 1 DataElementValue 3 0005 - BrowseGroupList* EAI= 0006 - LanguageBaseAttributeIDList* DataElementSize 2 DataElementType 1 DataElementValue 25966 DataElementSize 2 DataElementType 1 DataElementValue 106 DataElementSize 2 DataElementType 1 DataElementValue 256 0009 - BluetoothProfileDescriptorList EQE= DataElementSize 2 DataElementType 1 DataElementValue 256 0303 - Supported Formats List DataElementType 1 DataElementValue /w== pybluez-0.23/macos/LightAquaBlue/advertising-notes.txt000066400000000000000000000027641360152363700231460ustar00rootroot00000000000000SerialPortDictionary.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.py000077500000000000000000000160671360152363700171630ustar00rootroot00000000000000# 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.py000066400000000000000000000037551360152363700174160ustar00rootroot00000000000000# 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.py000077500000000000000000000026031360152363700174440ustar00rootroot00000000000000# 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__.py000077500000000000000000000141501360152363700163550ustar00rootroot00000000000000# 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.py000066400000000000000000001034071360152363700203570ustar00rootroot00000000000000# 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.py000077500000000000000000000454271360152363700167470ustar00rootroot00000000000000# 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.py000077500000000000000000000244531360152363700201540ustar00rootroot00000000000000# 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.py000077500000000000000000000213571360152363700164220ustar00rootroot00000000000000# 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.py000077500000000000000000000556541360152363700157300ustar00rootroot00000000000000# 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.py000077500000000000000000000434141360152363700171300ustar00rootroot00000000000000# 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.py000066400000000000000000000065551360152363700155620ustar00rootroot00000000000000# 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/000077500000000000000000000000001360152363700141035ustar00rootroot00000000000000pybluez-0.23/msbt/_msbt.c000066400000000000000000000741231360152363700153620ustar00rootroot00000000000000#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/000077500000000000000000000000001360152363700142055ustar00rootroot00000000000000pybluez-0.23/port3/port3.h000066400000000000000000000011471360152363700154300ustar00rootroot00000000000000 #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_checklist000066400000000000000000000004711360152363700165340ustar00rootroot000000000000001. 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.py000077500000000000000000000117411360152363700146570ustar00rootroot00000000000000#!/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/000077500000000000000000000000001360152363700145755ustar00rootroot00000000000000pybluez-0.23/widcomm/_widcomm.cpp000066400000000000000000000166131360152363700171060ustar00rootroot00000000000000#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.cpp000066400000000000000000000415151360152363700171450ustar00rootroot00000000000000#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 (&msg), sizeof (msg), 0); } typedef struct { int msg_type; CBtIf::STACK_STATUS new_status; } stack_status_change_msg_t; void WCInquirer::OnStackStatusChange (STACK_STATUS new_status) { dbg ("%s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__); stack_status_change_msg_t msg; msg.msg_type = STACK_STATUS_CHAGE; msg.new_status = new_status; send (this->threadfd, reinterpret_cast (&msg), sizeof (msg), 0); } #pragma pack(pop) // =================== typedef struct _WCInquirerPyObject WCInquirerPyObject; struct _WCInquirerPyObject { PyObject_HEAD WCInquirer *inq; int readfd; int writefd; }; PyDoc_STRVAR(wcinquirer_doc, "CBtIf wrapper"); extern PyTypeObject wcinquirer_type; static PyObject * get_sockport (PyObject *s) { WCInquirerPyObject *self = (WCInquirerPyObject*) s; return PyInt_FromLong (self->inq->GetSockPort ()); } static PyObject * accept_client (PyObject *s) { WCInquirerPyObject *self = (WCInquirerPyObject*) s; return PyInt_FromLong (self->inq->AcceptClient ()); } static PyObject * start_inquiry (PyObject *s) { WCInquirerPyObject *self = (WCInquirerPyObject*) s; BOOL success = TRUE; Py_BEGIN_ALLOW_THREADS success = self->inq->StartInquiry (); Py_END_ALLOW_THREADS if (success) { Py_RETURN_TRUE; } else { Py_RETURN_FALSE; } } static PyObject * start_discovery (PyObject *s, PyObject *args) { WCInquirerPyObject *self = (WCInquirerPyObject*) s; dbg ("%s:%d start_discovery\n", __FILE__, __LINE__); char *bdaddr_in = NULL; int bdaddr_in_len = 0; char *uuid_str = NULL; int uuid_str_len = 0; BD_ADDR bdaddr; if (!PyArg_ParseTuple (args, "s#|s#", &bdaddr_in, &bdaddr_in_len, &uuid_str, &uuid_str_len)) return 0; if (bdaddr_in_len != BD_ADDR_LEN) { PyErr_SetString (PyExc_ValueError, "invalid bdaddr"); return NULL; } memcpy (bdaddr, bdaddr_in, BD_ADDR_LEN); GUID uuid = { 0 }; GUID *puuid = NULL; if (uuid_str) { PyWidcomm::str2uuid (uuid_str, &uuid); puuid = &uuid; } BOOL result; Py_BEGIN_ALLOW_THREADS result = self->inq->StartDiscovery (bdaddr, puuid); Py_END_ALLOW_THREADS if (result) Py_RETURN_TRUE; else Py_RETURN_FALSE; } static PyObject * is_device_ready (PyObject *s) { WCInquirerPyObject *self = (WCInquirerPyObject*) s; dbg ("IsDeviceReady: %d\n", (self->inq->IsDeviceReady ())); if (self->inq->IsDeviceReady ()) Py_RETURN_TRUE; else Py_RETURN_FALSE; } static PyObject * is_stack_server_up (PyObject *s) { WCInquirerPyObject *self = (WCInquirerPyObject*) s; if (self->inq->IsStackServerUp ()) Py_RETURN_TRUE; else Py_RETURN_FALSE; } static PyObject * get_local_device_name (PyObject *s) { WCInquirerPyObject *self = (WCInquirerPyObject*) s; BD_NAME name; if (self->inq->GetLocalDeviceName (&name)) { return PyString_FromString ( (const char *)name); } else { Py_RETURN_NONE; } } static PyObject * get_local_device_version_info (PyObject *s) { WCInquirerPyObject *self = (WCInquirerPyObject*) s; Py_RETURN_NONE; // DEV_VER_INFO info; // BOOL success = self->inq->GetLocalDeviceVersionInfo (&info); // if (success) { // return Py_BuildValue ("s#BHBHH", // info.bd_addr, 6, // info.hci_version, // info.hci_revision, // info.lmp_version, // info.manufacturer, // info.lmp_sub_version); // } else { // Py_RETURN_NONE; // } } #define MAX_SDP_DISCOVERY_RECORDS 2000 static PyObject * read_discovery_records (PyObject *s, PyObject *args) { WCInquirerPyObject *self = (WCInquirerPyObject*) s; UINT8 *bdaddr_in = NULL; int bdaddr_in_len = 0; char *uuid_str = NULL; int uuid_str_len = 0; BD_ADDR bdaddr; if (!PyArg_ParseTuple (args, "s#|s#", &bdaddr_in, &bdaddr_in_len, &uuid_str, &uuid_str_len)) return 0; if (bdaddr_in_len != BD_ADDR_LEN) { PyErr_SetString (PyExc_ValueError, "invalid bdaddr"); return NULL; } memcpy (bdaddr, bdaddr_in, BD_ADDR_LEN); int nrecords = 0; CSdpDiscoveryRec *records = new CSdpDiscoveryRec[MAX_SDP_DISCOVERY_RECORDS]; if (uuid_str) { dbg ("filtering by uuid %s\n", uuid_str); GUID uuid = { 0 }; PyWidcomm::str2uuid (uuid_str, &uuid); nrecords = self->inq->ReadDiscoveryRecords (bdaddr, MAX_SDP_DISCOVERY_RECORDS, records, &uuid); } else { dbg ("no uuid specified.\n"); nrecords = self->inq->ReadDiscoveryRecords (bdaddr, MAX_SDP_DISCOVERY_RECORDS, records); dbg ("nrecords: %d\n", nrecords); } char bdaddr_str[18]; sprintf_s (bdaddr_str, sizeof(bdaddr_str), "%02X:%02X:%02X:%02X:%02X:%02X", bdaddr_in[0], bdaddr_in[1], bdaddr_in[2], bdaddr_in[3], bdaddr_in[4], bdaddr_in[5]); PyObject *result = PyList_New (nrecords); for (int i=0; i 0 && desc.elem[0].type == ATTR_TYPE_ARRAY) { dict_set_strings (dict, "description", (char*)desc.elem[0].val.array); } else { dict_set_strings (dict, "description", ""); } dict_set_strings (dict, "provider", ""); PyObject *profiles_list = PyList_New (0); dict_set_str_pyobj (dict, "profiles", profiles_list); Py_DECREF (profiles_list); dict_set_strings (dict, "service-id", ""); // service class list PyObject *uuid_list = PyList_New (0); // SDP_DISC_ATTTR_VAL service_classes; // if (records[i].FindAttribute (0x0001, &service_classes)) { // // printf ("service-classes: %d\n", desc.num_elem); // for (int j=0; jinq->GetLocalDeviceInfo (); if (result) { return Py_BuildValue ("s", self->inq->m_BdName); } else { Py_RETURN_NONE; } } static PyObject * get_btw_version_info (PyObject *s) { WCInquirerPyObject *self = (WCInquirerPyObject*) s; char buf[MAX_PATH]; BOOL result = self->inq->GetBTWVersionInfo (buf, MAX_PATH); if (result) { return PyString_FromString (buf); } else { Py_RETURN_NONE; } } static PyMethodDef wcinquirer_methods[] = { { "get_sockport", (PyCFunction) get_sockport, METH_NOARGS, "" }, { "accept_client", (PyCFunction) accept_client, METH_NOARGS, "" }, { "start_inquiry", (PyCFunction)start_inquiry, METH_NOARGS, "" }, { "start_discovery", (PyCFunction)start_discovery, METH_VARARGS, "" }, { "is_device_ready", (PyCFunction)is_device_ready, METH_NOARGS, "" }, { "is_stack_server_up", (PyCFunction)is_stack_server_up, METH_NOARGS, "" }, { "get_local_device_name", (PyCFunction)get_local_device_name, METH_NOARGS, "" }, { "get_local_device_version_info", (PyCFunction)get_local_device_version_info, METH_NOARGS, ""}, { "read_discovery_records", (PyCFunction)read_discovery_records, METH_VARARGS, "" }, { "get_remote_device_info", (PyCFunction)get_remote_device_info, METH_VARARGS, "" }, { "get_next_remote_device_info", (PyCFunction)get_next_remote_device_info, METH_VARARGS, "" }, { "get_local_device_address", (PyCFunction)get_local_device_address, METH_NOARGS, "" }, { "get_btw_version_info", (PyCFunction)get_btw_version_info, METH_NOARGS, "" }, { NULL, NULL } }; static PyObject * wcinquirer_repr(WCInquirerPyObject *s) { return PyString_FromString("_WCInquirer object"); } static PyObject * wcinquirer_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *newobj; newobj = type->tp_alloc(type, 0); if (newobj != NULL) { WCInquirerPyObject *self = (WCInquirerPyObject *)newobj; self->inq = NULL; } return newobj; } static void wcinquirer_dealloc(WCInquirerPyObject *self) { if (self->inq) { delete self->inq; self->inq = NULL; } Py_TYPE(self)->tp_free((PyObject*)self); } int wcinquirer_initobj(PyObject *s, PyObject *args, PyObject *kwds) { WCInquirerPyObject *self = (WCInquirerPyObject *)s; self->inq = new WCInquirer (s); return 0; } /* Type object for socket objects. */ PyTypeObject wcinquirer_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 "_widcomm._WCInquirer", /* tp_name */ sizeof(WCInquirerPyObject), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor)wcinquirer_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ (reprfunc)wcinquirer_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 */ wcinquirer_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ wcinquirer_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 */ wcinquirer_initobj, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ wcinquirer_new, /* tp_new */ PyObject_Del, /* tp_free */ }; pybluez-0.23/widcomm/inquirer.hpp000066400000000000000000000014601360152363700171450ustar00rootroot00000000000000#pragma once class WCInquirer : public CBtIf { public: enum { DEVICE_RESPONDED, INQUIRY_COMPLETE, DISCOVERY_COMPLETE, STACK_STATUS_CHAGE }; WCInquirer::WCInquirer (PyObject *wcinq); virtual ~WCInquirer (); int AcceptClient (); inline unsigned short GetSockPort () { return sockport; } private: void OnDeviceResponded (BD_ADDR bda, DEV_CLASS devClass, BD_NAME bdName, BOOL bConnected); void OnInquiryComplete (BOOL success, short num_responses); void OnDiscoveryComplete (); void OnStackStatusChange (STACK_STATUS new_status); PyObject * wcinq; SOCKET threadfd; SOCKET serverfd; unsigned short sockport; }; pybluez-0.23/widcomm/l2capconn.cpp000066400000000000000000000270341360152363700171660ustar00rootroot00000000000000#include #include #include #include #include #include #include "l2capconn.hpp" #include "l2capif.hpp" static inline void dbg (const char *fmt, ...) { return; va_list ap; va_start (ap, fmt); vfprintf (stderr, fmt, ap); va_end (ap); } WCL2CapConn::WCL2CapConn (PyObject *pyobj) : CL2CapConn () { this->pyobj = pyobj; 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); } WCL2CapConn::~WCL2CapConn () { closesocket (this->threadfd); } int WCL2CapConn::AcceptClient () { dbg ("%s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__); 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; int len; } data_received_t; void WCL2CapConn::OnDataReceived (void *p_data, UINT16 len) { dbg ("%s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__); data_received_t msg; msg.msg_type = DATA_RECEIVED; msg.len = len; send (this->threadfd, reinterpret_cast (&msg), sizeof (msg), 0); send (this->threadfd, reinterpret_cast (p_data), len, 0); } void WCL2CapConn::OnIncomingConnection () { dbg ("%s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__); int msg = INCOMING_CONNECTION; send (this->threadfd, reinterpret_cast (&msg), sizeof (msg), 0); } void WCL2CapConn::OnConnectPendingReceived () { dbg ("%s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__); // TODO } void WCL2CapConn::OnConnected () { dbg ("%s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__); int msg = CONNECTED; send (this->threadfd, reinterpret_cast (&msg), sizeof (msg), 0); } void WCL2CapConn::OnCongestionStatus (BOOL is_congested) { dbg ("%s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__); // TODO } void WCL2CapConn::OnRemoteDisconnected (UINT16 reason) { dbg ("%s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__); int msg = REMOTE_DISCONNECTED; send (this->threadfd, reinterpret_cast (&msg), sizeof (msg), 0); } #pragma pack(pop) // =================== typedef struct _WCL2CapConnPyObject WCL2CapConnPyObject; struct _WCL2CapConnPyObject { PyObject_HEAD WCL2CapConn *l2cap; }; PyDoc_STRVAR(wcl2capconn_doc, "CL2CapConn wrapper"); extern PyTypeObject wcl2capconn_type; static PyObject * get_sockport (PyObject *s) { WCL2CapConnPyObject *self = (WCL2CapConnPyObject*) s; return PyInt_FromLong (self->l2cap->GetSockPort ()); } static PyObject * accept_client (PyObject *s) { WCL2CapConnPyObject *self = (WCL2CapConnPyObject*) s; return PyInt_FromLong (self->l2cap->AcceptClient ()); } static PyObject * wc_listen (PyObject *s, PyObject *a) { WCL2CapConnPyObject *self = (WCL2CapConnPyObject*) s; dbg ("%s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__); if (! PyObject_IsInstance (a, (PyObject*)&wcl2capif_type)) { return NULL; } WCL2CapIfPyObject *l2cap_if = (WCL2CapIfPyObject*) a; BOOL result; Py_BEGIN_ALLOW_THREADS; result = self->l2cap->Listen (l2cap_if->l2capif); Py_END_ALLOW_THREADS; dbg (" listen: %d\n", result); if (result) { Py_RETURN_TRUE; } else { Py_RETURN_FALSE; } } static PyObject * wc_accept (PyObject *s, PyObject *args) { WCL2CapConnPyObject *self = (WCL2CapConnPyObject*) s; dbg ("%s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__); UINT16 desired_mtu = L2CAP_DEFAULT_MTU; if (!PyArg_ParseTuple (args, "|H", &desired_mtu)) return NULL; BOOL result; Py_BEGIN_ALLOW_THREADS; dbg (" calling accept (%p)\n", self->l2cap); result = self->l2cap->Accept (); dbg (" accept: %d\n", result); Py_END_ALLOW_THREADS; if (result) { Py_RETURN_TRUE; } else { Py_RETURN_FALSE; } } static PyObject * wc_connect (PyObject *s, PyObject *args) { WCL2CapConnPyObject *self = (WCL2CapConnPyObject*) s; WCL2CapIfPyObject *l2cap_if = NULL; char *bdaddr_in = NULL; int bdaddr_in_len; UINT16 desired_mtu = L2CAP_DEFAULT_MTU;; if(!PyArg_ParseTuple (args, "O!s#|H", &wcl2capif_type, &l2cap_if, &bdaddr_in, &bdaddr_in_len, &desired_mtu)) return NULL; if (bdaddr_in_len != BD_ADDR_LEN) { PyErr_SetString (PyExc_ValueError, "invalid bdaddr"); return NULL; } BD_ADDR bdaddr; memcpy (bdaddr, bdaddr_in, BD_ADDR_LEN); BOOL result; Py_BEGIN_ALLOW_THREADS; result = self->l2cap->Connect (l2cap_if->l2capif, bdaddr, desired_mtu); Py_END_ALLOW_THREADS; return PyInt_FromLong (result); } static PyObject * wc_disconnect (PyObject *s) { WCL2CapConnPyObject *self = (WCL2CapConnPyObject*) s; dbg ("%s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__); Py_BEGIN_ALLOW_THREADS; self->l2cap->Disconnect (); Py_END_ALLOW_THREADS; Py_RETURN_NONE; } static PyObject * wc_remote_bd_addr (PyObject *s) { WCL2CapConnPyObject *self = (WCL2CapConnPyObject*) s; dbg ("%s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__); tBT_CONN_STATS connstats; if (!self->l2cap->GetConnectionStats (&connstats)) { Py_RETURN_NONE; } if (!connstats.bIsConnected) Py_RETURN_NONE; return Py_BuildValue ("s#", &self->l2cap->m_RemoteBdAddr, BD_ADDR_LEN); } static PyObject * wc_write (PyObject *s, PyObject *args) { _WCL2CapConnPyObject *self = (_WCL2CapConnPyObject*) s; dbg ("%s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__); char *data = NULL; int datalen; if (!PyArg_ParseTuple (args, "s#", &data, &datalen)) return NULL; UINT16 written = 0; BOOL result; Py_BEGIN_ALLOW_THREADS; result = self->l2cap->Write (data, datalen, &written); Py_END_ALLOW_THREADS; return Py_BuildValue ("II", result, written); } static PyObject * wc_get_connection_stats (PyObject *s) { _WCL2CapConnPyObject *self = (_WCL2CapConnPyObject*) s; dbg ("%s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__); tBT_CONN_STATS stats; memset (&stats, 0, sizeof (stats)); BOOL result; Py_BEGIN_ALLOW_THREADS; result = self->l2cap->GetConnectionStats (&stats); Py_END_ALLOW_THREADS; return Py_BuildValue ("iIiIII", result, stats.bIsConnected, stats.Rssi, stats.BytesSent, stats.BytesRcvd, stats.Duration); } static PyObject * wc_switch_role (PyObject *s, PyObject *arg) { _WCL2CapConnPyObject *self = (_WCL2CapConnPyObject*) s; dbg ("%s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__); MASTER_SLAVE_ROLE new_role = static_cast (PyInt_AsLong (arg)); BOOL result = self->l2cap->SwitchRole (new_role); return PyInt_FromLong (result); } static PyObject * wc_set_link_supervision_timeout (PyObject *s, PyObject *arg) { _WCL2CapConnPyObject *self = (_WCL2CapConnPyObject*) s; dbg ("%s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__); UINT16 timeoutSlot = static_cast (PyInt_AsLong (arg)); BOOL result = self->l2cap->SetLinkSupervisionTimeOut (timeoutSlot); return PyInt_FromLong (result); } static PyMethodDef wcl2capconn_methods[] = { { "get_sockport", (PyCFunction) get_sockport, METH_NOARGS, "" }, { "accept_client", (PyCFunction) accept_client, METH_NOARGS, "" }, { "listen", (PyCFunction) wc_listen, METH_O, "" }, { "accept", (PyCFunction) wc_accept, METH_VARARGS, "" }, { "connect", (PyCFunction) wc_connect, METH_VARARGS, "" }, { "disconnect", (PyCFunction) wc_disconnect, METH_NOARGS, "" }, { "remote_bd_addr", (PyCFunction) wc_remote_bd_addr, METH_NOARGS, "" }, { "write", (PyCFunction)wc_write, METH_VARARGS, "" }, { "get_connection_stats", (PyCFunction)wc_get_connection_stats, METH_NOARGS, "" }, { "switch_role", (PyCFunction)wc_switch_role, METH_O, "" }, { "set_link_supervision_timeout", (PyCFunction)wc_set_link_supervision_timeout, METH_O, "" }, { NULL, NULL } }; static PyObject * wcl2capconn_repr(WCL2CapConnPyObject *s) { return PyString_FromString("_WCL2CapConn object"); } static PyObject * wcl2capconn_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *newobj; newobj = type->tp_alloc(type, 0); if (newobj != NULL) { WCL2CapConnPyObject *self = (WCL2CapConnPyObject *)newobj; self->l2cap = NULL; } return newobj; } static void wcl2capconn_dealloc(WCL2CapConnPyObject *self) { if (self->l2cap) { delete self->l2cap; self->l2cap = NULL; } Py_TYPE(self)->tp_free((PyObject*)self); } int wcl2capconn_initobj(PyObject *s, PyObject *args, PyObject *kwds) { WCL2CapConnPyObject *self = (WCL2CapConnPyObject *)s; self->l2cap = new WCL2CapConn (s); return 0; } /* Type object for socket objects. */ PyTypeObject wcl2capconn_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 "_widcomm._WCL2CapConn", /* tp_name */ sizeof(WCL2CapConnPyObject), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor)wcl2capconn_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ (reprfunc)wcl2capconn_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 */ wcl2capconn_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ wcl2capconn_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 */ wcl2capconn_initobj, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ wcl2capconn_new, /* tp_new */ PyObject_Del, /* tp_free */ }; pybluez-0.23/widcomm/l2capconn.hpp000066400000000000000000000014501360152363700171650ustar00rootroot00000000000000#pragma once class WCL2CapConn : public CL2CapConn { public: enum { DATA_RECEIVED, INCOMING_CONNECTION, REMOTE_DISCONNECTED, CONNECTED }; WCL2CapConn (PyObject *pyobj); virtual ~WCL2CapConn (); int AcceptClient (); inline unsigned short GetSockPort () { return sockport; } private: CL2CapIf rfcommif; void OnIncomingConnection (); void OnConnectPendingReceived (); void OnConnected (); void OnDataReceived (void *p_data, UINT16 len); void OnCongestionStatus (BOOL is_congested); void OnRemoteDisconnected (UINT16 reason); PyObject * pyobj; SOCKET threadfd; SOCKET serverfd; unsigned short sockport; }; pybluez-0.23/widcomm/l2capif.cpp000066400000000000000000000125111360152363700166210ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "util.h" #include "l2capif.hpp" // =================== static inline void dbg (const char *fmt, ...) { return; va_list ap; va_start (ap, fmt); vfprintf (stderr, fmt, ap); va_end (ap); } PyDoc_STRVAR(wcl2capif_doc, "CL2CapIf wrapper"); static PyObject * assign_psm_value (PyObject *s, PyObject *args) { // dbg ("%s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__); WCL2CapIfPyObject *self = (WCL2CapIfPyObject*) s; char *uuid_str = NULL; int uuid_str_len = 0; UINT16 psm = 0; char *service_name = _T(""); if(!PyArg_ParseTuple (args, "s#|H", &uuid_str, &uuid_str_len, &psm)) return NULL; GUID uuid = { 0 }; PyWidcomm::str2uuid (uuid_str, &uuid); BOOL result = self->l2capif->AssignPsmValue (&uuid, psm); dbg ("%s:%d:%s (%d)\n", __FILE__, __LINE__, __FUNCTION__, self->l2capif->GetPsm()); if (result) { Py_RETURN_TRUE; } else { Py_RETURN_FALSE; } } static PyObject * wc_register (PyObject *s) { WCL2CapIfPyObject *self = (WCL2CapIfPyObject*) s; return PyInt_FromLong (self->l2capif->Register ()); } static PyObject * wc_deregister (PyObject *s) { WCL2CapIfPyObject *self = (WCL2CapIfPyObject*) s; self->l2capif->Deregister (); Py_RETURN_NONE; } static PyObject * get_psm (PyObject *s) { WCL2CapIfPyObject *self = (WCL2CapIfPyObject*) s; return PyInt_FromLong (self->l2capif->GetPsm ()); } static PyObject * set_security_level (PyObject *s, PyObject *args) { char *service_name = NULL; UINT8 security_level = BTM_SEC_NONE; int is_server; if(!PyArg_ParseTuple (args, "sBi", &service_name, &security_level, &is_server)) return NULL; dbg ("%s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__); WCL2CapIfPyObject *self = (WCL2CapIfPyObject*) s; BOOL result = self->l2capif->SetSecurityLevel (service_name, security_level, (BOOL) is_server); // dbg ("%s:%d:%s %d\n", __FILE__, __LINE__, __FUNCTION__, result); if (result) { Py_RETURN_TRUE; } else { Py_RETURN_FALSE; } } static PyMethodDef wcl2capif_methods[] = { { "assign_psm_value", (PyCFunction)assign_psm_value, METH_VARARGS, "" }, { "register", (PyCFunction)wc_register, METH_NOARGS, "" }, { "deregister", (PyCFunction)wc_deregister, METH_NOARGS, "" }, { "get_psm", (PyCFunction)get_psm, METH_NOARGS, "" }, { "set_security_level", (PyCFunction)set_security_level, METH_VARARGS, "" }, { NULL, NULL } }; static PyObject * wcl2capif_repr(WCL2CapIfPyObject *s) { return PyString_FromString("_WCL2CapIf object"); } static PyObject * wcl2capif_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *newobj; newobj = type->tp_alloc(type, 0); if (newobj != NULL) { WCL2CapIfPyObject *self = (WCL2CapIfPyObject *)newobj; self->l2capif = NULL; } return newobj; } static void wcl2capif_dealloc(WCL2CapIfPyObject *self) { if (self->l2capif) { delete self->l2capif; self->l2capif = NULL; } Py_TYPE(self)->tp_free((PyObject*)self); } int wcl2capif_initobj(PyObject *s, PyObject *args, PyObject *kwds) { WCL2CapIfPyObject *self = (WCL2CapIfPyObject *)s; self->l2capif = new CL2CapIf (); return 0; } /* Type object for socket objects. */ PyTypeObject wcl2capif_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 "_widcomm._WCL2CapIf", /* tp_name */ sizeof(WCL2CapIfPyObject), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor)wcl2capif_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ (reprfunc)wcl2capif_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 */ wcl2capif_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ wcl2capif_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 */ wcl2capif_initobj, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ wcl2capif_new, /* tp_new */ PyObject_Del, /* tp_free */ }; pybluez-0.23/widcomm/l2capif.hpp000066400000000000000000000002641360152363700166300ustar00rootroot00000000000000#pragma once typedef struct _WCL2CapIfPyObject WCL2CapIfPyObject; struct _WCL2CapIfPyObject { PyObject_HEAD CL2CapIf * l2capif; }; extern PyTypeObject wcl2capif_type; pybluez-0.23/widcomm/rfcommif.cpp000066400000000000000000000113271360152363700171070ustar00rootroot00000000000000#include #include #include #include #include #include #include #include "util.h" // =================== typedef struct _WCRfCommIfPyObject WCRfCommIfPyObject; struct _WCRfCommIfPyObject { PyObject_HEAD CRfCommIf * rfcommif; }; PyDoc_STRVAR(wcrfcommif_doc, "CRfCommIf wrapper"); extern PyTypeObject wcrfcommif_type; static PyObject * assign_scn_value (PyObject *s, PyObject *args) { WCRfCommIfPyObject *self = (WCRfCommIfPyObject*) s; char *uuid_str = NULL; int uuid_str_len = 0; UINT8 scn = 0; char *service_name = _T(""); if(!PyArg_ParseTuple (args, "s#|Bs", &uuid_str, &uuid_str_len, &scn, &service_name)) return NULL; GUID uuid = { 0 }; PyWidcomm::str2uuid (uuid_str, &uuid); // printf ("AssignScnValue\n"); BOOL result = self->rfcommif->AssignScnValue (&uuid, scn, service_name); if (result) { Py_RETURN_TRUE; } else { Py_RETURN_FALSE; } } static PyObject * get_scn (PyObject *s) { WCRfCommIfPyObject *self = (WCRfCommIfPyObject*) s; return PyInt_FromLong (self->rfcommif->GetScn ()); } static PyObject * set_security_level (PyObject *s, PyObject *args) { char *service_name = NULL; UINT8 security_level = BTM_SEC_NONE; int is_server; if(!PyArg_ParseTuple (args, "sBi", &service_name, &security_level, &is_server)) return NULL; WCRfCommIfPyObject *self = (WCRfCommIfPyObject*) s; BOOL result = self->rfcommif->SetSecurityLevel (service_name, security_level, (BOOL) is_server); if (result) { Py_RETURN_TRUE; } else { Py_RETURN_FALSE; } } static PyMethodDef wcrfcommif_methods[] = { { "assign_scn_value", (PyCFunction)assign_scn_value, METH_VARARGS, "" }, { "get_scn", (PyCFunction)get_scn, METH_NOARGS, "" }, { "set_security_level", (PyCFunction)set_security_level, METH_VARARGS, "" }, { NULL, NULL } }; static PyObject * wcrfcommif_repr(WCRfCommIfPyObject *s) { return PyString_FromString("_WCRfCommIf object"); } static PyObject * wcrfcommif_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *newobj; newobj = type->tp_alloc(type, 0); if (newobj != NULL) { WCRfCommIfPyObject *self = (WCRfCommIfPyObject *)newobj; self->rfcommif = NULL; } return newobj; } static void wcrfcommif_dealloc(WCRfCommIfPyObject *self) { if (self->rfcommif) { delete self->rfcommif; self->rfcommif = NULL; } Py_TYPE(self)->tp_free((PyObject*)self); } int wcrfcommif_initobj(PyObject *s, PyObject *args, PyObject *kwds) { WCRfCommIfPyObject *self = (WCRfCommIfPyObject *)s; self->rfcommif = new CRfCommIf (); return 0; } /* Type object for socket objects. */ PyTypeObject wcrfcommif_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 "_widcomm._WCRfCommIf", /* tp_name */ sizeof(WCRfCommIfPyObject), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor)wcrfcommif_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ (reprfunc)wcrfcommif_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 */ wcrfcommif_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ wcrfcommif_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 */ wcrfcommif_initobj, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ wcrfcommif_new, /* tp_new */ PyObject_Del, /* tp_free */ }; pybluez-0.23/widcomm/rfcommport.cpp000066400000000000000000000272621360152363700175020ustar00rootroot00000000000000#include #include #include #include #include #include #include "rfcommport.hpp" static inline void dbg (const char *fmt, ...) { return; va_list ap; va_start (ap, fmt); vfprintf (stderr, fmt, ap); va_end (ap); } WCRfCommPort::WCRfCommPort (PyObject *pyobj) : CRfCommPort () { this->pyobj = pyobj; 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); } WCRfCommPort::~WCRfCommPort () { dbg ("%s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__); closesocket (this->threadfd); } int WCRfCommPort::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; int len; } data_received_t; void WCRfCommPort::OnDataReceived (void *p_data, UINT16 len) { dbg ("%s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__); data_received_t msg; msg.msg_type = DATA_RECEIVED; msg.len = len; send (this->threadfd, reinterpret_cast (&msg), sizeof (msg), 0); send (this->threadfd, reinterpret_cast (p_data), len, 0); } typedef struct { int msg_type; unsigned int event_code; } event_received_msg_t; void WCRfCommPort::OnEventReceived (UINT32 event_code) { dbg ("%s:%d event %u received\n", __FILE__, __LINE__, event_code); event_received_msg_t msg; msg.msg_type = EVENT_RECEIVED; msg.event_code = event_code; send (this->threadfd, reinterpret_cast (&msg), sizeof (msg), 0); } #pragma pack(pop) // =================== typedef struct _WCRfCommPortPyObject WCRfCommPortPyObject; struct _WCRfCommPortPyObject { PyObject_HEAD WCRfCommPort *rfcp; }; PyDoc_STRVAR(wcrfcommport_doc, "CRfCommPort wrapper"); extern PyTypeObject wcrfcommport_type; static PyObject * get_sockport (PyObject *s) { WCRfCommPortPyObject *self = (WCRfCommPortPyObject*) s; return PyInt_FromLong (self->rfcp->GetSockPort ()); } static PyObject * accept_client (PyObject *s) { WCRfCommPortPyObject *self = (WCRfCommPortPyObject*) s; return PyInt_FromLong (self->rfcp->AcceptClient ()); } static PyObject * wc_open_server (PyObject *s, PyObject *args) { WCRfCommPortPyObject *self = (WCRfCommPortPyObject*) s; UINT8 scn; UINT16 desired_mtu = RFCOMM_DEFAULT_MTU; if (!PyArg_ParseTuple (args, "B|H", &scn, &desired_mtu)) return NULL; CRfCommPort::PORT_RETURN_CODE result = self->rfcp->OpenServer (scn, desired_mtu); return PyInt_FromLong (result); } static PyObject * wc_open_client (PyObject *s, PyObject *args) { UINT8 scn; char *bdaddr_in = NULL; int bdaddr_in_len; UINT16 desired_mtu = RFCOMM_DEFAULT_MTU; if(!PyArg_ParseTuple (args, "Bs#|H", &scn, &bdaddr_in, &bdaddr_in_len, &desired_mtu)) return NULL; if (bdaddr_in_len != BD_ADDR_LEN) { PyErr_SetString (PyExc_ValueError, "invalid bdaddr"); return NULL; } BD_ADDR bdaddr; memcpy (bdaddr, bdaddr_in, BD_ADDR_LEN); _WCRfCommPortPyObject *self = (_WCRfCommPortPyObject*) s; CRfCommPort::PORT_RETURN_CODE result; Py_BEGIN_ALLOW_THREADS; result = self->rfcp->OpenClient (scn, bdaddr, desired_mtu); Py_END_ALLOW_THREADS; return PyInt_FromLong (result); } static PyObject * wc_is_connected (PyObject *s) { _WCRfCommPortPyObject *self = (_WCRfCommPortPyObject*) s; BD_ADDR remote_addr; if (self->rfcp->IsConnected (&remote_addr)) { return Py_BuildValue ("s#", &remote_addr, BD_ADDR_LEN); } else { Py_RETURN_NONE; } } static PyObject * wc_close (PyObject *s) { dbg ("%s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__); _WCRfCommPortPyObject *self = (_WCRfCommPortPyObject*) s; self->rfcp->Close (); Py_RETURN_NONE; } static PyObject * wc_set_flow_enabled (PyObject *s, PyObject *arg) { _WCRfCommPortPyObject *self = (_WCRfCommPortPyObject*) s; int enable = PyInt_AsLong (arg); CRfCommPort::PORT_RETURN_CODE result = self->rfcp->SetFlowEnabled (enable); return PyInt_FromLong (result); } static PyObject * wc_set_modem_signal (PyObject *s, PyObject *arg) { _WCRfCommPortPyObject *self = (_WCRfCommPortPyObject*) s; UINT8 signal = static_cast (PyInt_AsLong (arg)); CRfCommPort::PORT_RETURN_CODE result = self->rfcp->SetModemSignal (signal); return PyInt_FromLong (result); } static PyObject * wc_get_modem_status (PyObject *s) { _WCRfCommPortPyObject *self = (_WCRfCommPortPyObject*) s; UINT8 signal; CRfCommPort::PORT_RETURN_CODE result = self->rfcp->GetModemStatus (&signal); return Py_BuildValue ("ii", result, signal); } static PyObject * wc_send_error (PyObject *s, PyObject *arg) { _WCRfCommPortPyObject *self = (_WCRfCommPortPyObject*) s; UINT8 errors = static_cast (PyInt_AsLong (arg)); CRfCommPort::PORT_RETURN_CODE result = self->rfcp->SendError (errors); return PyInt_FromLong (result); } static PyObject * wc_purge (PyObject *s, PyObject *arg) { _WCRfCommPortPyObject *self = (_WCRfCommPortPyObject*) s; UINT8 purge_flags = static_cast (PyInt_AsLong (arg)); CRfCommPort::PORT_RETURN_CODE result = self->rfcp->Purge (purge_flags); return PyInt_FromLong (result); } static PyObject * wc_write (PyObject *s, PyObject *args) { _WCRfCommPortPyObject *self = (_WCRfCommPortPyObject*) s; char *data = NULL; int datalen; if (!PyArg_ParseTuple (args, "s#", &data, &datalen)) return NULL; UINT16 written = 0; CRfCommPort::PORT_RETURN_CODE status; Py_BEGIN_ALLOW_THREADS; status = self->rfcp->Write (data, datalen, &written); Py_END_ALLOW_THREADS; return Py_BuildValue ("II", status, written); } static PyObject * wc_get_connection_stats (PyObject *s) { _WCRfCommPortPyObject *self = (_WCRfCommPortPyObject*) s; tBT_CONN_STATS stats; memset (&stats, 0, sizeof (stats)); CRfCommPort::PORT_RETURN_CODE result = self->rfcp->GetConnectionStats (&stats); return Py_BuildValue ("iIiIII", result, stats.bIsConnected, stats.Rssi, stats.BytesSent, stats.BytesRcvd, stats.Duration); } static PyObject * wc_switch_role (PyObject *s, PyObject *arg) { _WCRfCommPortPyObject *self = (_WCRfCommPortPyObject*) s; MASTER_SLAVE_ROLE new_role = static_cast (PyInt_AsLong (arg)); BOOL result = self->rfcp->SwitchRole (new_role); return PyInt_FromLong (result); } static PyObject * wc_set_link_supervision_timeout (PyObject *s, PyObject *arg) { _WCRfCommPortPyObject *self = (_WCRfCommPortPyObject*) s; UINT16 timeoutSlot = static_cast (PyInt_AsLong (arg)); CRfCommPort::PORT_RETURN_CODE result = self->rfcp->SetLinkSupervisionTimeOut (timeoutSlot); return PyInt_FromLong (result); } static PyMethodDef wcrfcommport_methods[] = { { "get_sockport", (PyCFunction) get_sockport, METH_NOARGS, "" }, { "accept_client", (PyCFunction) accept_client, METH_NOARGS, "" }, { "open_server", (PyCFunction)wc_open_server, METH_VARARGS, "" }, { "open_client", (PyCFunction)wc_open_client, METH_VARARGS, "" }, { "close", (PyCFunction)wc_close, METH_NOARGS, "" }, { "is_connected", (PyCFunction)wc_is_connected, METH_NOARGS, "" }, { "set_flow_enabled", (PyCFunction)wc_set_flow_enabled, METH_O, "" }, { "set_modem_signal", (PyCFunction)wc_set_modem_signal, METH_O, "" }, { "get_modem_status", (PyCFunction)wc_get_modem_status, METH_NOARGS, "" }, { "send_error", (PyCFunction)wc_send_error, METH_O, "" }, { "purge", (PyCFunction)wc_purge, METH_O, "" }, { "write", (PyCFunction)wc_write, METH_VARARGS, "" }, { "get_connection_stats", (PyCFunction)wc_get_connection_stats, METH_NOARGS, "" }, { "switch_role", (PyCFunction)wc_switch_role, METH_O, "" }, { "set_link_supervision_timeout", (PyCFunction)wc_set_link_supervision_timeout, METH_O, "" }, { NULL, NULL } }; static PyObject * wcrfcommport_repr(WCRfCommPortPyObject *s) { return PyString_FromString("_WCRfCommPort object"); } static PyObject * wcrfcommport_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *newobj; newobj = type->tp_alloc(type, 0); if (newobj != NULL) { WCRfCommPortPyObject *self = (WCRfCommPortPyObject *)newobj; self->rfcp = NULL; } return newobj; } static void wcrfcommport_dealloc(WCRfCommPortPyObject *self) { dbg ("%s:%d:%s\n", __FILE__, __LINE__, __FUNCTION__); if (self->rfcp) { delete self->rfcp; self->rfcp = NULL; } Py_TYPE(self)->tp_free((PyObject*)self); } int wcrfcommport_initobj(PyObject *s, PyObject *args, PyObject *kwds) { WCRfCommPortPyObject *self = (WCRfCommPortPyObject *)s; self->rfcp = new WCRfCommPort (s); return 0; } /* Type object for socket objects. */ PyTypeObject wcrfcommport_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 "_widcomm._WCRfCommPort", /* tp_name */ sizeof(WCRfCommPortPyObject), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor)wcrfcommport_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ (reprfunc)wcrfcommport_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 */ wcrfcommport_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ wcrfcommport_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 */ wcrfcommport_initobj, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ wcrfcommport_new, /* tp_new */ PyObject_Del, /* tp_free */ }; pybluez-0.23/widcomm/rfcommport.hpp000066400000000000000000000011151360152363700174740ustar00rootroot00000000000000#pragma once class WCRfCommPort : public CRfCommPort { public: enum { DATA_RECEIVED, EVENT_RECEIVED }; WCRfCommPort (PyObject *pyobj); virtual ~WCRfCommPort (); int AcceptClient (); inline unsigned short GetSockPort () { return sockport; } private: CRfCommIf rfcommif; void OnDataReceived (void *p_data, UINT16 len); void OnEventReceived (UINT32 event_code); PyObject * pyobj; SOCKET threadfd; SOCKET serverfd; unsigned short sockport; }; pybluez-0.23/widcomm/sdpservice.cpp000066400000000000000000000150401360152363700174500ustar00rootroot00000000000000#include #include #include #include #include #include #include "util.h" // =================== typedef struct _WCSdpServicePyObject WCSdpServicePyObject; struct _WCSdpServicePyObject { PyObject_HEAD CSdpService * sdpservice; }; PyDoc_STRVAR(wcsdpservice_doc, "CSdpService wrapper"); extern PyTypeObject wcsdpservice_type; static PyObject * add_service_class_id_list (WCSdpServicePyObject *self, PyObject *arg) { int nuids = PySequence_Size (arg); if (nuids < 0) { return NULL; } GUID *uuids = (GUID*) malloc (nuids * sizeof (GUID)); for (int i=0; isdpservice->AddServiceClassIdList (nuids, uuids); free (uuids); return PyInt_FromLong (result); fail: free (uuids); return NULL; } static PyObject * add_profile_descriptor_list (WCSdpServicePyObject *self, PyObject *args) { char *uuid_str = NULL; int uuid_str_len = 0; UINT16 version = 0; GUID uuid; if (!PyArg_ParseTuple (args, "s#H", &uuid_str, &uuid_str_len, &version)) return NULL; PyWidcomm::str2uuid (uuid_str, &uuid); SDP_RETURN_CODE result = self->sdpservice->AddProfileDescriptorList (&uuid, version); return PyInt_FromLong (result); } static PyObject * add_service_name (WCSdpServicePyObject *self, PyObject *arg) { char *name = PyString_AsString (arg); if (!name) return NULL; SDP_RETURN_CODE result = self->sdpservice->AddServiceName (name); return PyInt_FromLong (result); } static PyObject * add_rfcomm_protocol_descriptor (WCSdpServicePyObject *self, PyObject *arg) { int port = PyInt_AsLong (arg); if (PyErr_Occurred ()) return NULL; UINT8 scn = static_cast (port); SDP_RETURN_CODE result = self->sdpservice->AddRFCommProtocolDescriptor (scn); return PyInt_FromLong (result); } static PyObject * add_l2cap_protocol_descriptor (WCSdpServicePyObject *self, PyObject *arg) { int port = PyInt_AsLong (arg); if (PyErr_Occurred ()) return NULL; UINT16 psm = static_cast (port); SDP_RETURN_CODE result = self->sdpservice->AddL2CapProtocolDescriptor (psm); return PyInt_FromLong (result); } static PyObject * make_public_browseable (WCSdpServicePyObject *self) { SDP_RETURN_CODE result = self->sdpservice->MakePublicBrowseable (); return PyInt_FromLong (result); } static PyObject * set_availability (WCSdpServicePyObject *self, PyObject *arg) { UINT8 available = static_cast (PyInt_AsLong (arg)); if (PyErr_Occurred ()) return NULL; SDP_RETURN_CODE result = self->sdpservice->SetAvailability (available); return PyInt_FromLong (result); } static PyMethodDef wcsdpservice_methods[] = { { "add_service_class_id_list", (PyCFunction)add_service_class_id_list, METH_O, "" }, { "add_profile_descriptor_list", (PyCFunction)add_profile_descriptor_list, METH_VARARGS, "" }, { "add_service_name", (PyCFunction)add_service_name, METH_O, "" }, { "add_rfcomm_protocol_descriptor", (PyCFunction)add_rfcomm_protocol_descriptor, METH_O, "" }, { "add_l2cap_protocol_descriptor", (PyCFunction)add_l2cap_protocol_descriptor, METH_O, "" }, { "make_public_browseable", (PyCFunction)make_public_browseable, METH_NOARGS, "" }, { "set_availability", (PyCFunction)set_availability, METH_O, "" }, { NULL, NULL } }; static PyObject * wcsdpservice_repr(WCSdpServicePyObject *s) { return PyString_FromString("_WCSdpService object"); } static PyObject * wcsdpservice_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { PyObject *newobj; newobj = type->tp_alloc(type, 0); if (newobj != NULL) { WCSdpServicePyObject *self = (WCSdpServicePyObject *)newobj; self->sdpservice = NULL; } return newobj; } static void wcsdpservice_dealloc(WCSdpServicePyObject *self) { if (self->sdpservice) { delete self->sdpservice; self->sdpservice = NULL; } Py_TYPE(self)->tp_free((PyObject*)self); } int wcsdpservice_initobj(PyObject *s, PyObject *args, PyObject *kwds) { WCSdpServicePyObject *self = (WCSdpServicePyObject *)s; self->sdpservice = new CSdpService (); return 0; } /* Type object for socket objects. */ PyTypeObject wcsdpservice_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 "_widcomm._WCSdpService", /* tp_name */ sizeof(WCSdpServicePyObject), /* tp_basicsize */ 0, /* tp_itemsize */ (destructor)wcsdpservice_dealloc, /* tp_dealloc */ 0, /* tp_print */ 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_compare */ (reprfunc)wcsdpservice_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 */ wcsdpservice_doc, /* tp_doc */ 0, /* tp_traverse */ 0, /* tp_clear */ 0, /* tp_richcompare */ 0, /* tp_weaklistoffset */ 0, /* tp_iter */ 0, /* tp_iternext */ wcsdpservice_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 */ wcsdpservice_initobj, /* tp_init */ PyType_GenericAlloc, /* tp_alloc */ wcsdpservice_new, /* tp_new */ PyObject_Del, /* tp_free */ }; pybluez-0.23/widcomm/util.cpp000066400000000000000000000016271360152363700162640ustar00rootroot00000000000000#include #include "util.h" namespace PyWidcomm { 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, sizeof(buf), uuid_str, 8); uuid->Data1 = strtoul( buf, NULL, 16 ); memset(buf, 0, sizeof(buf)); strncpy_s(buf, sizeof(buf), uuid_str+9, 4); uuid->Data2 = (unsigned short) strtoul( buf, NULL, 16 ); memset(buf, 0, sizeof(buf)); strncpy_s(buf, sizeof(buf), uuid_str+14, 4); uuid->Data3 = (unsigned short) strtoul( buf, NULL, 16 ); memset(buf, 0, sizeof(buf)); strncpy_s(buf, sizeof(buf), uuid_str+19, 4); strncpy_s(buf+4, sizeof(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; } } pybluez-0.23/widcomm/util.h000066400000000000000000000001601360152363700157200ustar00rootroot00000000000000#pragma once #include namespace PyWidcomm { int str2uuid( const char *uuid_str, GUID *uuid); };