diff options
author | Alexander Orlenko <zxteam@gmail.com> | 2010-08-03 19:47:11 +1100 |
---|---|---|
committer | Alexander Orlenko <zxteam@gmail.com> | 2010-08-03 19:47:11 +1100 |
commit | a3829c5c961ac8ba2e90761ce9a07db702501a3a (patch) | |
tree | c71c10e0ed3882e391fb7f860a6b417e67b28d96 | |
parent | 1b0516575b99c06046004771bd2d1d7dbebc06b2 (diff) | |
download | bluez-tools-a3829c5c961ac8ba2e90761ce9a07db702501a3a.tar.gz |
Added support of obex-data-server API
-rw-r--r-- | contrib/bluez-api-4.66-fixed/agent.xml (renamed from contrib/bluezAgent.xml) | 0 | ||||
-rwxr-xr-x | contrib/gen-dbus-gobject.pl | 18 | ||||
-rwxr-xr-x | contrib/generate-all.sh | 14 | ||||
-rw-r--r-- | contrib/obex-data-server-api-0.4.5-fixed.txt | 858 | ||||
-rw-r--r-- | src/Makefile.am | 8 | ||||
-rw-r--r-- | src/lib/marshallers.c | 286 | ||||
-rw-r--r-- | src/lib/marshallers.h | 82 | ||||
-rw-r--r-- | src/lib/marshallers.list | 11 | ||||
-rw-r--r-- | src/lib/obexmanager.c | 263 | ||||
-rw-r--r-- | src/lib/obexmanager.h | 73 | ||||
-rw-r--r-- | src/lib/obexserver.c | 372 | ||||
-rw-r--r-- | src/lib/obexserver.h | 73 | ||||
-rw-r--r-- | src/lib/obexserver_session.c | 350 | ||||
-rw-r--r-- | src/lib/obexserver_session.h | 71 | ||||
-rw-r--r-- | src/lib/obexsession.c | 495 | ||||
-rw-r--r-- | src/lib/obexsession.h | 85 |
16 files changed, 2961 insertions, 98 deletions
diff --git a/contrib/bluezAgent.xml b/contrib/bluez-api-4.66-fixed/agent.xml index 86e442b..86e442b 100644 --- a/contrib/bluezAgent.xml +++ b/contrib/bluez-api-4.66-fixed/agent.xml diff --git a/contrib/gen-dbus-gobject.pl b/contrib/gen-dbus-gobject.pl index 0f893be..8095a91 100755 --- a/contrib/gen-dbus-gobject.pl +++ b/contrib/gen-dbus-gobject.pl @@ -199,7 +199,7 @@ sub get_default_value { my $default_value; $default_value = 'NULL' if $c_type =~ /\*$/; - $default_value = 'FALSE' if $c_type eq 'gboolean'; + $default_value = 'FALSE' if $c_type =~ /boolean/; $default_value = '0' if $c_type =~ /int/; die "unknown C type (3): $c_type\n" unless defined $default_value; @@ -654,6 +654,10 @@ EOT $signals_registration .= "\t\t\tg_cclosure_marshal_VOID__STRING,\n". "\t\t\tG_TYPE_NONE, 1, G_TYPE_STRING);\n\n"; + } elsif ($arg_t eq 'object_string_string') { + $signals_registration .= + "\t\t\tg_cclosure_bluez_marshal_VOID__STRING_STRING_STRING,\n". + "\t\t\tG_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);\n\n"; } elsif ($arg_t eq 'string_variant') { $signals_registration .= "\t\t\tg_cclosure_bluez_marshal_VOID__STRING_BOXED,\n". @@ -666,10 +670,22 @@ EOT $signals_registration .= "\t\t\tg_cclosure_bluez_marshal_VOID__STRING_BOOLEAN,\n". "\t\t\tG_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_BOOLEAN);\n\n"; + } elsif ($arg_t eq 'uint64') { + $signals_registration .= + "\t\t\tg_cclosure_bluez_marshal_VOID__UINT64,\n". + "\t\t\tG_TYPE_NONE, 1, G_TYPE_UINT64);\n\n"; } elsif ($arg_t eq 'int32_int32') { $signals_registration .= "\t\t\tg_cclosure_bluez_marshal_VOID__INT_INT,\n". "\t\t\tG_TYPE_NONE, 2, G_TYPE_INT, G_TYPE_INT);\n\n"; + } elsif ($arg_t eq 'string_string') { + $signals_registration .= + "\t\t\tg_cclosure_bluez_marshal_VOID__STRING_STRING,\n". + "\t\t\tG_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING);\n\n"; + } elsif ($arg_t eq 'string_string_uint64') { + $signals_registration .= + "\t\t\tg_cclosure_bluez_marshal_VOID__STRING_STRING_UINT64,\n". + "\t\t\tG_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT64);\n\n"; } else { die "unknown signal arguments: $arg_t\n"; } diff --git a/contrib/generate-all.sh b/contrib/generate-all.sh index 42ce4b6..30b6c73 100755 --- a/contrib/generate-all.sh +++ b/contrib/generate-all.sh @@ -39,3 +39,17 @@ ./gen-dbus-gobject.pl -header bluez-api-4.66-fixed/serial-api.txt > ../src/lib/serial.h ./gen-dbus-gobject.pl -source bluez-api-4.66-fixed/serial-api.txt > ../src/lib/serial.c +# obex-data-server API + +./gen-dbus-gobject.pl -header obex-data-server-api-0.4.5-fixed.txt > ../src/lib/obexmanager.h +./gen-dbus-gobject.pl -source obex-data-server-api-0.4.5-fixed.txt > ../src/lib/obexmanager.c + +./gen-dbus-gobject.pl -header obex-data-server-api-0.4.5-fixed.txt 2 > ../src/lib/obexserver.h +./gen-dbus-gobject.pl -source obex-data-server-api-0.4.5-fixed.txt 2 > ../src/lib/obexserver.c + +./gen-dbus-gobject.pl -header obex-data-server-api-0.4.5-fixed.txt 3 > ../src/lib/obexsession.h +./gen-dbus-gobject.pl -source obex-data-server-api-0.4.5-fixed.txt 3 > ../src/lib/obexsession.c + +./gen-dbus-gobject.pl -header obex-data-server-api-0.4.5-fixed.txt 4 > ../src/lib/obexserver_session.h +./gen-dbus-gobject.pl -source obex-data-server-api-0.4.5-fixed.txt 4 > ../src/lib/obexserver_session.c + diff --git a/contrib/obex-data-server-api-0.4.5-fixed.txt b/contrib/obex-data-server-api-0.4.5-fixed.txt new file mode 100644 index 0000000..b9a7325 --- /dev/null +++ b/contrib/obex-data-server-api-0.4.5-fixed.txt @@ -0,0 +1,858 @@ +OBEX API description +******************** + +Manager hierarchy +=============================== + +Service org.openobex +Interface org.openobex.Manager +Object path /org/openobex +Object name OBEXManager + +Methods object CreateBluetoothSession(string target_address, string source_address, string pattern) + + Creates a Bluetooth OBEX session and returns the new session object + of type org.openobex.Session. Session is automatically connected. + The target_address represents the remote Bluetooth device, + source_address specifies which Bluetooth adapter to use + (to use default adapter, use "00:00:00:00:00:00") and + the pattern specifies the OBEX service it connects to, + or the OBEX service using a fixed Bluetooth channel. + Pattern can be a UUID-128 identifying the service or + place holder as "opp" (for Object Push) or "ftp" (for FTP). + In case you want to use a fixed channel, UUID has to be + like: UUID:CHANNEL where UUID is a valid UUID or service + place holder like before, and CHANNEL is an integer + representing a valid RFCOMM channel. Session object can + only be used when SessionConnected signal is emitted. + If connection fails (remote device refuses connection, link dies, etc.), + SessionConnectError signal is emitted instead. To cancel + connecting use CancelSessionConnect method. + + Returns object path for the created session. + + Possible errors: org.openobex.Error.InvalidArguments + org.openobex.Error.TransportNotAvailable + + object CreateBluetoothImagingSession(string target_address, string source_addres, string bip_feature) {skiped} + + Create Bluetooth OBEX session using BIP profile and returns new + session object of type org.openobex.Session. target_address + represents the remote Bluetooth device, source_address specifies + which Bluetooth adapter to use ("00:00:00:00:00:00" for default + adapter). bip_feature specifies imaging feature to use + ("imagepush" or "remotedisplay"). In case you want to use a fixed + RFCOMM channel, bip_feature has to be like FEATURE:CHANNEL where + CHANNEL is an integer representing a valid RFCOMM channel. Session + object can only be used when SessionConnected signal is emitted. + If connection fails, SessionConnectError signal is emitted instead. + To cancel connecting use CancelSessionConnect method. + + Returns object path for the created session. + + Possible errors: org.openobex.Error.InvalidArguments + org.openobex.Error.TransportNotAvailable + + object CreateUsbSession(integer interface_number, string profile) {skipped} + + Creates a USB OBEX session and returns the new session object + of type org.openobex.Session. Session is automatically connected. + To find out about available USB OBEX interfaces, use GetUsbInterfacesNum + and GetUsbInterfaceInfo. profile specifies profile to be used for + session (FTP profile is commonly used for USB OBEX sessions). + Session object can only be used when SessionConnected signal is emitted. + If connection fails (remote device refuses connection, link dies, etc.), + SessionConnectError signal is emitted instead. + Do not use CancelSessionConnect with USB sessions (connection is + established instantly). + + Returns object path for the created session. + + Possible errors: org.openobex.Error.InvalidArguments + org.openobex.Error.TransportNotAvailable + + object CreateTtySession(string tty_dev, string profile) {skipped} + + Creates OBEX session using TTY device and returns the new session + object of type org.openobex.Session. Session is automatically + connected. + tty_dev specifies TTY device node. + pattern specifies the profile to be used for session which may be + either "ftp" for OBEX FTP server, "opp" for OBEX Object Push server + or "bip" for OBEX Basic Imaging server. + Session object can only be used when SessionConnected signal is emitted. + If connection fails (remote device refuses connection, link dies, etc.), + SessionConnectError signal is emitted instead. + Do not use CancelSessionConnect with TTY sessions (connection is + established instantly). + + Returns object path for the created session. + + Possible errors: org.openobex.Error.InvalidArguments + + integer GetUsbInterfacesNum() {skipped} + + Returns the number of available USB OBEX interfaces + + Possible errors: none + + dict GetUsbInterfaceInfo(integer interface_number) {skipped} + + Returns info about specified USB OBEX interface: + "Manufacturer" : Manufacturer of the device + "Product" : Product name of the device + "Serial" : Serial number of the device + "Configuration" : USB configuration that this interface belongs to + "ControlInterface" : description of the OBEX control interface, typically + reveals the functionality of the interface + "DataInterfaceIdle" : description of the OBEX data idle interface, typically empty + "DataInterfaceActive" : description of the OBEX data active interface, typically empty + + If specified interface number is too large, returns empty structure. + + Possible errors: none + + boolean CancelSessionConnect(object session_object) + + Cancells session connection. If Session is being connected, + connection will be cancelled and SessionConnectError signal + with org.openobex.Cancelled error will be emitted. If session + is already connected or invalid session is supplied, this function + will do nothing and FALSE will be returned. + + Returns TRUE if cancelled successfully, FALSE otherwise. + + Possible errors: none + + object CreateBluetoothServer(string source_address, string pattern, boolean require_pairing) + + Gets Server object for specified bluetooth source address. + source_address can be Bluetooth address of any adapter or just + "00:00:00:00:00:00" for default adapter. + pattern specifies the type of server to create which may be + either "ftp" for OBEX FTP server, "opp" for OBEX Object Push server + or "bip" for OBEX Basic Imaging server. + require_pairing specifies whether client device should be paired + before allowing any operations (recommended values: True for FTP, + False for OPP). + + Returns object path for the created server. + + Possible errors: org.openobex.Error.Failed + org.openobex.Error.InvalidArguments + org.openobex.Error.TransportNotAvailable + + object CreateTtyServer(string tty_dev, string pattern) {skipped} + + Gets Server object for specified TTY device (e.g. /dev/ttyUSB0). + This kind of server can be used on embedded devices to serve files via USB OBEX. + tty_dev specifies TTY device node. + pattern specifies the type of server which may be + either "ftp" for OBEX FTP server, "opp" for OBEX Object Push server + or "bip" for OBEX Basic Imaging server. + + Return object path for the created server. + + Possible errors: org.openobex.Error.Failed + org.openobex.Error.InvalidArguments + + dict GetSessionInfo(object session_object) + + Returns info about specified session: + "BluetoothTargetAddress" : Target device Bluetooth address (only for Bluetooth sessions); + "BluetoothSourceAddress" : Source Bluetooth address (hci device used) (only for Bluetooth sessions); + "BluetoothChannel" : RFCOMM channel used for session (only for Bluetooth sessions); + "UsbInterfaceNumber" : USB interface number (only for USB sessions); + "TTYDevice" : TTY device which is used (only for TTY sessions); + If specified session does not exist, returns empty structure. + session_object specifies DBus path of Session object. + + Possible errors: none + + dict GetServerInfo(object server_object) + + Returns info about specified server: + "BluetoothSourceAddress" : Bluetooth source address (only for Bluetooth servers); + "RequirePairing" : if connecting to server triggers pairing (only for Bluetooth servers); + "TTYDevice" : TTY device which is used (only for TTY servers); + If specified session does not exist, returns empty structure. + server_object specifies DBus path of Server object. + + Possible errors: none + + array{string} GetSessionList() + + Returns list of open sessions. Array contains DBus paths of sessions. + + Possible errors: none + + array{string} GetServerList() + + Returns list of open servers. Array contains DBus paths of servers. + + Possible errors: none + + string GetVersion() + + Returns obex-data-server version and obex-data-server API version. + Returned string is formated like that: "<ods_ver>:<ods_api_ver>". + API version is an integer. When API incompatible with older one is + released, this number is increased by one. As of ods version 0.4 + API version is 1. Example of returned string: "0.4:1". + + Possible errors: none + +Signals SessionConnected(object path) + + Emitted when Session is connected to target device. + + SessionConnectError(object path, string error_name, string error_message) + + Emitted when Session connection fails. Session object must not be + used after that. + + SessionClosed(object path) + + Emitted when Session is closed and no longer valid. + +Server hierarchy +=============================== + +Service org.openobex +Interface org.openobex.Server +Object path /org/openobex/server{0,1,2...} +Object name OBEXServer + +Methods void Start(string path, boolean allow_write, boolean auto_accept) + + Starts OBEX Object Push / FTP server (begins + listening for connections). Started signal is emitted after + the server is started. If error occurs, ErrorOccurred signal is emitted + instead. Once the server is started, it emits SessionCreated signal + for every newly connected client. + + If this is Object Push server, path defines where all received files + will be saved. In case of FTP server path is the top-level folder which + will be served. allow_write specifies whether write operations + will be allowed (put and delete). In most cases, allow_write should be + set to True. + auto_accept specifies whether incoming files should be always accepted + (recommended values: True for FTP, False for OPP). If auto_accept is + set to False, either Accept() or Reject() has to be called + every time after you receive TransferStarted signal in ServerSession + object. If Accept() or Reject() is not called in 15 seconds after + TransferStarted signal, timeout will happen and the incoming file will + be automatically rejected. It is important to listen for Cancelled + signal on ServerSession object when auto_accept is False because + you can receive Cancelled signal while waiting for user to accept or + reject incoming file. This would effectively mean that timeout happened + and the incoming file was rejected. + + Possible errors: org.openobex.Error.InvalidArguments + org.openobex.Error.NotAuthorized + org.openobex.Error.Started + + void Stop() + + Stops the server. All client connections will be closed and + operations will be cancelled. Stopped signal is emitted + after the server is stopped. + + Possible errors: org.openobex.Error.NotAuthorized + org.openobex.Error.NotStarted + + void Close() + + Closes the server. If server is not stopped, all client connections + will be closed, operations will be cancelled. Server object will + be destroyed after that. Closed signal is emitted immediately + when this method is invoked. + + Possible errors: org.openobex.Error.NotAuthorized + + boolean IsStarted() + + Returns true if server is started, false otherwise. + + Possible errors: none + + void SetOption(string name, variant value) + + Sets server options. Supported options: + "Limit" : maximum server sessions that server will accept + (0 for no limit). Default is 0. Value type is uint16. + "RequireImagingThumbnails" : whether to require clients to send + thumbnails for uploaded images (specific to BIP servers). + Default is False. Value type is boolean. + + Possible errors: org.openobex.Error.InvalidArguments + + dict GetServerSessionInfo(object session_object) + + Returns info about specified server session: + "BluetoothAddress" : Client device Bluetooth address; + If specified server session does not exist, returns empty structure. + session_object specifies DBus path of ServerSession object. + + Possible errors: none + + array{string} GetServerSessionList() + + Returns list of open server sessions. Array contains DBus paths + of server sessions. + + Possible errors: none + +Signals Started() + + This signal informs that the server was started. + + Stopped() + + This signal informs that the server was stopped and all operations + were ceased. + + Closed() + + This signal informs that the server was closed and it's object is + no longer valid. + + ErrorOccurred(string error_name, string error_message) + + This signal informs that error occurred while starting or stopping + the server. + + SessionCreated(object session_object) + + Signal informs that client connected to server and new ServerSession + object was created. Returns path of ServerSession object. + + SessionRemoved(object session_object) + + Signal informs that client disconnected from server. Returns + path of ServerSession object that was closed. + +Session hierarchy +=============================== + +Service org.openobex +Interface org.openobex.Session +Object path /org/openobex/session{0,1,2...} +Object name OBEXSession + +Methods void Disconnect() + + Disconnects from remote device by sending OBEX disconnect command. + Disconnected signal is emitted once disconnected. Normally, + "Close" should be called immediately after Session is disconnected. + + Possible errors: org.openobex.Error.Busy + org.openobex.Error.Failed + org.openobex.Error.NotAuthorized + org.openobex.Error.OutOfMemory + + void Close() + + Closes the session (the actual connection to remote device is closed). + Session object is finalized and can not be used anymore. + Closed signal is emitted once closed. + + Possible errors: org.openobex.Error.Failed + org.openobex.Error.NotAuthorized + + void ChangeCurrentFolder(string path) + + Changes current path on a remote device to the specified one. + This method only returns after operation is finished. + This means that if method returned without any error, + operation is complete (this is in contrast with how file + transfers work). + + Possible errors: org.openobex.Error.Busy + org.openobex.Error.Failed + org.openobex.Error.InvalidArguments + org.openobex.Error.NotAuthorized + org.openobex.Error.NotConnected + org.openobex.Error.OutOfMemory + + void ChangeCurrentFolderBackward() + + Changes current path on a remote device one level up. If current + folder is root, path is not changed. + This method only returns after operation is finished. + This means that if method returned without any error, + operation is complete (this is in contrast with how file + transfers work). + + Possible errors: org.openobex.Error.Busy + org.openobex.Error.Failed + org.openobex.Error.InvalidArguments + org.openobex.Error.NotAuthorized + org.openobex.Error.NotConnected + org.openobex.Error.OutOfMemory + + void ChangeCurrentFolderToRoot() + + Changes current path on a remote device to root. + This method only returns after operation is finished. + This means that if method returned without any error, + operation is complete (this is in contrast with how file + transfers work). + + Possible errors: org.openobex.Error.Busy + org.openobex.Error.Failed + org.openobex.Error.InvalidArguments + org.openobex.Error.NotAuthorized + org.openobex.Error.NotConnected + org.openobex.Error.OutOfMemory + + string GetCurrentPath() + + Returns current path on a remote device. + + Possible errors: none + + void CopyRemoteFile(string remote_filename, string local_path) + + Starts receiving a specified file from a remote device. + remote_filename specifies the file to receive on a remote device. + local_path is the path where received file will be saved. + TransferStarted signal is emitted when transfer starts. If error + occurs during operation, ErrorOccurred signal is emitted instead. + + Possible errors: org.openobex.Error.Busy + org.openobex.Error.Failed + org.openobex.Error.InvalidArguments + org.openobex.Error.NotAuthorized + org.openobex.Error.NotConnected + org.openobex.Error.NotFound + org.openobex.Error.OutOfMemory + + void CopyRemoteFileByType(string type, string local_path) + + Starts receiving default object of specified type from a remote + device. type specifies OBEX type to receive. local_path is the path + where received file will be saved. TransferStarted signal is emitted + when transfer starts. If error occurs during operation, + ErrorOccurred signal is emitted instead. + + Possible errors: org.openobex.Error.Busy + org.openobex.Error.Failed + org.openobex.Error.InvalidArguments + org.openobex.Error.NotAuthorized + org.openobex.Error.NotConnected + org.openobex.Error.NotFound + org.openobex.Error.OutOfMemory + + void CreateFolder(string folder_name) + + Creates a folder on a remote device with a specified + name. This method only returns after operation is finished. + This means that if method returned without any error, + operation is complete (this is in contrast with how file + transfers work). + + Possible errors: org.openobex.Error.Busy + org.openobex.Error.Failed + org.openobex.Error.InvalidArguments + org.openobex.Error.NotAuthorized + org.openobex.Error.NotConnected + org.openobex.Error.OutOfMemory + + string RetrieveFolderListing() + + Retrieves the list of files in the current folder. + The list is XML formatted string. See OBEX specification for + info about the format. + This method only returns after operation is finished. + This means that if method returned without any error, + operation is complete (this is in contrast with how file + transfers work). + + Possible errors: none? + + string GetCapability() + + Retrieves the FTP capability object. + This method only returns after operation is finished. + This means that if method returned without any error, + operation is complete (this is in contrast with how file + transfers work). + + Possible errors: none? + + void SendFile(string local_path) + + Starts sending a specified file to a remote device. + local_path specifies the path to file that will be sent. + TransferStarted signal is emitted when transfer starts. If error + occurs during operation, ErrorOccurred signal is emitted. + + Possible errors: org.openobex.Error.NotAuthorized + org.openobex.Error.NotConnected + org.openobex.Error.Busy + org.openobex.Error.InvalidArguments + org.openobex.Error.OutOfMemory + org.openobex.Error.NotFound + !! org.openobex.Error.Failed + + void SendFileExt(string local_path, string remote_filename, string type) + + Starts sending a specified file to a remote device. It's possible + to specify different filename (remote_filename) than that of local + file. When remote_filename is empty, original filename is used. + type specifies particular OBEX type to send file as. type can be + empty. When type is used, remote_filename must be empty. + TransferStarted signal is emitted when transfer starts. If error + occurs during operation, ErrorOccurred signal is emitted. + + Possible errors: org.openobex.Error.NotAuthorized + org.openobex.Error.NotConnected + org.openobex.Error.Busy + org.openobex.Error.InvalidArguments + org.openobex.Error.OutOfMemory + org.openobex.Error.NotFound + !! org.openobex.Error.Failed + + void DeleteRemoteFile(string remote_filename) + + Deletes specified file on remote device. + This method only returns after operation is finished. + This means that if method returned without any error, + operation is complete (this is in contrast with how file + transfers work). + + Possible errors: org.openobex.Error.Failed + + void RemoteCopy(string remote_source, string remote_destination) + + FTP profile + + Initiates remote copy operation (data is copied from one location + to the other in remote device). remote_source specifies a file + or folder to be copied (this file or folder has to exist in current + directory). remote_destination specifies path where to copy data. + This path can be relative to current folder or relative to root + folder. Both slash ('/') and backslash ('\') symbols can be used in + path. Example source/destination pairs : + 'File.txt' : 'Folder/OtherFolder/NewFile.txt' + 'Folder' : '/Folder/OtherFolder/NewFolder' (relative to root folder) + 'Folder' : 'Folder\NewFolder' + Note that ods does not check remote_destination argument validity. + This method only returns after operation is finished. + This means that if method returned without any error, + operation is complete (this is in contrast with how file + transfers work). + ! This method is not included in official FTP profile specification, + therefore not many devices support it. + + Possible errors: none? + + void RemoteMove(string remote_source, string remote_destination) + + FTP profile + + Initiates remote move operation (data is moved from one location + to the other in remote device). See RemoteCopy method for how the + arguments should be used. + This method only returns after operation is finished. + This means that if method returned without any error, + operation is complete (this is in contrast with how file + transfers work). + ! This method is not included in official FTP profile specification, + therefore not many devices support it. + + Possible errors: none? + + string GetImagingCapabilities() {skipped} + + BIP profile, all features + + Retrieves imaging capabilities object ("x-bt/img-capabilities"). + This method only returns after operation is finished. + This means that if method returned without any error, + operation is complete (this is in contrast with how file + transfers work). + + Possible errors: none? + + void GetImageInfo(string local_path, out uint16 width, out uint16 height, out string encoding) {skipped} + + BIP profile utility function + + Returns image info for specified locally stored image. Returns + width, height and encoding. Can be used to determine how image + should be resized to match remote device preferred image format + specified in imaging capabilities object. + This method only returns after operation is finished. + This means that if method returned without any error, + operation is complete (this is in contrast with how file + transfers work). + + Possible errors: org.openobex.Error.InvalidArguments + org.openobex.Error.NotSupported + org.openobex.Error.Failed + + void PutImage(string local_path) {skipped} + + BIP profile, ImagePush and RemoteDisplay features + + Pushes image to remote device. local_path specifies image filename. + TransferStarted signal is emitted when transfer starts. If error + occurs during operation, ErrorOccurred signal is emitted. When + transfer finishes successfully, ImageHandleReceived signal is + emitted (ImageHandleReceived signal returns image handle for pushed + image to be used in further operations). + + Possible errors: none? + + void PutImageResized(string local_path, uint16 width, uint16 height, string encoding, string transformation) {skipped} + + BIP profile, ImagePush and RemoteDisplay features + + Pushes resized/encoded image to remote device. Client application + should parse ImagingCapabilities object prior to this to acquire + image formats supported by remote device. local_path specifies + original image filename. width and height specify new dimensions. + encoding specifies image format ("JPEG", "PNG", etc.). If encoding + is empty, original encoding will be preserved. See ImageMagick + supported formats list for available values. transformation + defines how image should be resized. Possible transformations are + "stretch" (stretches image to new dimensions), "crop" (crops image) + or "fill" (in case dimensions are bigger than original, image is filled + with white backround). If specified dimensions match the original + dimensions, no resizing will be done. If invalid transformation value + is used, "stretch" will be used by default. + TransferStarted signal is emitted when transfer starts. If error + occurs during operation, ErrorOccurred signal is emitted. When + transfer finishes successfully, ImageHandleReceived signal is + emitted (ImageHandleReceived signal returns image handle for pushed + image to be used in further operations). + + Possible errors: none? + + void PutLinkedAttachment(string image_handle, string local_path, string content_type, string charset) {skipped} + + BIP profile, ImagePush feature + + Pushes attachment linked to previously pushed image. image_handle + specifies handle of previously pushed image, local_path is path + to file to be sent. content_type specifies attachment's MIME + content type, e.g. "text/plain". content_type is optional and can + be empty. charset specifies charset in which attachment is encoded. + charset is also optional and can be empty. Progress of transfer + is reported using TransferStarted, TransferProgress, ErrorOccurred + and TransferCompleted signals. + + Possible errors: none? + + void RemoteDisplaySelectImage(string image_handle) {skipped} + + BIP profile, RemoteDisplay feature + + Selects previously pushed image (using PutImage or PutImageResized + methods). image_handle specifies image handle corresponding to + previously pushed image (returned by ImageHandleReceived signal). + This method only returns after operation is finished. + This means that if method returned without any error, + operation is complete (this is in contrast with how file + transfers work). + + Possible errors: org.openobex.Error.Failed + + void RemoteDisplayShowCurrentImage() {skipped} + + BIP profile, RemoteDisplay feature + + Triggers remote device to show currently selected image. + This method only returns after operation is finished. + This means that if method returned without any error, + operation is complete (this is in contrast with how file + transfers work). + + Possible errors: org.openobex.Error.Failed + + void RemoteDisplayShowNextImage() {skipped} + + BIP profile, RemoteDisplay feature + + Triggers remote device to show next image. + This method only returns after operation is finished. + This means that if method returned without any error, + operation is complete (this is in contrast with how file + transfers work). + + Possible errors: org.openobex.Error.Failed + + void RemoteDisplayShowPreviousImage() {skipped} + + BIP profile, RemoteDisplay feature + + Triggers remote device to show previous image. + This method only returns after operation is finished. + This means that if method returned without any error, + operation is complete (this is in contrast with how file + transfers work). + + Possible errors: org.openobex.Error.Failed + + dict GetTransferInfo() + + Returns info about the ongoing transfer: + "LocalPath" : full local path; + "RemoteFilename" : filename; + "Size" : total bytes being transferred; + "Time" : last modification time of file being sent; + "OBEXCommand" : either "GET" or "PUT"; + + Possible errors: none + + boolean IsBusy() + + Returns true if there is an operation in progress, false otherwise. + + Possible errors: none + + void Cancel() + + Cancels any operation that is in progress. + + Possible errors: org.openobex.Error.Failed + +Signals Cancelled() + + This signal informs that the current transfer was cancelled either by + client or by server. + + Disconnected() + + This signal informs that the session was disconnected. + + Closed() + + This signal informs that the session was terminated and that it's object + is no longer valid. + + TransferStarted(string filename, string local_path, uint64 total_bytes) + + This signal informs that transfer was started. + + total_bytes is the number of total bytes that are being sent (0 + if total bytes are unknown). filename specifies the filename (without + path) of file being sent or null if it is unknown. local_path specifies + where the file is stored locally. + + TransferProgress(uint64 bytes_transferred) + + This signal is emitted constantly during the transfer. + bytes_transferred specifies how many bytes were already transferred. + + TransferCompleted() + + This signal informs that transfer was completed. + + ErrorOccurred(string error_name, string error_message) + + This signal informs that error occurred while performing some operation. + + ImageHandleReceived(string image_handle, boolean thumbnail_requested) {skipped} + + This signal returns image handle for pushed image (using PutImage or + PutImageResized). thumbnail_requested specifies whether Imaging + Responder requested client to send thumbnail. If thumbnail was + requested, TransferStarted/TransferProgress/TransferCompleted + signals will be emitted when transferring thumbnail. + +ServerSession hierarchy +=============================== + +Service org.openobex +Interface org.openobex.ServerSession +Object path /org/openobex/serversession{0,1,2...} +Object name OBEXServerSession + +Methods void Accept() + + Accepts incoming file (use this when auto_accept is set to False for + corresponding Server object). If auto_accept is True, this function will + do nothing. Call this method just after receiving TransferStarted signal. + If there is no transfer in progress or if current transfer is not + an incoming transfer, error will be returned. If you do not call + Accept() or Reject() in 15 seconds after TransferStarted signal, + incoming file will be automatically rejected and you will receive + Cancelled signal. + + Possible errors: org.openobex.Error.Failed + + void Reject() + + Rejects incoming file (use this when auto_accept is set to False for + corresponding Server object). If auto_accept is True, this function will + do nothing. Call this method just after receiving TransferStarted signal. + If there is no transfer in progress or if current transfer is not + an incoming transfer, error will be returned. If you do not call + Accept() or Reject() in 15 seconds after TransferStarted signal, + incoming file will be automatically rejected and you will receive + Cancelled signal. + + Possible errors: org.openobex.Error.Failed + + void Disconnect() + + Disconnects from remote device. + ServerSession object is finalized and can not be used anymore. + Disconnected signal is emitted once disconnected. + + Possible errors: none? + + dict GetTransferInfo() + + Returns all info about the ongoing transfer (filename, local path, + total bytes). + + Possible errors: none + + void Cancel() + + Cancels any operation that is in progress. + + Possible errors: org.openobex.Error.Failed + +Signals Cancelled() + + This signal informs that the current transfer was cancelled either by + client or by server. + + Disconnected() + + This signal informs that the ServerSession was disconnected. + ServerSession object is finalized and can not be used anymore. + + TransferStarted(string filename, string local_path, uint64 total_bytes) + + This signal informs that transfer was started. + + total_bytes is the number of total bytes that are being sent (0 + if total bytes are unknown). filename specifies the filename (without + path) of file being sent or null if it is unknown. local_path specifies + where the file is stored locally. + + TransferProgress(uint64 bytes_transferred) + + This signal is emitted constantly during the transfer. + bytes_transferred specifies how many bytes were already transferred. + + TransferCompleted() + + This signal informs that transfer was completed. + + ErrorOccurred(string error_name, string error_message) + + This signal informs that error occurred while performing some operation. + + RemoteDisplayRequested(string filename) {skipped} + + This signal is used for Imaging sessions that use Remote Display + feature. Signal informs that remote device requested display of + previously uploaded image. filename specifies the filename of image + to be displayed. diff --git a/src/Makefile.am b/src/Makefile.am index aab0406..4e499fd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -28,7 +28,12 @@ lib_sources = lib/marshallers.c lib/marshallers.h \ lib/serial.c lib/serial.h \ lib/sdp.c lib/sdp.h -bin_PROGRAMS = bt-monitor bt-adapter bt-agent bt-device bt-input bt-audio bt-network bt-serial +obex_sources = lib/obexmanager.c lib/obexmanager.h \ + lib/obexsession.c lib/obexsession.h \ + lib/obexserver.c lib/obexserver.h \ + lib/obexserver_session.c lib/obexserver_session.h + +bin_PROGRAMS = bt-monitor bt-adapter bt-agent bt-device bt-input bt-audio bt-network bt-serial bt-obex bt_monitor_SOURCES = $(lib_sources) bt-monitor.c bt_adapter_SOURCES = ${lib_sources} bt-adapter.c bt_agent_SOURCES = $(lib_sources) bt-agent.c @@ -37,6 +42,7 @@ bt_input_SOURCES = $(lib_sources) bt-input.c bt_audio_SOURCES = $(lib_sources) bt-audio.c bt_network_SOURCES = $(lib_sources) bt-network.c bt_serial_SOURCES = $(lib_sources) bt-serial.c +bt_obex_SOURCES = $(lib_sources) $(obex_sources) bt-obex.c #CLEANFILES = Makefile.in lib/marshallers.c lib/marshallers.h diff --git a/src/lib/marshallers.c b/src/lib/marshallers.c index 80801c6..8391165 100644 --- a/src/lib/marshallers.c +++ b/src/lib/marshallers.c @@ -47,7 +47,42 @@ #endif /* !G_ENABLE_DEBUG */ -/* VOID:STRING,BOXED (lib/marshallers.list:1) */ +/* VOID:UINT64 (lib/marshallers.list:1) */ +void +g_cclosure_bluez_marshal_VOID__UINT64 (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef void (*GMarshalFunc_VOID__UINT64) (gpointer data1, + guint64 arg_1, + gpointer data2); + register GMarshalFunc_VOID__UINT64 callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + + g_return_if_fail (n_param_values == 2); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_VOID__UINT64) (marshal_data ? marshal_data : cc->callback); + + callback (data1, + g_marshal_value_peek_uint64 (param_values + 1), + data2); +} + +/* VOID:STRING,BOXED (lib/marshallers.list:2) */ void g_cclosure_bluez_marshal_VOID__STRING_BOXED (GClosure *closure, GValue *return_value G_GNUC_UNUSED, @@ -84,28 +119,24 @@ g_cclosure_bluez_marshal_VOID__STRING_BOXED (GClosure *closure, data2); } -/* BOOLEAN:BOXED,UINT,UCHAR,POINTER (lib/marshallers.list:2) */ +/* VOID:STRING,STRING (lib/marshallers.list:3) */ void -g_cclosure_bluez_marshal_BOOLEAN__BOXED_UINT_UCHAR_POINTER (GClosure *closure, - GValue *return_value G_GNUC_UNUSED, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint G_GNUC_UNUSED, - gpointer marshal_data) +g_cclosure_bluez_marshal_VOID__STRING_STRING (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) { - typedef gboolean (*GMarshalFunc_BOOLEAN__BOXED_UINT_UCHAR_POINTER) (gpointer data1, - gpointer arg_1, - guint arg_2, - guchar arg_3, - gpointer arg_4, - gpointer data2); - register GMarshalFunc_BOOLEAN__BOXED_UINT_UCHAR_POINTER callback; + typedef void (*GMarshalFunc_VOID__STRING_STRING) (gpointer data1, + gpointer arg_1, + gpointer arg_2, + gpointer data2); + register GMarshalFunc_VOID__STRING_STRING callback; register GCClosure *cc = (GCClosure*) closure; register gpointer data1, data2; - gboolean v_return; - g_return_if_fail (return_value != NULL); - g_return_if_fail (n_param_values == 5); + g_return_if_fail (n_param_values == 3); if (G_CCLOSURE_SWAP_DATA (closure)) { @@ -117,38 +148,32 @@ g_cclosure_bluez_marshal_BOOLEAN__BOXED_UINT_UCHAR_POINTER (GClosure *closur data1 = g_value_peek_pointer (param_values + 0); data2 = closure->data; } - callback = (GMarshalFunc_BOOLEAN__BOXED_UINT_UCHAR_POINTER) (marshal_data ? marshal_data : cc->callback); + callback = (GMarshalFunc_VOID__STRING_STRING) (marshal_data ? marshal_data : cc->callback); - v_return = callback (data1, - g_marshal_value_peek_boxed (param_values + 1), - g_marshal_value_peek_uint (param_values + 2), - g_marshal_value_peek_uchar (param_values + 3), - g_marshal_value_peek_pointer (param_values + 4), - data2); - - g_value_set_boolean (return_value, v_return); + callback (data1, + g_marshal_value_peek_string (param_values + 1), + g_marshal_value_peek_string (param_values + 2), + data2); } -/* BOOLEAN:BOXED,STRING,POINTER (lib/marshallers.list:3) */ +/* VOID:STRING,STRING,STRING (lib/marshallers.list:4) */ void -g_cclosure_bluez_marshal_BOOLEAN__BOXED_STRING_POINTER (GClosure *closure, - GValue *return_value G_GNUC_UNUSED, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint G_GNUC_UNUSED, - gpointer marshal_data) +g_cclosure_bluez_marshal_VOID__STRING_STRING_STRING (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) { - typedef gboolean (*GMarshalFunc_BOOLEAN__BOXED_STRING_POINTER) (gpointer data1, - gpointer arg_1, - gpointer arg_2, - gpointer arg_3, - gpointer data2); - register GMarshalFunc_BOOLEAN__BOXED_STRING_POINTER callback; + typedef void (*GMarshalFunc_VOID__STRING_STRING_STRING) (gpointer data1, + gpointer arg_1, + gpointer arg_2, + gpointer arg_3, + gpointer data2); + register GMarshalFunc_VOID__STRING_STRING_STRING callback; register GCClosure *cc = (GCClosure*) closure; register gpointer data1, data2; - gboolean v_return; - g_return_if_fail (return_value != NULL); g_return_if_fail (n_param_values == 4); if (G_CCLOSURE_SWAP_DATA (closure)) @@ -161,18 +186,55 @@ g_cclosure_bluez_marshal_BOOLEAN__BOXED_STRING_POINTER (GClosure *closure, data1 = g_value_peek_pointer (param_values + 0); data2 = closure->data; } - callback = (GMarshalFunc_BOOLEAN__BOXED_STRING_POINTER) (marshal_data ? marshal_data : cc->callback); + callback = (GMarshalFunc_VOID__STRING_STRING_STRING) (marshal_data ? marshal_data : cc->callback); - v_return = callback (data1, - g_marshal_value_peek_boxed (param_values + 1), - g_marshal_value_peek_string (param_values + 2), - g_marshal_value_peek_pointer (param_values + 3), - data2); + callback (data1, + g_marshal_value_peek_string (param_values + 1), + g_marshal_value_peek_string (param_values + 2), + g_marshal_value_peek_string (param_values + 3), + data2); +} - g_value_set_boolean (return_value, v_return); +/* VOID:STRING,STRING,UINT64 (lib/marshallers.list:5) */ +void +g_cclosure_bluez_marshal_VOID__STRING_STRING_UINT64 (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef void (*GMarshalFunc_VOID__STRING_STRING_UINT64) (gpointer data1, + gpointer arg_1, + gpointer arg_2, + guint64 arg_3, + gpointer data2); + register GMarshalFunc_VOID__STRING_STRING_UINT64 callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + + g_return_if_fail (n_param_values == 4); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_VOID__STRING_STRING_UINT64) (marshal_data ? marshal_data : cc->callback); + + callback (data1, + g_marshal_value_peek_string (param_values + 1), + g_marshal_value_peek_string (param_values + 2), + g_marshal_value_peek_uint64 (param_values + 3), + data2); } -/* BOOLEAN:POINTER (lib/marshallers.list:4) */ +/* BOOLEAN:POINTER (lib/marshallers.list:7) */ void g_cclosure_bluez_marshal_BOOLEAN__POINTER (GClosure *closure, GValue *return_value G_GNUC_UNUSED, @@ -211,7 +273,91 @@ g_cclosure_bluez_marshal_BOOLEAN__POINTER (GClosure *closure, g_value_set_boolean (return_value, v_return); } -/* BOOLEAN:BOXED,POINTER,POINTER (lib/marshallers.list:5) */ +/* BOOLEAN:STRING,POINTER (lib/marshallers.list:8) */ +void +g_cclosure_bluez_marshal_BOOLEAN__STRING_POINTER (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef gboolean (*GMarshalFunc_BOOLEAN__STRING_POINTER) (gpointer data1, + gpointer arg_1, + gpointer arg_2, + gpointer data2); + register GMarshalFunc_BOOLEAN__STRING_POINTER callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + gboolean v_return; + + g_return_if_fail (return_value != NULL); + g_return_if_fail (n_param_values == 3); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_BOOLEAN__STRING_POINTER) (marshal_data ? marshal_data : cc->callback); + + v_return = callback (data1, + g_marshal_value_peek_string (param_values + 1), + g_marshal_value_peek_pointer (param_values + 2), + data2); + + g_value_set_boolean (return_value, v_return); +} + +/* BOOLEAN:BOXED,STRING,POINTER (lib/marshallers.list:9) */ +void +g_cclosure_bluez_marshal_BOOLEAN__BOXED_STRING_POINTER (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) +{ + typedef gboolean (*GMarshalFunc_BOOLEAN__BOXED_STRING_POINTER) (gpointer data1, + gpointer arg_1, + gpointer arg_2, + gpointer arg_3, + gpointer data2); + register GMarshalFunc_BOOLEAN__BOXED_STRING_POINTER callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + gboolean v_return; + + g_return_if_fail (return_value != NULL); + g_return_if_fail (n_param_values == 4); + + if (G_CCLOSURE_SWAP_DATA (closure)) + { + data1 = closure->data; + data2 = g_value_peek_pointer (param_values + 0); + } + else + { + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + } + callback = (GMarshalFunc_BOOLEAN__BOXED_STRING_POINTER) (marshal_data ? marshal_data : cc->callback); + + v_return = callback (data1, + g_marshal_value_peek_boxed (param_values + 1), + g_marshal_value_peek_string (param_values + 2), + g_marshal_value_peek_pointer (param_values + 3), + data2); + + g_value_set_boolean (return_value, v_return); +} + +/* BOOLEAN:BOXED,POINTER,POINTER (lib/marshallers.list:10) */ void g_cclosure_bluez_marshal_BOOLEAN__BOXED_POINTER_POINTER (GClosure *closure, GValue *return_value G_GNUC_UNUSED, @@ -254,7 +400,7 @@ g_cclosure_bluez_marshal_BOOLEAN__BOXED_POINTER_POINTER (GClosure *closure, g_value_set_boolean (return_value, v_return); } -/* BOOLEAN:BOXED,UINT,POINTER (lib/marshallers.list:6) */ +/* BOOLEAN:BOXED,UINT,POINTER (lib/marshallers.list:11) */ void g_cclosure_bluez_marshal_BOOLEAN__BOXED_UINT_POINTER (GClosure *closure, GValue *return_value G_GNUC_UNUSED, @@ -297,26 +443,28 @@ g_cclosure_bluez_marshal_BOOLEAN__BOXED_UINT_POINTER (GClosure *closure, g_value_set_boolean (return_value, v_return); } -/* BOOLEAN:STRING,POINTER (lib/marshallers.list:7) */ +/* BOOLEAN:BOXED,UINT,UCHAR,POINTER (lib/marshallers.list:12) */ void -g_cclosure_bluez_marshal_BOOLEAN__STRING_POINTER (GClosure *closure, - GValue *return_value G_GNUC_UNUSED, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint G_GNUC_UNUSED, - gpointer marshal_data) +g_cclosure_bluez_marshal_BOOLEAN__BOXED_UINT_UCHAR_POINTER (GClosure *closure, + GValue *return_value G_GNUC_UNUSED, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint G_GNUC_UNUSED, + gpointer marshal_data) { - typedef gboolean (*GMarshalFunc_BOOLEAN__STRING_POINTER) (gpointer data1, - gpointer arg_1, - gpointer arg_2, - gpointer data2); - register GMarshalFunc_BOOLEAN__STRING_POINTER callback; + typedef gboolean (*GMarshalFunc_BOOLEAN__BOXED_UINT_UCHAR_POINTER) (gpointer data1, + gpointer arg_1, + guint arg_2, + guchar arg_3, + gpointer arg_4, + gpointer data2); + register GMarshalFunc_BOOLEAN__BOXED_UINT_UCHAR_POINTER callback; register GCClosure *cc = (GCClosure*) closure; register gpointer data1, data2; gboolean v_return; g_return_if_fail (return_value != NULL); - g_return_if_fail (n_param_values == 3); + g_return_if_fail (n_param_values == 5); if (G_CCLOSURE_SWAP_DATA (closure)) { @@ -328,11 +476,13 @@ g_cclosure_bluez_marshal_BOOLEAN__STRING_POINTER (GClosure *closure, data1 = g_value_peek_pointer (param_values + 0); data2 = closure->data; } - callback = (GMarshalFunc_BOOLEAN__STRING_POINTER) (marshal_data ? marshal_data : cc->callback); + callback = (GMarshalFunc_BOOLEAN__BOXED_UINT_UCHAR_POINTER) (marshal_data ? marshal_data : cc->callback); v_return = callback (data1, - g_marshal_value_peek_string (param_values + 1), - g_marshal_value_peek_pointer (param_values + 2), + g_marshal_value_peek_boxed (param_values + 1), + g_marshal_value_peek_uint (param_values + 2), + g_marshal_value_peek_uchar (param_values + 3), + g_marshal_value_peek_pointer (param_values + 4), data2); g_value_set_boolean (return_value, v_return); diff --git a/src/lib/marshallers.h b/src/lib/marshallers.h index 121b114..d5b7555 100644 --- a/src/lib/marshallers.h +++ b/src/lib/marshallers.h @@ -6,7 +6,15 @@ G_BEGIN_DECLS -/* VOID:STRING,BOXED (lib/marshallers.list:1) */ +/* VOID:UINT64 (lib/marshallers.list:1) */ +extern void g_cclosure_bluez_marshal_VOID__UINT64 (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); + +/* VOID:STRING,BOXED (lib/marshallers.list:2) */ extern void g_cclosure_bluez_marshal_VOID__STRING_BOXED (GClosure *closure, GValue *return_value, guint n_param_values, @@ -14,23 +22,31 @@ extern void g_cclosure_bluez_marshal_VOID__STRING_BOXED (GClosure *closure, gpointer invocation_hint, gpointer marshal_data); -/* BOOLEAN:BOXED,UINT,UCHAR,POINTER (lib/marshallers.list:2) */ -extern void g_cclosure_bluez_marshal_BOOLEAN__BOXED_UINT_UCHAR_POINTER (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data); +/* VOID:STRING,STRING (lib/marshallers.list:3) */ +extern void g_cclosure_bluez_marshal_VOID__STRING_STRING (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); -/* BOOLEAN:BOXED,STRING,POINTER (lib/marshallers.list:3) */ -extern void g_cclosure_bluez_marshal_BOOLEAN__BOXED_STRING_POINTER (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data); +/* VOID:STRING,STRING,STRING (lib/marshallers.list:4) */ +extern void g_cclosure_bluez_marshal_VOID__STRING_STRING_STRING (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); -/* BOOLEAN:POINTER (lib/marshallers.list:4) */ +/* VOID:STRING,STRING,UINT64 (lib/marshallers.list:5) */ +extern void g_cclosure_bluez_marshal_VOID__STRING_STRING_UINT64 (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); + +/* BOOLEAN:POINTER (lib/marshallers.list:7) */ extern void g_cclosure_bluez_marshal_BOOLEAN__POINTER (GClosure *closure, GValue *return_value, guint n_param_values, @@ -38,7 +54,23 @@ extern void g_cclosure_bluez_marshal_BOOLEAN__POINTER (GClosure *closure, gpointer invocation_hint, gpointer marshal_data); -/* BOOLEAN:BOXED,POINTER,POINTER (lib/marshallers.list:5) */ +/* BOOLEAN:STRING,POINTER (lib/marshallers.list:8) */ +extern void g_cclosure_bluez_marshal_BOOLEAN__STRING_POINTER (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); + +/* BOOLEAN:BOXED,STRING,POINTER (lib/marshallers.list:9) */ +extern void g_cclosure_bluez_marshal_BOOLEAN__BOXED_STRING_POINTER (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); + +/* BOOLEAN:BOXED,POINTER,POINTER (lib/marshallers.list:10) */ extern void g_cclosure_bluez_marshal_BOOLEAN__BOXED_POINTER_POINTER (GClosure *closure, GValue *return_value, guint n_param_values, @@ -46,7 +78,7 @@ extern void g_cclosure_bluez_marshal_BOOLEAN__BOXED_POINTER_POINTER (GClosure gpointer invocation_hint, gpointer marshal_data); -/* BOOLEAN:BOXED,UINT,POINTER (lib/marshallers.list:6) */ +/* BOOLEAN:BOXED,UINT,POINTER (lib/marshallers.list:11) */ extern void g_cclosure_bluez_marshal_BOOLEAN__BOXED_UINT_POINTER (GClosure *closure, GValue *return_value, guint n_param_values, @@ -54,13 +86,13 @@ extern void g_cclosure_bluez_marshal_BOOLEAN__BOXED_UINT_POINTER (GClosure * gpointer invocation_hint, gpointer marshal_data); -/* BOOLEAN:STRING,POINTER (lib/marshallers.list:7) */ -extern void g_cclosure_bluez_marshal_BOOLEAN__STRING_POINTER (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data); +/* BOOLEAN:BOXED,UINT,UCHAR,POINTER (lib/marshallers.list:12) */ +extern void g_cclosure_bluez_marshal_BOOLEAN__BOXED_UINT_UCHAR_POINTER (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); G_END_DECLS diff --git a/src/lib/marshallers.list b/src/lib/marshallers.list index 4096a34..93ec5f6 100644 --- a/src/lib/marshallers.list +++ b/src/lib/marshallers.list @@ -1,7 +1,12 @@ +VOID:UINT64 VOID:STRING,BOXED -BOOLEAN:BOXED,UINT,UCHAR,POINTER -BOOLEAN:BOXED,STRING,POINTER +VOID:STRING,STRING +VOID:STRING,STRING,STRING +VOID:STRING,STRING,UINT64 + BOOLEAN:POINTER +BOOLEAN:STRING,POINTER +BOOLEAN:BOXED,STRING,POINTER BOOLEAN:BOXED,POINTER,POINTER BOOLEAN:BOXED,UINT,POINTER -BOOLEAN:STRING,POINTER +BOOLEAN:BOXED,UINT,UCHAR,POINTER diff --git a/src/lib/obexmanager.c b/src/lib/obexmanager.c new file mode 100644 index 0000000..f207084 --- /dev/null +++ b/src/lib/obexmanager.c @@ -0,0 +1,263 @@ +/* + * + * bluez-tools - a set of tools to manage bluetooth devices for linux + * + * Copyright (C) 2010 Alexander Orlenko <zxteam@gmail.com> + * + * + * 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 + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <glib.h> +#include <string.h> + +#include "dbus-common.h" +#include "marshallers.h" +#include "obexmanager.h" + +#define OBEXMANAGER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), OBEXMANAGER_TYPE, OBEXManagerPrivate)) + +struct _OBEXManagerPrivate { + DBusGProxy *dbus_g_proxy; + + /* Introspection data */ + DBusGProxy *introspection_g_proxy; + gchar *introspection_xml; +}; + +G_DEFINE_TYPE(OBEXManager, obexmanager, G_TYPE_OBJECT); + +enum { + SESSION_CLOSED, + SESSION_CONNECT_ERROR, + SESSION_CONNECTED, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = {0}; + +static void session_closed_handler(DBusGProxy *dbus_g_proxy, const gchar *path, gpointer data); +static void session_connect_error_handler(DBusGProxy *dbus_g_proxy, const gchar *path, const gchar *error_name, const gchar *error_message, gpointer data); +static void session_connected_handler(DBusGProxy *dbus_g_proxy, const gchar *path, gpointer data); + +static void obexmanager_dispose(GObject *gobject) +{ + OBEXManager *self = OBEXMANAGER(gobject); + + /* DBus signals disconnection */ + dbus_g_proxy_disconnect_signal(self->priv->dbus_g_proxy, "SessionClosed", G_CALLBACK(session_closed_handler), self); + dbus_g_proxy_disconnect_signal(self->priv->dbus_g_proxy, "SessionConnectError", G_CALLBACK(session_connect_error_handler), self); + dbus_g_proxy_disconnect_signal(self->priv->dbus_g_proxy, "SessionConnected", G_CALLBACK(session_connected_handler), self); + + /* Proxy free */ + g_object_unref(self->priv->dbus_g_proxy); + + /* Introspection data free */ + g_free(self->priv->introspection_xml); + g_object_unref(self->priv->introspection_g_proxy); + + /* Chain up to the parent class */ + G_OBJECT_CLASS(obexmanager_parent_class)->dispose(gobject); +} + +static void obexmanager_class_init(OBEXManagerClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS(klass); + + gobject_class->dispose = obexmanager_dispose; + + g_type_class_add_private(klass, sizeof(OBEXManagerPrivate)); + + /* Signals registation */ + signals[SESSION_CLOSED] = g_signal_new("SessionClosed", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, + 0, NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, G_TYPE_STRING); + + signals[SESSION_CONNECT_ERROR] = g_signal_new("SessionConnectError", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, + 0, NULL, NULL, + g_cclosure_bluez_marshal_VOID__STRING_STRING_STRING, + G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING); + + signals[SESSION_CONNECTED] = g_signal_new("SessionConnected", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, + 0, NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, G_TYPE_STRING); +} + +static void obexmanager_init(OBEXManager *self) +{ + self->priv = OBEXMANAGER_GET_PRIVATE(self); + + g_assert(conn != NULL); + + GError *error = NULL; + + /* Getting introspection XML */ + self->priv->introspection_g_proxy = dbus_g_proxy_new_for_name(conn, BLUEZ_DBUS_NAME, BLUEZ_DBUS_OBEXMANAGER_PATH, "org.freedesktop.DBus.Introspectable"); + self->priv->introspection_xml = NULL; + if (!dbus_g_proxy_call(self->priv->introspection_g_proxy, "Introspect", &error, G_TYPE_INVALID, G_TYPE_STRING, &self->priv->introspection_xml, G_TYPE_INVALID)) { + g_critical("%s", error->message); + } + g_assert(error == NULL); + + gchar *check_intf_regex_str = g_strconcat("<interface name=\"", BLUEZ_DBUS_OBEXMANAGER_INTERFACE, "\">", NULL); + if (!g_regex_match_simple(check_intf_regex_str, self->priv->introspection_xml, 0, 0)) { + g_critical("Interface \"%s\" does not exist in \"%s\"", BLUEZ_DBUS_OBEXMANAGER_INTERFACE, BLUEZ_DBUS_OBEXMANAGER_PATH); + g_assert(FALSE); + } + g_free(check_intf_regex_str); + + self->priv->dbus_g_proxy = dbus_g_proxy_new_for_name(conn, BLUEZ_DBUS_NAME, BLUEZ_DBUS_OBEXMANAGER_PATH, BLUEZ_DBUS_OBEXMANAGER_INTERFACE); + + /* DBus signals connection */ + + /* SessionClosed(object path) */ + dbus_g_proxy_add_signal(self->priv->dbus_g_proxy, "SessionClosed", DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); + dbus_g_proxy_connect_signal(self->priv->dbus_g_proxy, "SessionClosed", G_CALLBACK(session_closed_handler), self, NULL); + + /* SessionConnectError(object path, string error_name, string error_message) */ + dbus_g_proxy_add_signal(self->priv->dbus_g_proxy, "SessionConnectError", DBUS_TYPE_G_OBJECT_PATH, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID); + dbus_g_proxy_connect_signal(self->priv->dbus_g_proxy, "SessionConnectError", G_CALLBACK(session_connect_error_handler), self, NULL); + + /* SessionConnected(object path) */ + dbus_g_proxy_add_signal(self->priv->dbus_g_proxy, "SessionConnected", DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); + dbus_g_proxy_connect_signal(self->priv->dbus_g_proxy, "SessionConnected", G_CALLBACK(session_connected_handler), self, NULL); +} + +/* Methods */ + +/* boolean CancelSessionConnect(object session_object) */ +gboolean obexmanager_cancel_session_connect(OBEXManager *self, const gchar *session_object, GError **error) +{ + g_assert(OBEXMANAGER_IS(self)); + + gboolean ret = FALSE; + dbus_g_proxy_call(self->priv->dbus_g_proxy, "CancelSessionConnect", error, DBUS_TYPE_G_OBJECT_PATH, session_object, G_TYPE_INVALID, G_TYPE_BOOLEAN, &ret, G_TYPE_INVALID); + + return ret; +} + +/* object CreateBluetoothServer(string source_address, string pattern, boolean require_pairing) */ +gchar *obexmanager_create_bluetooth_server(OBEXManager *self, const gchar *source_address, const gchar *pattern, const gboolean require_pairing, GError **error) +{ + g_assert(OBEXMANAGER_IS(self)); + + gchar *ret = NULL; + dbus_g_proxy_call(self->priv->dbus_g_proxy, "CreateBluetoothServer", error, G_TYPE_STRING, source_address, G_TYPE_STRING, pattern, G_TYPE_BOOLEAN, require_pairing, G_TYPE_INVALID, DBUS_TYPE_G_OBJECT_PATH, &ret, G_TYPE_INVALID); + + return ret; +} + +/* object CreateBluetoothSession(string target_address, string source_address, string pattern) */ +gchar *obexmanager_create_bluetooth_session(OBEXManager *self, const gchar *target_address, const gchar *source_address, const gchar *pattern, GError **error) +{ + g_assert(OBEXMANAGER_IS(self)); + + gchar *ret = NULL; + dbus_g_proxy_call(self->priv->dbus_g_proxy, "CreateBluetoothSession", error, G_TYPE_STRING, target_address, G_TYPE_STRING, source_address, G_TYPE_STRING, pattern, G_TYPE_INVALID, DBUS_TYPE_G_OBJECT_PATH, &ret, G_TYPE_INVALID); + + return ret; +} + +/* dict GetServerInfo(object server_object) */ +GHashTable *obexmanager_get_server_info(OBEXManager *self, const gchar *server_object, GError **error) +{ + g_assert(OBEXMANAGER_IS(self)); + + GHashTable *ret = NULL; + dbus_g_proxy_call(self->priv->dbus_g_proxy, "GetServerInfo", error, DBUS_TYPE_G_OBJECT_PATH, server_object, G_TYPE_INVALID, DBUS_TYPE_G_STRING_VARIANT_HASHTABLE, &ret, G_TYPE_INVALID); + + return ret; +} + +/* array{string} GetServerList() */ +gchar **obexmanager_get_server_list(OBEXManager *self, GError **error) +{ + g_assert(OBEXMANAGER_IS(self)); + + gchar **ret = NULL; + dbus_g_proxy_call(self->priv->dbus_g_proxy, "GetServerList", error, G_TYPE_INVALID, G_TYPE_STRV, &ret, G_TYPE_INVALID); + + return ret; +} + +/* dict GetSessionInfo(object session_object) */ +GHashTable *obexmanager_get_session_info(OBEXManager *self, const gchar *session_object, GError **error) +{ + g_assert(OBEXMANAGER_IS(self)); + + GHashTable *ret = NULL; + dbus_g_proxy_call(self->priv->dbus_g_proxy, "GetSessionInfo", error, DBUS_TYPE_G_OBJECT_PATH, session_object, G_TYPE_INVALID, DBUS_TYPE_G_STRING_VARIANT_HASHTABLE, &ret, G_TYPE_INVALID); + + return ret; +} + +/* array{string} GetSessionList() */ +gchar **obexmanager_get_session_list(OBEXManager *self, GError **error) +{ + g_assert(OBEXMANAGER_IS(self)); + + gchar **ret = NULL; + dbus_g_proxy_call(self->priv->dbus_g_proxy, "GetSessionList", error, G_TYPE_INVALID, G_TYPE_STRV, &ret, G_TYPE_INVALID); + + return ret; +} + +/* string GetVersion() */ +gchar *obexmanager_get_version(OBEXManager *self, GError **error) +{ + g_assert(OBEXMANAGER_IS(self)); + + gchar *ret = NULL; + dbus_g_proxy_call(self->priv->dbus_g_proxy, "GetVersion", error, G_TYPE_INVALID, G_TYPE_STRING, &ret, G_TYPE_INVALID); + + return ret; +} + +/* Signals handlers */ +static void session_closed_handler(DBusGProxy *dbus_g_proxy, const gchar *path, gpointer data) +{ + OBEXManager *self = OBEXMANAGER(data); + + g_signal_emit(self, signals[SESSION_CLOSED], 0, path); +} + +static void session_connect_error_handler(DBusGProxy *dbus_g_proxy, const gchar *path, const gchar *error_name, const gchar *error_message, gpointer data) +{ + OBEXManager *self = OBEXMANAGER(data); + + g_signal_emit(self, signals[SESSION_CONNECT_ERROR], 0, path, error_name, error_message); +} + +static void session_connected_handler(DBusGProxy *dbus_g_proxy, const gchar *path, gpointer data) +{ + OBEXManager *self = OBEXMANAGER(data); + + g_signal_emit(self, signals[SESSION_CONNECTED], 0, path); +} + diff --git a/src/lib/obexmanager.h b/src/lib/obexmanager.h new file mode 100644 index 0000000..f5964f2 --- /dev/null +++ b/src/lib/obexmanager.h @@ -0,0 +1,73 @@ +/* + * + * bluez-tools - a set of tools to manage bluetooth devices for linux + * + * Copyright (C) 2010 Alexander Orlenko <zxteam@gmail.com> + * + * + * 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 + * + */ + +#ifndef __OBEXMANAGER_H +#define __OBEXMANAGER_H + +#include <glib-object.h> + +#define BLUEZ_DBUS_OBEXMANAGER_PATH "/org/openobex" +#define BLUEZ_DBUS_OBEXMANAGER_INTERFACE "org.openobex.Manager" + +/* + * Type macros + */ +#define OBEXMANAGER_TYPE (obexmanager_get_type()) +#define OBEXMANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), OBEXMANAGER_TYPE, OBEXManager)) +#define OBEXMANAGER_IS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), OBEXMANAGER_TYPE)) +#define OBEXMANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), OBEXMANAGER_TYPE, OBEXManagerClass)) +#define OBEXMANAGER_IS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), OBEXMANAGER_TYPE)) +#define OBEXMANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), OBEXMANAGER_TYPE, OBEXManagerClass)) + +typedef struct _OBEXManager OBEXManager; +typedef struct _OBEXManagerClass OBEXManagerClass; +typedef struct _OBEXManagerPrivate OBEXManagerPrivate; + +struct _OBEXManager { + GObject parent_instance; + + /*< private >*/ + OBEXManagerPrivate *priv; +}; + +struct _OBEXManagerClass { + GObjectClass parent_class; +}; + +/* used by OBEXMANAGER_TYPE */ +GType obexmanager_get_type(void) G_GNUC_CONST; + +/* + * Method definitions + */ +gboolean obexmanager_cancel_session_connect(OBEXManager *self, const gchar *session_object, GError **error); +gchar *obexmanager_create_bluetooth_server(OBEXManager *self, const gchar *source_address, const gchar *pattern, const gboolean require_pairing, GError **error); +gchar *obexmanager_create_bluetooth_session(OBEXManager *self, const gchar *target_address, const gchar *source_address, const gchar *pattern, GError **error); +GHashTable *obexmanager_get_server_info(OBEXManager *self, const gchar *server_object, GError **error); +gchar **obexmanager_get_server_list(OBEXManager *self, GError **error); +GHashTable *obexmanager_get_session_info(OBEXManager *self, const gchar *session_object, GError **error); +gchar **obexmanager_get_session_list(OBEXManager *self, GError **error); +gchar *obexmanager_get_version(OBEXManager *self, GError **error); + +#endif /* __OBEXMANAGER_H */ + diff --git a/src/lib/obexserver.c b/src/lib/obexserver.c new file mode 100644 index 0000000..b067e74 --- /dev/null +++ b/src/lib/obexserver.c @@ -0,0 +1,372 @@ +/* + * + * bluez-tools - a set of tools to manage bluetooth devices for linux + * + * Copyright (C) 2010 Alexander Orlenko <zxteam@gmail.com> + * + * + * 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 + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <glib.h> +#include <string.h> + +#include "dbus-common.h" +#include "marshallers.h" +#include "obexserver.h" + +#define OBEXSERVER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), OBEXSERVER_TYPE, OBEXServerPrivate)) + +struct _OBEXServerPrivate { + DBusGProxy *dbus_g_proxy; + + /* Introspection data */ + DBusGProxy *introspection_g_proxy; + gchar *introspection_xml; +}; + +G_DEFINE_TYPE(OBEXServer, obexserver, G_TYPE_OBJECT); + +enum { + PROP_0, + + PROP_DBUS_OBJECT_PATH /* readwrite, construct only */ +}; + +static void _obexserver_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec); +static void _obexserver_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec); + +enum { + CLOSED, + ERROR_OCCURRED, + SESSION_CREATED, + SESSION_REMOVED, + STARTED, + STOPPED, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = {0}; + +static void closed_handler(DBusGProxy *dbus_g_proxy, gpointer data); +static void error_occurred_handler(DBusGProxy *dbus_g_proxy, const gchar *error_name, const gchar *error_message, gpointer data); +static void session_created_handler(DBusGProxy *dbus_g_proxy, const gchar *session_object, gpointer data); +static void session_removed_handler(DBusGProxy *dbus_g_proxy, const gchar *session_object, gpointer data); +static void started_handler(DBusGProxy *dbus_g_proxy, gpointer data); +static void stopped_handler(DBusGProxy *dbus_g_proxy, gpointer data); + +static void obexserver_dispose(GObject *gobject) +{ + OBEXServer *self = OBEXSERVER(gobject); + + /* DBus signals disconnection */ + dbus_g_proxy_disconnect_signal(self->priv->dbus_g_proxy, "Closed", G_CALLBACK(closed_handler), self); + dbus_g_proxy_disconnect_signal(self->priv->dbus_g_proxy, "ErrorOccurred", G_CALLBACK(error_occurred_handler), self); + dbus_g_proxy_disconnect_signal(self->priv->dbus_g_proxy, "SessionCreated", G_CALLBACK(session_created_handler), self); + dbus_g_proxy_disconnect_signal(self->priv->dbus_g_proxy, "SessionRemoved", G_CALLBACK(session_removed_handler), self); + dbus_g_proxy_disconnect_signal(self->priv->dbus_g_proxy, "Started", G_CALLBACK(started_handler), self); + dbus_g_proxy_disconnect_signal(self->priv->dbus_g_proxy, "Stopped", G_CALLBACK(stopped_handler), self); + + /* Proxy free */ + g_object_unref(self->priv->dbus_g_proxy); + + /* Introspection data free */ + g_free(self->priv->introspection_xml); + g_object_unref(self->priv->introspection_g_proxy); + + /* Chain up to the parent class */ + G_OBJECT_CLASS(obexserver_parent_class)->dispose(gobject); +} + +static void obexserver_class_init(OBEXServerClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS(klass); + + gobject_class->dispose = obexserver_dispose; + + g_type_class_add_private(klass, sizeof(OBEXServerPrivate)); + + /* Properties registration */ + GParamSpec *pspec; + + gobject_class->get_property = _obexserver_get_property; + gobject_class->set_property = _obexserver_set_property; + + /* object DBusObjectPath [readwrite, construct only] */ + pspec = g_param_spec_string("DBusObjectPath", "dbus_object_path", "Adapter D-Bus object path", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_property(gobject_class, PROP_DBUS_OBJECT_PATH, pspec); + + /* Signals registation */ + signals[CLOSED] = g_signal_new("Closed", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, + 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[ERROR_OCCURRED] = g_signal_new("ErrorOccurred", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, + 0, NULL, NULL, + g_cclosure_bluez_marshal_VOID__STRING_STRING, + G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING); + + signals[SESSION_CREATED] = g_signal_new("SessionCreated", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, + 0, NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, G_TYPE_STRING); + + signals[SESSION_REMOVED] = g_signal_new("SessionRemoved", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, + 0, NULL, NULL, + g_cclosure_marshal_VOID__STRING, + G_TYPE_NONE, 1, G_TYPE_STRING); + + signals[STARTED] = g_signal_new("Started", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, + 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[STOPPED] = g_signal_new("Stopped", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, + 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); +} + +static void obexserver_init(OBEXServer *self) +{ + self->priv = OBEXSERVER_GET_PRIVATE(self); + + g_assert(conn != NULL); +} + +static void obexserver_post_init(OBEXServer *self, const gchar *dbus_object_path) +{ + g_assert(dbus_object_path != NULL); + g_assert(strlen(dbus_object_path) > 0); + g_assert(self->priv->dbus_g_proxy == NULL); + + GError *error = NULL; + + /* Getting introspection XML */ + self->priv->introspection_g_proxy = dbus_g_proxy_new_for_name(conn, BLUEZ_DBUS_NAME, dbus_object_path, "org.freedesktop.DBus.Introspectable"); + self->priv->introspection_xml = NULL; + if (!dbus_g_proxy_call(self->priv->introspection_g_proxy, "Introspect", &error, G_TYPE_INVALID, G_TYPE_STRING, &self->priv->introspection_xml, G_TYPE_INVALID)) { + g_critical("%s", error->message); + } + g_assert(error == NULL); + + gchar *check_intf_regex_str = g_strconcat("<interface name=\"", BLUEZ_DBUS_OBEXSERVER_INTERFACE, "\">", NULL); + if (!g_regex_match_simple(check_intf_regex_str, self->priv->introspection_xml, 0, 0)) { + g_critical("Interface \"%s\" does not exist in \"%s\"", BLUEZ_DBUS_OBEXSERVER_INTERFACE, dbus_object_path); + g_assert(FALSE); + } + g_free(check_intf_regex_str); + self->priv->dbus_g_proxy = dbus_g_proxy_new_for_name(conn, BLUEZ_DBUS_NAME, dbus_object_path, BLUEZ_DBUS_OBEXSERVER_INTERFACE); + + /* DBus signals connection */ + + /* Closed() */ + dbus_g_proxy_add_signal(self->priv->dbus_g_proxy, "Closed", G_TYPE_INVALID); + dbus_g_proxy_connect_signal(self->priv->dbus_g_proxy, "Closed", G_CALLBACK(closed_handler), self, NULL); + + /* ErrorOccurred(string error_name, string error_message) */ + dbus_g_proxy_add_signal(self->priv->dbus_g_proxy, "ErrorOccurred", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID); + dbus_g_proxy_connect_signal(self->priv->dbus_g_proxy, "ErrorOccurred", G_CALLBACK(error_occurred_handler), self, NULL); + + /* SessionCreated(object session_object) */ + dbus_g_proxy_add_signal(self->priv->dbus_g_proxy, "SessionCreated", DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); + dbus_g_proxy_connect_signal(self->priv->dbus_g_proxy, "SessionCreated", G_CALLBACK(session_created_handler), self, NULL); + + /* SessionRemoved(object session_object) */ + dbus_g_proxy_add_signal(self->priv->dbus_g_proxy, "SessionRemoved", DBUS_TYPE_G_OBJECT_PATH, G_TYPE_INVALID); + dbus_g_proxy_connect_signal(self->priv->dbus_g_proxy, "SessionRemoved", G_CALLBACK(session_removed_handler), self, NULL); + + /* Started() */ + dbus_g_proxy_add_signal(self->priv->dbus_g_proxy, "Started", G_TYPE_INVALID); + dbus_g_proxy_connect_signal(self->priv->dbus_g_proxy, "Started", G_CALLBACK(started_handler), self, NULL); + + /* Stopped() */ + dbus_g_proxy_add_signal(self->priv->dbus_g_proxy, "Stopped", G_TYPE_INVALID); + dbus_g_proxy_connect_signal(self->priv->dbus_g_proxy, "Stopped", G_CALLBACK(stopped_handler), self, NULL); +} + +static void _obexserver_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec) +{ + OBEXServer *self = OBEXSERVER(object); + + switch (property_id) { + case PROP_DBUS_OBJECT_PATH: + g_value_set_string(value, obexserver_get_dbus_object_path(self)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + break; + } +} + +static void _obexserver_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) +{ + OBEXServer *self = OBEXSERVER(object); + GError *error = NULL; + + switch (property_id) { + case PROP_DBUS_OBJECT_PATH: + obexserver_post_init(self, g_value_get_string(value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + break; + } + + if (error != NULL) { + g_critical("%s", error->message); + } + g_assert(error == NULL); +} + +/* Methods */ + +/* void Close() */ +void obexserver_close(OBEXServer *self, GError **error) +{ + g_assert(OBEXSERVER_IS(self)); + + dbus_g_proxy_call(self->priv->dbus_g_proxy, "Close", error, G_TYPE_INVALID, G_TYPE_INVALID); +} + +/* dict GetServerSessionInfo(object session_object) */ +GHashTable *obexserver_get_server_session_info(OBEXServer *self, const gchar *session_object, GError **error) +{ + g_assert(OBEXSERVER_IS(self)); + + GHashTable *ret = NULL; + dbus_g_proxy_call(self->priv->dbus_g_proxy, "GetServerSessionInfo", error, DBUS_TYPE_G_OBJECT_PATH, session_object, G_TYPE_INVALID, DBUS_TYPE_G_STRING_VARIANT_HASHTABLE, &ret, G_TYPE_INVALID); + + return ret; +} + +/* array{string} GetServerSessionList() */ +gchar **obexserver_get_server_session_list(OBEXServer *self, GError **error) +{ + g_assert(OBEXSERVER_IS(self)); + + gchar **ret = NULL; + dbus_g_proxy_call(self->priv->dbus_g_proxy, "GetServerSessionList", error, G_TYPE_INVALID, G_TYPE_STRV, &ret, G_TYPE_INVALID); + + return ret; +} + +/* boolean IsStarted() */ +gboolean obexserver_is_started(OBEXServer *self, GError **error) +{ + g_assert(OBEXSERVER_IS(self)); + + gboolean ret = FALSE; + dbus_g_proxy_call(self->priv->dbus_g_proxy, "IsStarted", error, G_TYPE_INVALID, G_TYPE_BOOLEAN, &ret, G_TYPE_INVALID); + + return ret; +} + +/* void SetOption(string name, variant value) */ +void obexserver_set_option(OBEXServer *self, const gchar *name, const GValue *value, GError **error) +{ + g_assert(OBEXSERVER_IS(self)); + + dbus_g_proxy_call(self->priv->dbus_g_proxy, "SetOption", error, G_TYPE_STRING, name, G_TYPE_VALUE, value, G_TYPE_INVALID, G_TYPE_INVALID); +} + +/* void Start(string path, boolean allow_write, boolean auto_accept) */ +void obexserver_start(OBEXServer *self, const gchar *path, const gboolean allow_write, const gboolean auto_accept, GError **error) +{ + g_assert(OBEXSERVER_IS(self)); + + dbus_g_proxy_call(self->priv->dbus_g_proxy, "Start", error, G_TYPE_STRING, path, G_TYPE_BOOLEAN, allow_write, G_TYPE_BOOLEAN, auto_accept, G_TYPE_INVALID, G_TYPE_INVALID); +} + +/* void Stop() */ +void obexserver_stop(OBEXServer *self, GError **error) +{ + g_assert(OBEXSERVER_IS(self)); + + dbus_g_proxy_call(self->priv->dbus_g_proxy, "Stop", error, G_TYPE_INVALID, G_TYPE_INVALID); +} + +/* Properties access methods */ +const gchar *obexserver_get_dbus_object_path(OBEXServer *self) +{ + g_assert(OBEXSERVER_IS(self)); + + return dbus_g_proxy_get_path(self->priv->dbus_g_proxy); +} + +/* Signals handlers */ +static void closed_handler(DBusGProxy *dbus_g_proxy, gpointer data) +{ + OBEXServer *self = OBEXSERVER(data); + + g_signal_emit(self, signals[CLOSED], 0); +} + +static void error_occurred_handler(DBusGProxy *dbus_g_proxy, const gchar *error_name, const gchar *error_message, gpointer data) +{ + OBEXServer *self = OBEXSERVER(data); + + g_signal_emit(self, signals[ERROR_OCCURRED], 0, error_name, error_message); +} + +static void session_created_handler(DBusGProxy *dbus_g_proxy, const gchar *session_object, gpointer data) +{ + OBEXServer *self = OBEXSERVER(data); + + g_signal_emit(self, signals[SESSION_CREATED], 0, session_object); +} + +static void session_removed_handler(DBusGProxy *dbus_g_proxy, const gchar *session_object, gpointer data) +{ + OBEXServer *self = OBEXSERVER(data); + + g_signal_emit(self, signals[SESSION_REMOVED], 0, session_object); +} + +static void started_handler(DBusGProxy *dbus_g_proxy, gpointer data) +{ + OBEXServer *self = OBEXSERVER(data); + + g_signal_emit(self, signals[STARTED], 0); +} + +static void stopped_handler(DBusGProxy *dbus_g_proxy, gpointer data) +{ + OBEXServer *self = OBEXSERVER(data); + + g_signal_emit(self, signals[STOPPED], 0); +} + diff --git a/src/lib/obexserver.h b/src/lib/obexserver.h new file mode 100644 index 0000000..dfea764 --- /dev/null +++ b/src/lib/obexserver.h @@ -0,0 +1,73 @@ +/* + * + * bluez-tools - a set of tools to manage bluetooth devices for linux + * + * Copyright (C) 2010 Alexander Orlenko <zxteam@gmail.com> + * + * + * 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 + * + */ + +#ifndef __OBEXSERVER_H +#define __OBEXSERVER_H + +#include <glib-object.h> + +#define BLUEZ_DBUS_OBEXSERVER_INTERFACE "org.openobex.Server" + +/* + * Type macros + */ +#define OBEXSERVER_TYPE (obexserver_get_type()) +#define OBEXSERVER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), OBEXSERVER_TYPE, OBEXServer)) +#define OBEXSERVER_IS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), OBEXSERVER_TYPE)) +#define OBEXSERVER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), OBEXSERVER_TYPE, OBEXServerClass)) +#define OBEXSERVER_IS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), OBEXSERVER_TYPE)) +#define OBEXSERVER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), OBEXSERVER_TYPE, OBEXServerClass)) + +typedef struct _OBEXServer OBEXServer; +typedef struct _OBEXServerClass OBEXServerClass; +typedef struct _OBEXServerPrivate OBEXServerPrivate; + +struct _OBEXServer { + GObject parent_instance; + + /*< private >*/ + OBEXServerPrivate *priv; +}; + +struct _OBEXServerClass { + GObjectClass parent_class; +}; + +/* used by OBEXSERVER_TYPE */ +GType obexserver_get_type(void) G_GNUC_CONST; + +/* + * Method definitions + */ +void obexserver_close(OBEXServer *self, GError **error); +GHashTable *obexserver_get_server_session_info(OBEXServer *self, const gchar *session_object, GError **error); +gchar **obexserver_get_server_session_list(OBEXServer *self, GError **error); +gboolean obexserver_is_started(OBEXServer *self, GError **error); +void obexserver_set_option(OBEXServer *self, const gchar *name, const GValue *value, GError **error); +void obexserver_start(OBEXServer *self, const gchar *path, const gboolean allow_write, const gboolean auto_accept, GError **error); +void obexserver_stop(OBEXServer *self, GError **error); + +const gchar *obexserver_get_dbus_object_path(OBEXServer *self); + +#endif /* __OBEXSERVER_H */ + diff --git a/src/lib/obexserver_session.c b/src/lib/obexserver_session.c new file mode 100644 index 0000000..bac86aa --- /dev/null +++ b/src/lib/obexserver_session.c @@ -0,0 +1,350 @@ +/* + * + * bluez-tools - a set of tools to manage bluetooth devices for linux + * + * Copyright (C) 2010 Alexander Orlenko <zxteam@gmail.com> + * + * + * 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 + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <glib.h> +#include <string.h> + +#include "dbus-common.h" +#include "marshallers.h" +#include "obexserver_session.h" + +#define OBEXSERVER_SESSION_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), OBEXSERVER_SESSION_TYPE, OBEXServerSessionPrivate)) + +struct _OBEXServerSessionPrivate { + DBusGProxy *dbus_g_proxy; + + /* Introspection data */ + DBusGProxy *introspection_g_proxy; + gchar *introspection_xml; +}; + +G_DEFINE_TYPE(OBEXServerSession, obexserver_session, G_TYPE_OBJECT); + +enum { + PROP_0, + + PROP_DBUS_OBJECT_PATH /* readwrite, construct only */ +}; + +static void _obexserver_session_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec); +static void _obexserver_session_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec); + +enum { + CANCELLED, + DISCONNECTED, + ERROR_OCCURRED, + TRANSFER_COMPLETED, + TRANSFER_PROGRESS, + TRANSFER_STARTED, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = {0}; + +static void cancelled_handler(DBusGProxy *dbus_g_proxy, gpointer data); +static void disconnected_handler(DBusGProxy *dbus_g_proxy, gpointer data); +static void error_occurred_handler(DBusGProxy *dbus_g_proxy, const gchar *error_name, const gchar *error_message, gpointer data); +static void transfer_completed_handler(DBusGProxy *dbus_g_proxy, gpointer data); +static void transfer_progress_handler(DBusGProxy *dbus_g_proxy, const guint64 bytes_transferred, gpointer data); +static void transfer_started_handler(DBusGProxy *dbus_g_proxy, const gchar *filename, const gchar *local_path, const guint64 total_bytes, gpointer data); + +static void obexserver_session_dispose(GObject *gobject) +{ + OBEXServerSession *self = OBEXSERVER_SESSION(gobject); + + /* DBus signals disconnection */ + dbus_g_proxy_disconnect_signal(self->priv->dbus_g_proxy, "Cancelled", G_CALLBACK(cancelled_handler), self); + dbus_g_proxy_disconnect_signal(self->priv->dbus_g_proxy, "Disconnected", G_CALLBACK(disconnected_handler), self); + dbus_g_proxy_disconnect_signal(self->priv->dbus_g_proxy, "ErrorOccurred", G_CALLBACK(error_occurred_handler), self); + dbus_g_proxy_disconnect_signal(self->priv->dbus_g_proxy, "TransferCompleted", G_CALLBACK(transfer_completed_handler), self); + dbus_g_proxy_disconnect_signal(self->priv->dbus_g_proxy, "TransferProgress", G_CALLBACK(transfer_progress_handler), self); + dbus_g_proxy_disconnect_signal(self->priv->dbus_g_proxy, "TransferStarted", G_CALLBACK(transfer_started_handler), self); + + /* Proxy free */ + g_object_unref(self->priv->dbus_g_proxy); + + /* Introspection data free */ + g_free(self->priv->introspection_xml); + g_object_unref(self->priv->introspection_g_proxy); + + /* Chain up to the parent class */ + G_OBJECT_CLASS(obexserver_session_parent_class)->dispose(gobject); +} + +static void obexserver_session_class_init(OBEXServerSessionClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS(klass); + + gobject_class->dispose = obexserver_session_dispose; + + g_type_class_add_private(klass, sizeof(OBEXServerSessionPrivate)); + + /* Properties registration */ + GParamSpec *pspec; + + gobject_class->get_property = _obexserver_session_get_property; + gobject_class->set_property = _obexserver_session_set_property; + + /* object DBusObjectPath [readwrite, construct only] */ + pspec = g_param_spec_string("DBusObjectPath", "dbus_object_path", "Adapter D-Bus object path", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_property(gobject_class, PROP_DBUS_OBJECT_PATH, pspec); + + /* Signals registation */ + signals[CANCELLED] = g_signal_new("Cancelled", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, + 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[DISCONNECTED] = g_signal_new("Disconnected", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, + 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[ERROR_OCCURRED] = g_signal_new("ErrorOccurred", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, + 0, NULL, NULL, + g_cclosure_bluez_marshal_VOID__STRING_STRING, + G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING); + + signals[TRANSFER_COMPLETED] = g_signal_new("TransferCompleted", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, + 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[TRANSFER_PROGRESS] = g_signal_new("TransferProgress", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, + 0, NULL, NULL, + g_cclosure_bluez_marshal_VOID__UINT64, + G_TYPE_NONE, 1, G_TYPE_UINT64); + + signals[TRANSFER_STARTED] = g_signal_new("TransferStarted", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, + 0, NULL, NULL, + g_cclosure_bluez_marshal_VOID__STRING_STRING_UINT64, + G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT64); +} + +static void obexserver_session_init(OBEXServerSession *self) +{ + self->priv = OBEXSERVER_SESSION_GET_PRIVATE(self); + + g_assert(conn != NULL); +} + +static void obexserver_session_post_init(OBEXServerSession *self, const gchar *dbus_object_path) +{ + g_assert(dbus_object_path != NULL); + g_assert(strlen(dbus_object_path) > 0); + g_assert(self->priv->dbus_g_proxy == NULL); + + GError *error = NULL; + + /* Getting introspection XML */ + self->priv->introspection_g_proxy = dbus_g_proxy_new_for_name(conn, BLUEZ_DBUS_NAME, dbus_object_path, "org.freedesktop.DBus.Introspectable"); + self->priv->introspection_xml = NULL; + if (!dbus_g_proxy_call(self->priv->introspection_g_proxy, "Introspect", &error, G_TYPE_INVALID, G_TYPE_STRING, &self->priv->introspection_xml, G_TYPE_INVALID)) { + g_critical("%s", error->message); + } + g_assert(error == NULL); + + gchar *check_intf_regex_str = g_strconcat("<interface name=\"", BLUEZ_DBUS_OBEXSERVER_SESSION_INTERFACE, "\">", NULL); + if (!g_regex_match_simple(check_intf_regex_str, self->priv->introspection_xml, 0, 0)) { + g_critical("Interface \"%s\" does not exist in \"%s\"", BLUEZ_DBUS_OBEXSERVER_SESSION_INTERFACE, dbus_object_path); + g_assert(FALSE); + } + g_free(check_intf_regex_str); + self->priv->dbus_g_proxy = dbus_g_proxy_new_for_name(conn, BLUEZ_DBUS_NAME, dbus_object_path, BLUEZ_DBUS_OBEXSERVER_SESSION_INTERFACE); + + /* DBus signals connection */ + + /* Cancelled() */ + dbus_g_proxy_add_signal(self->priv->dbus_g_proxy, "Cancelled", G_TYPE_INVALID); + dbus_g_proxy_connect_signal(self->priv->dbus_g_proxy, "Cancelled", G_CALLBACK(cancelled_handler), self, NULL); + + /* Disconnected() */ + dbus_g_proxy_add_signal(self->priv->dbus_g_proxy, "Disconnected", G_TYPE_INVALID); + dbus_g_proxy_connect_signal(self->priv->dbus_g_proxy, "Disconnected", G_CALLBACK(disconnected_handler), self, NULL); + + /* ErrorOccurred(string error_name, string error_message) */ + dbus_g_proxy_add_signal(self->priv->dbus_g_proxy, "ErrorOccurred", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID); + dbus_g_proxy_connect_signal(self->priv->dbus_g_proxy, "ErrorOccurred", G_CALLBACK(error_occurred_handler), self, NULL); + + /* TransferCompleted() */ + dbus_g_proxy_add_signal(self->priv->dbus_g_proxy, "TransferCompleted", G_TYPE_INVALID); + dbus_g_proxy_connect_signal(self->priv->dbus_g_proxy, "TransferCompleted", G_CALLBACK(transfer_completed_handler), self, NULL); + + /* TransferProgress(uint64 bytes_transferred) */ + dbus_g_proxy_add_signal(self->priv->dbus_g_proxy, "TransferProgress", G_TYPE_UINT64, G_TYPE_INVALID); + dbus_g_proxy_connect_signal(self->priv->dbus_g_proxy, "TransferProgress", G_CALLBACK(transfer_progress_handler), self, NULL); + + /* TransferStarted(string filename, string local_path, uint64 total_bytes) */ + dbus_g_proxy_add_signal(self->priv->dbus_g_proxy, "TransferStarted", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT64, G_TYPE_INVALID); + dbus_g_proxy_connect_signal(self->priv->dbus_g_proxy, "TransferStarted", G_CALLBACK(transfer_started_handler), self, NULL); +} + +static void _obexserver_session_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec) +{ + OBEXServerSession *self = OBEXSERVER_SESSION(object); + + switch (property_id) { + case PROP_DBUS_OBJECT_PATH: + g_value_set_string(value, obexserver_session_get_dbus_object_path(self)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + break; + } +} + +static void _obexserver_session_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) +{ + OBEXServerSession *self = OBEXSERVER_SESSION(object); + GError *error = NULL; + + switch (property_id) { + case PROP_DBUS_OBJECT_PATH: + obexserver_session_post_init(self, g_value_get_string(value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + break; + } + + if (error != NULL) { + g_critical("%s", error->message); + } + g_assert(error == NULL); +} + +/* Methods */ + +/* void Accept() */ +void obexserver_session_accept(OBEXServerSession *self, GError **error) +{ + g_assert(OBEXSERVER_SESSION_IS(self)); + + dbus_g_proxy_call(self->priv->dbus_g_proxy, "Accept", error, G_TYPE_INVALID, G_TYPE_INVALID); +} + +/* void Cancel() */ +void obexserver_session_cancel(OBEXServerSession *self, GError **error) +{ + g_assert(OBEXSERVER_SESSION_IS(self)); + + dbus_g_proxy_call(self->priv->dbus_g_proxy, "Cancel", error, G_TYPE_INVALID, G_TYPE_INVALID); +} + +/* void Disconnect() */ +void obexserver_session_disconnect(OBEXServerSession *self, GError **error) +{ + g_assert(OBEXSERVER_SESSION_IS(self)); + + dbus_g_proxy_call(self->priv->dbus_g_proxy, "Disconnect", error, G_TYPE_INVALID, G_TYPE_INVALID); +} + +/* dict GetTransferInfo() */ +GHashTable *obexserver_session_get_transfer_info(OBEXServerSession *self, GError **error) +{ + g_assert(OBEXSERVER_SESSION_IS(self)); + + GHashTable *ret = NULL; + dbus_g_proxy_call(self->priv->dbus_g_proxy, "GetTransferInfo", error, G_TYPE_INVALID, DBUS_TYPE_G_STRING_VARIANT_HASHTABLE, &ret, G_TYPE_INVALID); + + return ret; +} + +/* void Reject() */ +void obexserver_session_reject(OBEXServerSession *self, GError **error) +{ + g_assert(OBEXSERVER_SESSION_IS(self)); + + dbus_g_proxy_call(self->priv->dbus_g_proxy, "Reject", error, G_TYPE_INVALID, G_TYPE_INVALID); +} + +/* Properties access methods */ +const gchar *obexserver_session_get_dbus_object_path(OBEXServerSession *self) +{ + g_assert(OBEXSERVER_SESSION_IS(self)); + + return dbus_g_proxy_get_path(self->priv->dbus_g_proxy); +} + +/* Signals handlers */ +static void cancelled_handler(DBusGProxy *dbus_g_proxy, gpointer data) +{ + OBEXServerSession *self = OBEXSERVER_SESSION(data); + + g_signal_emit(self, signals[CANCELLED], 0); +} + +static void disconnected_handler(DBusGProxy *dbus_g_proxy, gpointer data) +{ + OBEXServerSession *self = OBEXSERVER_SESSION(data); + + g_signal_emit(self, signals[DISCONNECTED], 0); +} + +static void error_occurred_handler(DBusGProxy *dbus_g_proxy, const gchar *error_name, const gchar *error_message, gpointer data) +{ + OBEXServerSession *self = OBEXSERVER_SESSION(data); + + g_signal_emit(self, signals[ERROR_OCCURRED], 0, error_name, error_message); +} + +static void transfer_completed_handler(DBusGProxy *dbus_g_proxy, gpointer data) +{ + OBEXServerSession *self = OBEXSERVER_SESSION(data); + + g_signal_emit(self, signals[TRANSFER_COMPLETED], 0); +} + +static void transfer_progress_handler(DBusGProxy *dbus_g_proxy, const guint64 bytes_transferred, gpointer data) +{ + OBEXServerSession *self = OBEXSERVER_SESSION(data); + + g_signal_emit(self, signals[TRANSFER_PROGRESS], 0, bytes_transferred); +} + +static void transfer_started_handler(DBusGProxy *dbus_g_proxy, const gchar *filename, const gchar *local_path, const guint64 total_bytes, gpointer data) +{ + OBEXServerSession *self = OBEXSERVER_SESSION(data); + + g_signal_emit(self, signals[TRANSFER_STARTED], 0, filename, local_path, total_bytes); +} + diff --git a/src/lib/obexserver_session.h b/src/lib/obexserver_session.h new file mode 100644 index 0000000..53072cd --- /dev/null +++ b/src/lib/obexserver_session.h @@ -0,0 +1,71 @@ +/* + * + * bluez-tools - a set of tools to manage bluetooth devices for linux + * + * Copyright (C) 2010 Alexander Orlenko <zxteam@gmail.com> + * + * + * 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 + * + */ + +#ifndef __OBEXSERVER_SESSION_H +#define __OBEXSERVER_SESSION_H + +#include <glib-object.h> + +#define BLUEZ_DBUS_OBEXSERVER_SESSION_INTERFACE "org.openobex.ServerSession" + +/* + * Type macros + */ +#define OBEXSERVER_SESSION_TYPE (obexserver_session_get_type()) +#define OBEXSERVER_SESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), OBEXSERVER_SESSION_TYPE, OBEXServerSession)) +#define OBEXSERVER_SESSION_IS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), OBEXSERVER_SESSION_TYPE)) +#define OBEXSERVER_SESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), OBEXSERVER_SESSION_TYPE, OBEXServerSessionClass)) +#define OBEXSERVER_SESSION_IS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), OBEXSERVER_SESSION_TYPE)) +#define OBEXSERVER_SESSION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), OBEXSERVER_SESSION_TYPE, OBEXServerSessionClass)) + +typedef struct _OBEXServerSession OBEXServerSession; +typedef struct _OBEXServerSessionClass OBEXServerSessionClass; +typedef struct _OBEXServerSessionPrivate OBEXServerSessionPrivate; + +struct _OBEXServerSession { + GObject parent_instance; + + /*< private >*/ + OBEXServerSessionPrivate *priv; +}; + +struct _OBEXServerSessionClass { + GObjectClass parent_class; +}; + +/* used by OBEXSERVER_SESSION_TYPE */ +GType obexserver_session_get_type(void) G_GNUC_CONST; + +/* + * Method definitions + */ +void obexserver_session_accept(OBEXServerSession *self, GError **error); +void obexserver_session_cancel(OBEXServerSession *self, GError **error); +void obexserver_session_disconnect(OBEXServerSession *self, GError **error); +GHashTable *obexserver_session_get_transfer_info(OBEXServerSession *self, GError **error); +void obexserver_session_reject(OBEXServerSession *self, GError **error); + +const gchar *obexserver_session_get_dbus_object_path(OBEXServerSession *self); + +#endif /* __OBEXSERVER_SESSION_H */ + diff --git a/src/lib/obexsession.c b/src/lib/obexsession.c new file mode 100644 index 0000000..b8836a7 --- /dev/null +++ b/src/lib/obexsession.c @@ -0,0 +1,495 @@ +/* + * + * bluez-tools - a set of tools to manage bluetooth devices for linux + * + * Copyright (C) 2010 Alexander Orlenko <zxteam@gmail.com> + * + * + * 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 + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <glib.h> +#include <string.h> + +#include "dbus-common.h" +#include "marshallers.h" +#include "obexsession.h" + +#define OBEXSESSION_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), OBEXSESSION_TYPE, OBEXSessionPrivate)) + +struct _OBEXSessionPrivate { + DBusGProxy *dbus_g_proxy; + + /* Introspection data */ + DBusGProxy *introspection_g_proxy; + gchar *introspection_xml; +}; + +G_DEFINE_TYPE(OBEXSession, obexsession, G_TYPE_OBJECT); + +enum { + PROP_0, + + PROP_DBUS_OBJECT_PATH /* readwrite, construct only */ +}; + +static void _obexsession_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec); +static void _obexsession_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec); + +enum { + CANCELLED, + CLOSED, + DISCONNECTED, + ERROR_OCCURRED, + TRANSFER_COMPLETED, + TRANSFER_PROGRESS, + TRANSFER_STARTED, + + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL] = {0}; + +static void cancelled_handler(DBusGProxy *dbus_g_proxy, gpointer data); +static void closed_handler(DBusGProxy *dbus_g_proxy, gpointer data); +static void disconnected_handler(DBusGProxy *dbus_g_proxy, gpointer data); +static void error_occurred_handler(DBusGProxy *dbus_g_proxy, const gchar *error_name, const gchar *error_message, gpointer data); +static void transfer_completed_handler(DBusGProxy *dbus_g_proxy, gpointer data); +static void transfer_progress_handler(DBusGProxy *dbus_g_proxy, const guint64 bytes_transferred, gpointer data); +static void transfer_started_handler(DBusGProxy *dbus_g_proxy, const gchar *filename, const gchar *local_path, const guint64 total_bytes, gpointer data); + +static void obexsession_dispose(GObject *gobject) +{ + OBEXSession *self = OBEXSESSION(gobject); + + /* DBus signals disconnection */ + dbus_g_proxy_disconnect_signal(self->priv->dbus_g_proxy, "Cancelled", G_CALLBACK(cancelled_handler), self); + dbus_g_proxy_disconnect_signal(self->priv->dbus_g_proxy, "Closed", G_CALLBACK(closed_handler), self); + dbus_g_proxy_disconnect_signal(self->priv->dbus_g_proxy, "Disconnected", G_CALLBACK(disconnected_handler), self); + dbus_g_proxy_disconnect_signal(self->priv->dbus_g_proxy, "ErrorOccurred", G_CALLBACK(error_occurred_handler), self); + dbus_g_proxy_disconnect_signal(self->priv->dbus_g_proxy, "TransferCompleted", G_CALLBACK(transfer_completed_handler), self); + dbus_g_proxy_disconnect_signal(self->priv->dbus_g_proxy, "TransferProgress", G_CALLBACK(transfer_progress_handler), self); + dbus_g_proxy_disconnect_signal(self->priv->dbus_g_proxy, "TransferStarted", G_CALLBACK(transfer_started_handler), self); + + /* Proxy free */ + g_object_unref(self->priv->dbus_g_proxy); + + /* Introspection data free */ + g_free(self->priv->introspection_xml); + g_object_unref(self->priv->introspection_g_proxy); + + /* Chain up to the parent class */ + G_OBJECT_CLASS(obexsession_parent_class)->dispose(gobject); +} + +static void obexsession_class_init(OBEXSessionClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS(klass); + + gobject_class->dispose = obexsession_dispose; + + g_type_class_add_private(klass, sizeof(OBEXSessionPrivate)); + + /* Properties registration */ + GParamSpec *pspec; + + gobject_class->get_property = _obexsession_get_property; + gobject_class->set_property = _obexsession_set_property; + + /* object DBusObjectPath [readwrite, construct only] */ + pspec = g_param_spec_string("DBusObjectPath", "dbus_object_path", "Adapter D-Bus object path", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY); + g_object_class_install_property(gobject_class, PROP_DBUS_OBJECT_PATH, pspec); + + /* Signals registation */ + signals[CANCELLED] = g_signal_new("Cancelled", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, + 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[CLOSED] = g_signal_new("Closed", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, + 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[DISCONNECTED] = g_signal_new("Disconnected", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, + 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[ERROR_OCCURRED] = g_signal_new("ErrorOccurred", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, + 0, NULL, NULL, + g_cclosure_bluez_marshal_VOID__STRING_STRING, + G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_STRING); + + signals[TRANSFER_COMPLETED] = g_signal_new("TransferCompleted", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, + 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[TRANSFER_PROGRESS] = g_signal_new("TransferProgress", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, + 0, NULL, NULL, + g_cclosure_bluez_marshal_VOID__UINT64, + G_TYPE_NONE, 1, G_TYPE_UINT64); + + signals[TRANSFER_STARTED] = g_signal_new("TransferStarted", + G_TYPE_FROM_CLASS(gobject_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, + 0, NULL, NULL, + g_cclosure_bluez_marshal_VOID__STRING_STRING_UINT64, + G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT64); +} + +static void obexsession_init(OBEXSession *self) +{ + self->priv = OBEXSESSION_GET_PRIVATE(self); + + g_assert(conn != NULL); +} + +static void obexsession_post_init(OBEXSession *self, const gchar *dbus_object_path) +{ + g_assert(dbus_object_path != NULL); + g_assert(strlen(dbus_object_path) > 0); + g_assert(self->priv->dbus_g_proxy == NULL); + + GError *error = NULL; + + /* Getting introspection XML */ + self->priv->introspection_g_proxy = dbus_g_proxy_new_for_name(conn, BLUEZ_DBUS_NAME, dbus_object_path, "org.freedesktop.DBus.Introspectable"); + self->priv->introspection_xml = NULL; + if (!dbus_g_proxy_call(self->priv->introspection_g_proxy, "Introspect", &error, G_TYPE_INVALID, G_TYPE_STRING, &self->priv->introspection_xml, G_TYPE_INVALID)) { + g_critical("%s", error->message); + } + g_assert(error == NULL); + + gchar *check_intf_regex_str = g_strconcat("<interface name=\"", BLUEZ_DBUS_OBEXSESSION_INTERFACE, "\">", NULL); + if (!g_regex_match_simple(check_intf_regex_str, self->priv->introspection_xml, 0, 0)) { + g_critical("Interface \"%s\" does not exist in \"%s\"", BLUEZ_DBUS_OBEXSESSION_INTERFACE, dbus_object_path); + g_assert(FALSE); + } + g_free(check_intf_regex_str); + self->priv->dbus_g_proxy = dbus_g_proxy_new_for_name(conn, BLUEZ_DBUS_NAME, dbus_object_path, BLUEZ_DBUS_OBEXSESSION_INTERFACE); + + /* DBus signals connection */ + + /* Cancelled() */ + dbus_g_proxy_add_signal(self->priv->dbus_g_proxy, "Cancelled", G_TYPE_INVALID); + dbus_g_proxy_connect_signal(self->priv->dbus_g_proxy, "Cancelled", G_CALLBACK(cancelled_handler), self, NULL); + + /* Closed() */ + dbus_g_proxy_add_signal(self->priv->dbus_g_proxy, "Closed", G_TYPE_INVALID); + dbus_g_proxy_connect_signal(self->priv->dbus_g_proxy, "Closed", G_CALLBACK(closed_handler), self, NULL); + + /* Disconnected() */ + dbus_g_proxy_add_signal(self->priv->dbus_g_proxy, "Disconnected", G_TYPE_INVALID); + dbus_g_proxy_connect_signal(self->priv->dbus_g_proxy, "Disconnected", G_CALLBACK(disconnected_handler), self, NULL); + + /* ErrorOccurred(string error_name, string error_message) */ + dbus_g_proxy_add_signal(self->priv->dbus_g_proxy, "ErrorOccurred", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_INVALID); + dbus_g_proxy_connect_signal(self->priv->dbus_g_proxy, "ErrorOccurred", G_CALLBACK(error_occurred_handler), self, NULL); + + /* TransferCompleted() */ + dbus_g_proxy_add_signal(self->priv->dbus_g_proxy, "TransferCompleted", G_TYPE_INVALID); + dbus_g_proxy_connect_signal(self->priv->dbus_g_proxy, "TransferCompleted", G_CALLBACK(transfer_completed_handler), self, NULL); + + /* TransferProgress(uint64 bytes_transferred) */ + dbus_g_proxy_add_signal(self->priv->dbus_g_proxy, "TransferProgress", G_TYPE_UINT64, G_TYPE_INVALID); + dbus_g_proxy_connect_signal(self->priv->dbus_g_proxy, "TransferProgress", G_CALLBACK(transfer_progress_handler), self, NULL); + + /* TransferStarted(string filename, string local_path, uint64 total_bytes) */ + dbus_g_proxy_add_signal(self->priv->dbus_g_proxy, "TransferStarted", G_TYPE_STRING, G_TYPE_STRING, G_TYPE_UINT64, G_TYPE_INVALID); + dbus_g_proxy_connect_signal(self->priv->dbus_g_proxy, "TransferStarted", G_CALLBACK(transfer_started_handler), self, NULL); +} + +static void _obexsession_get_property(GObject *object, guint property_id, GValue *value, GParamSpec *pspec) +{ + OBEXSession *self = OBEXSESSION(object); + + switch (property_id) { + case PROP_DBUS_OBJECT_PATH: + g_value_set_string(value, obexsession_get_dbus_object_path(self)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + break; + } +} + +static void _obexsession_set_property(GObject *object, guint property_id, const GValue *value, GParamSpec *pspec) +{ + OBEXSession *self = OBEXSESSION(object); + GError *error = NULL; + + switch (property_id) { + case PROP_DBUS_OBJECT_PATH: + obexsession_post_init(self, g_value_get_string(value)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec); + break; + } + + if (error != NULL) { + g_critical("%s", error->message); + } + g_assert(error == NULL); +} + +/* Methods */ + +/* void Cancel() */ +void obexsession_cancel(OBEXSession *self, GError **error) +{ + g_assert(OBEXSESSION_IS(self)); + + dbus_g_proxy_call(self->priv->dbus_g_proxy, "Cancel", error, G_TYPE_INVALID, G_TYPE_INVALID); +} + +/* void ChangeCurrentFolder(string path) */ +void obexsession_change_current_folder(OBEXSession *self, const gchar *path, GError **error) +{ + g_assert(OBEXSESSION_IS(self)); + + dbus_g_proxy_call(self->priv->dbus_g_proxy, "ChangeCurrentFolder", error, G_TYPE_STRING, path, G_TYPE_INVALID, G_TYPE_INVALID); +} + +/* void ChangeCurrentFolderBackward() */ +void obexsession_change_current_folder_backward(OBEXSession *self, GError **error) +{ + g_assert(OBEXSESSION_IS(self)); + + dbus_g_proxy_call(self->priv->dbus_g_proxy, "ChangeCurrentFolderBackward", error, G_TYPE_INVALID, G_TYPE_INVALID); +} + +/* void ChangeCurrentFolderToRoot() */ +void obexsession_change_current_folder_to_root(OBEXSession *self, GError **error) +{ + g_assert(OBEXSESSION_IS(self)); + + dbus_g_proxy_call(self->priv->dbus_g_proxy, "ChangeCurrentFolderToRoot", error, G_TYPE_INVALID, G_TYPE_INVALID); +} + +/* void Close() */ +void obexsession_close(OBEXSession *self, GError **error) +{ + g_assert(OBEXSESSION_IS(self)); + + dbus_g_proxy_call(self->priv->dbus_g_proxy, "Close", error, G_TYPE_INVALID, G_TYPE_INVALID); +} + +/* void CopyRemoteFile(string remote_filename, string local_path) */ +void obexsession_copy_remote_file(OBEXSession *self, const gchar *remote_filename, const gchar *local_path, GError **error) +{ + g_assert(OBEXSESSION_IS(self)); + + dbus_g_proxy_call(self->priv->dbus_g_proxy, "CopyRemoteFile", error, G_TYPE_STRING, remote_filename, G_TYPE_STRING, local_path, G_TYPE_INVALID, G_TYPE_INVALID); +} + +/* void CopyRemoteFileByType(string type, string local_path) */ +void obexsession_copy_remote_file_by_type(OBEXSession *self, const gchar *type, const gchar *local_path, GError **error) +{ + g_assert(OBEXSESSION_IS(self)); + + dbus_g_proxy_call(self->priv->dbus_g_proxy, "CopyRemoteFileByType", error, G_TYPE_STRING, type, G_TYPE_STRING, local_path, G_TYPE_INVALID, G_TYPE_INVALID); +} + +/* void CreateFolder(string folder_name) */ +void obexsession_create_folder(OBEXSession *self, const gchar *folder_name, GError **error) +{ + g_assert(OBEXSESSION_IS(self)); + + dbus_g_proxy_call(self->priv->dbus_g_proxy, "CreateFolder", error, G_TYPE_STRING, folder_name, G_TYPE_INVALID, G_TYPE_INVALID); +} + +/* void DeleteRemoteFile(string remote_filename) */ +void obexsession_delete_remote_file(OBEXSession *self, const gchar *remote_filename, GError **error) +{ + g_assert(OBEXSESSION_IS(self)); + + dbus_g_proxy_call(self->priv->dbus_g_proxy, "DeleteRemoteFile", error, G_TYPE_STRING, remote_filename, G_TYPE_INVALID, G_TYPE_INVALID); +} + +/* void Disconnect() */ +void obexsession_disconnect(OBEXSession *self, GError **error) +{ + g_assert(OBEXSESSION_IS(self)); + + dbus_g_proxy_call(self->priv->dbus_g_proxy, "Disconnect", error, G_TYPE_INVALID, G_TYPE_INVALID); +} + +/* string GetCapability() */ +gchar *obexsession_get_capability(OBEXSession *self, GError **error) +{ + g_assert(OBEXSESSION_IS(self)); + + gchar *ret = NULL; + dbus_g_proxy_call(self->priv->dbus_g_proxy, "GetCapability", error, G_TYPE_INVALID, G_TYPE_STRING, &ret, G_TYPE_INVALID); + + return ret; +} + +/* string GetCurrentPath() */ +gchar *obexsession_get_current_path(OBEXSession *self, GError **error) +{ + g_assert(OBEXSESSION_IS(self)); + + gchar *ret = NULL; + dbus_g_proxy_call(self->priv->dbus_g_proxy, "GetCurrentPath", error, G_TYPE_INVALID, G_TYPE_STRING, &ret, G_TYPE_INVALID); + + return ret; +} + +/* dict GetTransferInfo() */ +GHashTable *obexsession_get_transfer_info(OBEXSession *self, GError **error) +{ + g_assert(OBEXSESSION_IS(self)); + + GHashTable *ret = NULL; + dbus_g_proxy_call(self->priv->dbus_g_proxy, "GetTransferInfo", error, G_TYPE_INVALID, DBUS_TYPE_G_STRING_VARIANT_HASHTABLE, &ret, G_TYPE_INVALID); + + return ret; +} + +/* boolean IsBusy() */ +gboolean obexsession_is_busy(OBEXSession *self, GError **error) +{ + g_assert(OBEXSESSION_IS(self)); + + gboolean ret = FALSE; + dbus_g_proxy_call(self->priv->dbus_g_proxy, "IsBusy", error, G_TYPE_INVALID, G_TYPE_BOOLEAN, &ret, G_TYPE_INVALID); + + return ret; +} + +/* void RemoteCopy(string remote_source, string remote_destination) */ +void obexsession_remote_copy(OBEXSession *self, const gchar *remote_source, const gchar *remote_destination, GError **error) +{ + g_assert(OBEXSESSION_IS(self)); + + dbus_g_proxy_call(self->priv->dbus_g_proxy, "RemoteCopy", error, G_TYPE_STRING, remote_source, G_TYPE_STRING, remote_destination, G_TYPE_INVALID, G_TYPE_INVALID); +} + +/* void RemoteMove(string remote_source, string remote_destination) */ +void obexsession_remote_move(OBEXSession *self, const gchar *remote_source, const gchar *remote_destination, GError **error) +{ + g_assert(OBEXSESSION_IS(self)); + + dbus_g_proxy_call(self->priv->dbus_g_proxy, "RemoteMove", error, G_TYPE_STRING, remote_source, G_TYPE_STRING, remote_destination, G_TYPE_INVALID, G_TYPE_INVALID); +} + +/* string RetrieveFolderListing() */ +gchar *obexsession_retrieve_folder_listing(OBEXSession *self, GError **error) +{ + g_assert(OBEXSESSION_IS(self)); + + gchar *ret = NULL; + dbus_g_proxy_call(self->priv->dbus_g_proxy, "RetrieveFolderListing", error, G_TYPE_INVALID, G_TYPE_STRING, &ret, G_TYPE_INVALID); + + return ret; +} + +/* void SendFile(string local_path) */ +void obexsession_send_file(OBEXSession *self, const gchar *local_path, GError **error) +{ + g_assert(OBEXSESSION_IS(self)); + + dbus_g_proxy_call(self->priv->dbus_g_proxy, "SendFile", error, G_TYPE_STRING, local_path, G_TYPE_INVALID, G_TYPE_INVALID); +} + +/* void SendFileExt(string local_path, string remote_filename, string type) */ +void obexsession_send_file_ext(OBEXSession *self, const gchar *local_path, const gchar *remote_filename, const gchar *type, GError **error) +{ + g_assert(OBEXSESSION_IS(self)); + + dbus_g_proxy_call(self->priv->dbus_g_proxy, "SendFileExt", error, G_TYPE_STRING, local_path, G_TYPE_STRING, remote_filename, G_TYPE_STRING, type, G_TYPE_INVALID, G_TYPE_INVALID); +} + +/* Properties access methods */ +const gchar *obexsession_get_dbus_object_path(OBEXSession *self) +{ + g_assert(OBEXSESSION_IS(self)); + + return dbus_g_proxy_get_path(self->priv->dbus_g_proxy); +} + +/* Signals handlers */ +static void cancelled_handler(DBusGProxy *dbus_g_proxy, gpointer data) +{ + OBEXSession *self = OBEXSESSION(data); + + g_signal_emit(self, signals[CANCELLED], 0); +} + +static void closed_handler(DBusGProxy *dbus_g_proxy, gpointer data) +{ + OBEXSession *self = OBEXSESSION(data); + + g_signal_emit(self, signals[CLOSED], 0); +} + +static void disconnected_handler(DBusGProxy *dbus_g_proxy, gpointer data) +{ + OBEXSession *self = OBEXSESSION(data); + + g_signal_emit(self, signals[DISCONNECTED], 0); +} + +static void error_occurred_handler(DBusGProxy *dbus_g_proxy, const gchar *error_name, const gchar *error_message, gpointer data) +{ + OBEXSession *self = OBEXSESSION(data); + + g_signal_emit(self, signals[ERROR_OCCURRED], 0, error_name, error_message); +} + +static void transfer_completed_handler(DBusGProxy *dbus_g_proxy, gpointer data) +{ + OBEXSession *self = OBEXSESSION(data); + + g_signal_emit(self, signals[TRANSFER_COMPLETED], 0); +} + +static void transfer_progress_handler(DBusGProxy *dbus_g_proxy, const guint64 bytes_transferred, gpointer data) +{ + OBEXSession *self = OBEXSESSION(data); + + g_signal_emit(self, signals[TRANSFER_PROGRESS], 0, bytes_transferred); +} + +static void transfer_started_handler(DBusGProxy *dbus_g_proxy, const gchar *filename, const gchar *local_path, const guint64 total_bytes, gpointer data) +{ + OBEXSession *self = OBEXSESSION(data); + + g_signal_emit(self, signals[TRANSFER_STARTED], 0, filename, local_path, total_bytes); +} + diff --git a/src/lib/obexsession.h b/src/lib/obexsession.h new file mode 100644 index 0000000..a42ff67 --- /dev/null +++ b/src/lib/obexsession.h @@ -0,0 +1,85 @@ +/* + * + * bluez-tools - a set of tools to manage bluetooth devices for linux + * + * Copyright (C) 2010 Alexander Orlenko <zxteam@gmail.com> + * + * + * 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 + * + */ + +#ifndef __OBEXSESSION_H +#define __OBEXSESSION_H + +#include <glib-object.h> + +#define BLUEZ_DBUS_OBEXSESSION_INTERFACE "org.openobex.Session" + +/* + * Type macros + */ +#define OBEXSESSION_TYPE (obexsession_get_type()) +#define OBEXSESSION(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), OBEXSESSION_TYPE, OBEXSession)) +#define OBEXSESSION_IS(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), OBEXSESSION_TYPE)) +#define OBEXSESSION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), OBEXSESSION_TYPE, OBEXSessionClass)) +#define OBEXSESSION_IS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass), OBEXSESSION_TYPE)) +#define OBEXSESSION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), OBEXSESSION_TYPE, OBEXSessionClass)) + +typedef struct _OBEXSession OBEXSession; +typedef struct _OBEXSessionClass OBEXSessionClass; +typedef struct _OBEXSessionPrivate OBEXSessionPrivate; + +struct _OBEXSession { + GObject parent_instance; + + /*< private >*/ + OBEXSessionPrivate *priv; +}; + +struct _OBEXSessionClass { + GObjectClass parent_class; +}; + +/* used by OBEXSESSION_TYPE */ +GType obexsession_get_type(void) G_GNUC_CONST; + +/* + * Method definitions + */ +void obexsession_cancel(OBEXSession *self, GError **error); +void obexsession_change_current_folder(OBEXSession *self, const gchar *path, GError **error); +void obexsession_change_current_folder_backward(OBEXSession *self, GError **error); +void obexsession_change_current_folder_to_root(OBEXSession *self, GError **error); +void obexsession_close(OBEXSession *self, GError **error); +void obexsession_copy_remote_file(OBEXSession *self, const gchar *remote_filename, const gchar *local_path, GError **error); +void obexsession_copy_remote_file_by_type(OBEXSession *self, const gchar *type, const gchar *local_path, GError **error); +void obexsession_create_folder(OBEXSession *self, const gchar *folder_name, GError **error); +void obexsession_delete_remote_file(OBEXSession *self, const gchar *remote_filename, GError **error); +void obexsession_disconnect(OBEXSession *self, GError **error); +gchar *obexsession_get_capability(OBEXSession *self, GError **error); +gchar *obexsession_get_current_path(OBEXSession *self, GError **error); +GHashTable *obexsession_get_transfer_info(OBEXSession *self, GError **error); +gboolean obexsession_is_busy(OBEXSession *self, GError **error); +void obexsession_remote_copy(OBEXSession *self, const gchar *remote_source, const gchar *remote_destination, GError **error); +void obexsession_remote_move(OBEXSession *self, const gchar *remote_source, const gchar *remote_destination, GError **error); +gchar *obexsession_retrieve_folder_listing(OBEXSession *self, GError **error); +void obexsession_send_file(OBEXSession *self, const gchar *local_path, GError **error); +void obexsession_send_file_ext(OBEXSession *self, const gchar *local_path, const gchar *remote_filename, const gchar *type, GError **error); + +const gchar *obexsession_get_dbus_object_path(OBEXSession *self); + +#endif /* __OBEXSESSION_H */ + |