author | korovkin <korovkin> | 2006-07-06 16:28:08 (UTC) |
---|---|---|
committer | korovkin <korovkin> | 2006-07-06 16:28:08 (UTC) |
commit | 43cd66c08de4447998028179d20fd4817aaf16ca (patch) (side-by-side diff) | |
tree | 87888aadc3398c3c633e332cda46d92bb0522d6a | |
parent | adcfc6f4afe184a9eb6fbf458616494dfe0dadda (diff) | |
download | opie-43cd66c08de4447998028179d20fd4817aaf16ca.zip opie-43cd66c08de4447998028179d20fd4817aaf16ca.tar.gz opie-43cd66c08de4447998028179d20fd4817aaf16ca.tar.bz2 |
Added OBEX Push functionality for Bluetooth.
- Added ObexBase - asic class for IR and BT Obex
- Added ObexServer - OBEX Push server.
-rw-r--r-- | core/obex/.cvsignore | 2 | ||||
-rw-r--r-- | core/obex/btobex.cpp | 60 | ||||
-rw-r--r-- | core/obex/btobex.h | 40 | ||||
-rw-r--r-- | core/obex/obex.cpp | 49 | ||||
-rw-r--r-- | core/obex/obex.h | 40 | ||||
-rw-r--r-- | core/obex/obex.pro | 16 | ||||
-rw-r--r-- | core/obex/obexbase.cpp | 74 | ||||
-rw-r--r-- | core/obex/obexbase.h | 99 | ||||
-rw-r--r-- | core/obex/obexhandler.cpp | 44 | ||||
-rw-r--r-- | core/obex/obexhandler.h | 9 | ||||
-rw-r--r-- | core/obex/obexsend.cpp | 2 | ||||
-rw-r--r-- | core/obex/obexserver.cpp | 514 | ||||
-rw-r--r-- | core/obex/obexserver.h | 83 | ||||
-rw-r--r-- | core/obex/receiver.cpp | 9 | ||||
-rw-r--r-- | core/obex/receiver.h | 12 |
15 files changed, 985 insertions, 68 deletions
diff --git a/core/obex/.cvsignore b/core/obex/.cvsignore index ed75078..90f9614 100644 --- a/core/obex/.cvsignore +++ b/core/obex/.cvsignore @@ -1,4 +1,6 @@ Makefile moc_* .moc .obj +obexsendbase.h +obexsendbase.cpp diff --git a/core/obex/btobex.cpp b/core/obex/btobex.cpp index a5bfe5f..212a084 100644 --- a/core/obex/btobex.cpp +++ b/core/obex/btobex.cpp @@ -1,262 +1,294 @@ +/* + =. This file is part of the OPIE Project + .=l. Copyright (c) 2002 Maximilian Reiss <max.reiss@gmx.de> + .>+-= + _;:, .> :=|. This library is free software; you can +.> <, > . <= redistribute it and/or modify it under +:=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; version 2 of the License. + ._= =} : + .%+i> _;_. + .i_,=:_. -<s. This library 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 +..}^=.= = ; Library General Public License for more +++= -. . .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-= this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ +/* + * The Bluetooth OBEX manipulating class implementation + */ #include "btobex.h" #include <manager.h> #include <services.h> /* OPIE */ #include <opie2/oprocess.h> #include <opie2/odebug.h> /* QT */ #include <qfileinfo.h> #include <qstring.h> #include <qmap.h> #include <qmessagebox.h> using namespace OpieObex; using namespace Opie::Core; /* TRANSLATOR OpieObex::Obex */ using namespace OpieTooth; BtObex::BtObex( QObject *parent, const char* name ) - : QObject(parent, name ) + : ObexBase(parent, name ) { m_rec = 0; m_send=0; - m_count = 0; - m_receive = false; - connect( this, SIGNAL(error(int) ), // for recovering to receive - SLOT(slotError() ) ); - connect( this, SIGNAL(sent(bool) ), - SLOT(slotError() ) ); btManager = NULL; }; BtObex::~BtObex() { delete btManager; delete m_rec; delete m_send; } void BtObex::receive() { - m_receive = true; - m_outp = QString::null; - m_rec = new OProcess(); + ObexBase::receive(); + m_rec = new ObexServer(); + odebug << "BT OBEX do receive" << oendl; // TODO mbhaynie: No idea if this actually works -- maybe opd is better. - *m_rec << "obexftpd" << "-b"; // connect to the necessary slots connect(m_rec, SIGNAL(processExited(Opie::Core::OProcess*) ), this, SLOT(slotExited(Opie::Core::OProcess*) ) ); connect(m_rec, SIGNAL(receivedStdout(Opie::Core::OProcess*, char*, int ) ), this, SLOT(slotStdOut(Opie::Core::OProcess*, char*, int) ) ); if(!m_rec->start(OProcess::NotifyOnExit, OProcess::AllOutput) ) { emit done( false ); delete m_rec; m_rec = 0; } } void BtObex::send( const QString& fileName, const QString& bdaddr) { + ObexBase::send(fileName, bdaddr); // if currently receiving stop it send receive - m_count = 0; - m_file = fileName; - m_bdaddr = bdaddr; if (m_send != 0) { if (m_send->isSending()) return; else { delete m_send; m_send = 0; } } if (m_rec != 0 ) { if (m_rec->isRunning() ) { emit error(-1 ); delete m_rec; m_rec = 0; }else{ emit error( -1 ); // we did not delete yet but it's not running slotExited is pending return; } } //Now we need to find out if the OBEX push is supported for this device //And get the port number if (!btManager) { btManager = new Manager("hci0"); connect(btManager, SIGNAL(foundServices(const QString&, Services::ValueList)), this, SLOT(slotFoundServices(const QString&, Services::ValueList))); } btManager->searchServices(bdaddr); } /** * This function reacts on the service discovery finish */ void BtObex::slotFoundServices(const QString&, Services::ValueList svcList) { QValueList<OpieTooth::Services>::Iterator it; QMap<int, QString> classList; //The classes list QMap<int, QString>::Iterator classIt; //Iterator in the class list int portNum = -1; //The desired port number odebug << "BtObex slotFoundServices" << oendl; if (svcList.isEmpty()) { QMessageBox::critical(NULL, tr("Object send"), tr("No services found")); emit error(-1); return; } for (it = svcList.begin(); it != svcList.end(); it++) { classList = (*it).classIdList(); classIt = classList.begin(); if (classIt == classList.end()) continue; ////We really need symbolic names for service IDs //Ok, we have found the object push service if (classIt.key() == 4357) { portNum = (*it).protocolDescriptorList().last().port(); break; } } if (portNum == -1) { QMessageBox::critical(NULL, tr("Object send"), tr("No OBEX Push service")); emit error(-1); return; } m_port = portNum; sendNow(); } void BtObex::sendNow(){ QString m_dst = ""; int result; //function call result if ( m_count >= 25 ) { // could not send emit error(-1 ); emit sent(false); return; } // OProcess inititialisation m_send = new ObexPush(); // connect to slots Exited and and StdOut connect(m_send, SIGNAL(sendComplete(int)), this, SLOT(slotPushComplete(int)) ); connect(m_send, SIGNAL(sendError(int)), this, SLOT(slotPushError(int)) ); connect(m_send, SIGNAL(status(QCString&)), this, SLOT(slotPushStatus(QCString&) ) ); + /* + * FIXME: this delay is made because some cell phones understands an error + * later. + */ ::sleep(4); // now start it result = m_send->send(m_bdaddr, m_port, m_file, m_dst); if (result > 0) //Sending process is actually running return; else if (result < 0) { m_count = 25; emit error(-1 ); delete m_send; m_send=0; } // end m_count++; emit currentTry( m_count ); } void BtObex::slotExited(OProcess* proc ){ odebug << proc->name() << " exited with result " << proc->exitStatus() << oendl; if (proc == m_rec ) // receive process received(); + } void BtObex::slotStdOut(OProcess* proc, char* buf, int len){ if ( proc == m_rec ) { // only receive QByteArray ar( len ); memcpy( ar.data(), buf, len ); m_outp.append( ar ); + QCString str(buf, len); + odebug << str << oendl; } } void BtObex::slotPushComplete(int result) { if (result == 0) { delete m_send; m_send=0; emit sent(true); } else { // it failed maybe the other side wasn't ready // let's try it again delete m_send; m_send = 0; sendNow(); } } void BtObex::slotPushError(int) { emit error( -1 ); delete m_send; m_send = 0; } void BtObex::slotPushStatus(QCString& str) { odebug << str << oendl; } void BtObex::received() { if (m_rec->normalExit() ) { if ( m_rec->exitStatus() == 0 ) { // we got one QString filename = parseOut(); + odebug << "OBEX " << filename << " received" << oendl; emit receivedFile( filename ); } }else{ emit done(false); }; delete m_rec; m_rec = 0; receive(); } // This probably doesn't do anything useful for bt. QString BtObex::parseOut(){ QString path; QStringList list = QStringList::split("\n", m_outp); QStringList::Iterator it; for (it = list.begin(); it != list.end(); ++it ) { odebug << (*it) << oendl; if ( (*it).startsWith("Wrote" ) ) { int pos = (*it).findRev('(' ); if ( pos > 0 ) { path = (*it).remove( pos, (*it).length() - pos ); path = path.mid(6 ); path = path.stripWhiteSpace(); } } } return path; } /** * when sent is done slotError is called we will start receive again */ void BtObex::slotError() { + ObexBase::slotError(); if ( m_receive ) receive(); }; void BtObex::setReceiveEnabled( bool receive ) { + odebug << "BT OBEX setReceiveEnabled " << receive << oendl; + ObexBase::setReceiveEnabled(receive); if ( !receive ) { // m_receive = false; shutDownReceive(); } } void BtObex::shutDownReceive() { if (m_rec != 0 ) { if (m_rec->isRunning() ) { emit error(-1 ); delete m_rec; m_rec = 0; } } } diff --git a/core/obex/btobex.h b/core/obex/btobex.h index 9c1ab70..7e91c06 100644 --- a/core/obex/btobex.h +++ b/core/obex/btobex.h @@ -1,90 +1,118 @@ +/* + =. This file is part of the OPIE Project + .=l. Copyright (c) 2002 Maximilian Reiss <max.reiss@gmx.de> + .>+-= + _;:, .> :=|. This library is free software; you can +.> <, > . <= redistribute it and/or modify it under +:=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; version 2 of the License. + ._= =} : + .%+i> _;_. + .i_,=:_. -<s. This library 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 +..}^=.= = ; Library General Public License for more +++= -. . .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-= this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ +/* + * The Bluetooth OBEX manipulating class declaration + */ #ifndef OpieBtObex_H #define OpieBtObex_H +#include "obexbase.h" #include <qobject.h> #include <services.h> #include <manager.h> #include <obexpush.h> +#include "obexserver.h" namespace Opie {namespace Core {class OProcess;}} class QCopChannel; using namespace OpieTooth; namespace OpieObex { // Maybe this should be derved from Obex. - class BtObex : public QObject { + class BtObex : public ObexBase { Q_OBJECT public: /** * BtObex c'tor look */ BtObex( QObject *parent, const char* name); /** * d'tor */ ~BtObex(); /** TODO mbhaynie -- Maybe opd would be a better way to receive. * Starting listening to Bluetooth after enabled by the applet * a signal gets emitted when received a file */ void receive(); void send( const QString&, const QString& ); void setReceiveEnabled( bool = false ); signals: /** * a signal * @param path The path to the received file */ void receivedFile( const QString& path); /** * error signal if the program couldn't be started or the * the connection timed out */ void error( int ); /** * The current try to receive data */ void currentTry(unsigned int); /** * signal sent The file got beamed to the remote location */ void sent(bool); void done(bool); private: - uint m_count; - QString m_file; - QString m_outp; - QString m_bdaddr; int m_port; ObexPush* m_send; - Opie::Core::OProcess *m_rec; bool m_receive : 1; OpieTooth::Manager* btManager; void shutDownReceive(); + ObexServer* m_rec; private slots: // Push process slots void slotPushStatus(QCString&); void slotPushComplete(int); void slotPushError(int); // the process exited void slotExited(Opie::Core::OProcess*) ; void slotStdOut(Opie::Core::OProcess*, char*, int); void slotError(); void slotFoundServices(const QString&, Services::ValueList); private: void sendNow(); QString parseOut(); void received(); }; }; #endif diff --git a/core/obex/obex.cpp b/core/obex/obex.cpp index 36634ec..95c561a 100644 --- a/core/obex/obex.cpp +++ b/core/obex/obex.cpp @@ -1,187 +1,212 @@ +/* + =. This file is part of the OPIE Project + .=l. Copyright (c) 2002 Maximilian Reiss <max.reiss@gmx.de> + .>+-= + _;:, .> :=|. This library is free software; you can +.> <, > . <= redistribute it and/or modify it under +:=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; version 2 of the License. + ._= =} : + .%+i> _;_. + .i_,=:_. -<s. This library 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 +..}^=.= = ; Library General Public License for more +++= -. . .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-= this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ +/* + * The Infrared OBEX handling class implementation + */ #include "obex.h" /* OPIE */ #include <opie2/oprocess.h> #include <opie2/odebug.h> /* QT */ #include <qfileinfo.h> using namespace OpieObex; using namespace Opie::Core; /* TRANSLATOR OpieObex::Obex */ Obex::Obex( QObject *parent, const char* name ) - : QObject(parent, name ) + : ObexBase(parent, name ) { m_rec = 0; m_send=0; - m_count = 0; - m_receive = false; - connect( this, SIGNAL(error(int) ), // for recovering to receive - SLOT(slotError() ) ); - connect( this, SIGNAL(sent(bool) ), - SLOT(slotError() ) ); }; Obex::~Obex() { delete m_rec; delete m_send; } void Obex::receive() { - m_receive = true; - m_outp = QString::null; + ObexBase::receive(); m_rec = new OProcess(); *m_rec << "irobex_palm3"; // connect to the necessary slots connect(m_rec, SIGNAL(processExited(Opie::Core::OProcess*) ), this, SLOT(slotExited(Opie::Core::OProcess*) ) ); connect(m_rec, SIGNAL(receivedStdout(Opie::Core::OProcess*, char*, int ) ), this, SLOT(slotStdOut(Opie::Core::OProcess*, char*, int) ) ); if(!m_rec->start(OProcess::NotifyOnExit, OProcess::AllOutput) ) { emit done( false ); delete m_rec; m_rec = 0; } } -void Obex::send( const QString& fileName) { // if currently receiving stop it send receive - m_count = 0; - m_file = fileName; +// if currently receiving stop it send receive +void Obex::send(const QString& fileName, const QString& addr) { + ObexBase::send(fileName, addr); if (m_rec != 0 ) { if (m_rec->isRunning() ) { emit error(-1 ); delete m_rec; m_rec = 0; }else{ emit error( -1 ); // we did not delete yet but it's not running slotExited is pending return; } } sendNow(); } void Obex::sendNow(){ if ( m_count >= 25 ) { // could not send emit error(-1 ); emit sent(false); return; } // OProcess inititialisation m_send = new OProcess(); m_send->setWorkingDirectory( QFileInfo(m_file).dirPath(true) ); *m_send << "irobex_palm3"; *m_send << QFile::encodeName(QFileInfo(m_file).fileName()); // connect to slots Exited and and StdOut connect(m_send, SIGNAL(processExited(Opie::Core::OProcess*) ), this, SLOT(slotExited(Opie::Core::OProcess*)) ); connect(m_send, SIGNAL(receivedStdout(Opie::Core::OProcess*, char*, int )), this, SLOT(slotStdOut(Opie::Core::OProcess*, char*, int) ) ); // now start it if (!m_send->start(/*OProcess::NotifyOnExit, OProcess::AllOutput*/ ) ) { m_count = 25; emit error(-1 ); delete m_send; m_send=0; } // end m_count++; emit currentTry( m_count ); } void Obex::slotExited(OProcess* proc ){ if (proc == m_rec ) // receive process received(); else if ( proc == m_send ) sendEnd(); } void Obex::slotStdOut(OProcess* proc, char* buf, int len){ if ( proc == m_rec ) { // only receive QByteArray ar( len ); memcpy( ar.data(), buf, len ); m_outp.append( ar ); } } void Obex::received() { if (m_rec->normalExit() ) { if ( m_rec->exitStatus() == 0 ) { // we got one QString filename = parseOut(); emit receivedFile( filename ); } }else{ emit done(false); }; delete m_rec; m_rec = 0; receive(); } void Obex::sendEnd() { if (m_send->normalExit() ) { if ( m_send->exitStatus() == 0 ) { delete m_send; m_send=0; emit sent(true); }else if (m_send->exitStatus() == 255 ) { // it failed maybe the other side wasn't ready // let's try it again delete m_send; m_send = 0; sendNow(); } }else { emit error( -1 ); delete m_send; m_send = 0; } } QString Obex::parseOut( ){ QString path; QStringList list = QStringList::split("\n", m_outp); QStringList::Iterator it; for (it = list.begin(); it != list.end(); ++it ) { if ( (*it).startsWith("Wrote" ) ) { int pos = (*it).findRev('(' ); if ( pos > 0 ) { path = (*it).remove( pos, (*it).length() - pos ); path = path.mid(6 ); path = path.stripWhiteSpace(); } } } return path; } /** * when sent is done slotError is called we will start receive again */ void Obex::slotError() { + ObexBase::slotError(); if ( m_receive ) receive(); }; void Obex::setReceiveEnabled( bool receive ) { + ObexBase::setReceiveEnabled(receive); if ( !receive ) { // m_receive = false; shutDownReceive(); } } void Obex::shutDownReceive() { if (m_rec != 0 ) { if (m_rec->isRunning() ) { emit error(-1 ); delete m_rec; m_rec = 0; } } } diff --git a/core/obex/obex.h b/core/obex/obex.h index 5993976..36ff29a 100644 --- a/core/obex/obex.h +++ b/core/obex/obex.h @@ -1,84 +1,114 @@ +/* + =. This file is part of the OPIE Project + .=l. Copyright (c) 2002 Maximilian Reiss <max.reiss@gmx.de> + .>+-= + _;:, .> :=|. This library is free software; you can +.> <, > . <= redistribute it and/or modify it under +:=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; version 2 of the License. + ._= =} : + .%+i> _;_. + .i_,=:_. -<s. This library 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 +..}^=.= = ; Library General Public License for more +++= -. . .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-= this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. +*/ +/* + * The Infrared OBEX handling class declaration + */ #ifndef OpieObex_H #define OpieObex_H +#include "obexbase.h" #include <qobject.h> namespace Opie {namespace Core {class OProcess;}} class QCopChannel; namespace OpieObex { - class Obex : public QObject { + class Obex : public ObexBase { Q_OBJECT public: /** * Obex c'tor look */ Obex( QObject *parent, const char* name); /** * d'tor */ ~Obex(); /** * Starting listening to irda after enabled by the applet * a signal gets emitted when received a file */ - void receive(); - void send( const QString& ); - void setReceiveEnabled( bool = false ); + virtual void receive(); + virtual void send(const QString& filename, const QString& addr); + virtual void setReceiveEnabled( bool = false ); signals: /** * a signal * @param path The path to the received file */ void receivedFile( const QString& path); /** * error signal if the program couldn't be started or the * the connection timed out */ void error( int ); /** * The current try to receive data */ void currentTry(unsigned int); /** * signal sent The file got beamed to the remote location */ void sent(bool); void done(bool); private: uint m_count; QString m_file; QString m_outp; Opie::Core::OProcess *m_send; Opie::Core::OProcess *m_rec; bool m_receive : 1; void shutDownReceive(); private slots: /** * send over palm obex */ //void send(const QString&); // the process exited void slotExited(Opie::Core::OProcess* proc) ; void slotStdOut(Opie::Core::OProcess*, char*, int); - void slotError(); + virtual void slotError(); private: void sendNow(); QString parseOut(); void received(); void sendEnd(); }; }; #endif diff --git a/core/obex/obex.pro b/core/obex/obex.pro index 33cb957..1fc6958 100644 --- a/core/obex/obex.pro +++ b/core/obex/obex.pro @@ -1,14 +1,20 @@ TEMPLATE = lib CONFIG += qt warn_on -HEADERS = obex.h btobex.h obexhandler.h obexsend.h receiver.h obeximpl.h -SOURCES = obex.cpp btobex.cpp obexsend.cpp obexhandler.cpp receiver.cpp obeximpl.cpp +HEADERS = obex.h btobex.h obexhandler.h obexsend.h receiver.h obeximpl.h obexbase.h obexserver.h +SOURCES = obex.cpp btobex.cpp obexsend.cpp obexhandler.cpp receiver.cpp obeximpl.cpp obexbase.cpp obexserver.cpp TARGET = opieobex DESTDIR = $(OPIEDIR)/plugins/obex INTERFACES = obexsendbase.ui -INCLUDEPATH += $(OPIEDIR)/include $(OPIEDIR)/core/launcher $(OPIEDIR)/noncore/net/opietooth/lib +INCLUDEPATH += $(OPIEDIR)/include $(OPIEDIR)/core/launcher DEPENDPATH += -LIBS += -lopietooth1 -lqpe -lopiecore2 -VERSION = 0.0.3 +LIBS += -lqpe -lopiecore2 +VERSION = 0.0.4 include( $(OPIEDIR)/include.pro ) target.path = $$prefix/plugins/applets + +#FIXME: These parameters are used if bluetooth is used +INCLUDEPATH += $(OPIEDIR)/noncore/net/opietooth/lib +LIBS += -lopietooth1 -lbluetooth -lopenobex +DEFINES += BLUETOOTH + diff --git a/core/obex/obexbase.cpp b/core/obex/obexbase.cpp new file mode 100644 index 0000000..8eda04e --- a/dev/null +++ b/core/obex/obexbase.cpp @@ -0,0 +1,74 @@ +/* + =. This file is part of the OPIE Project + .=l. Copyright (c) 2002 Maximilian Reiss <max.reiss@gmx.de> + .>+-= + _;:, .> :=|. This library is free software; you can +.> <, > . <= redistribute it and/or modify it under +:=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; version 2 of the License. + ._= =} : + .%+i> _;_. + .i_,=:_. -<s. This library 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 +..}^=.= = ; Library General Public License for more +++= -. . .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-= this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ +/* + * The basic class for OBEX manipulating classes implementation + */ + +#include "obexbase.h" + +/* OPIE */ +#include <opie2/oprocess.h> +#include <opie2/odebug.h> + +using namespace OpieObex; + +using namespace Opie::Core; + +ObexBase::ObexBase(QObject *parent, const char* name) + : QObject(parent, name) +{ + m_count = 0; + m_receive = false; + connect( this, SIGNAL(error(int) ), // for recovering to receive + SLOT(slotError() ) ); + connect( this, SIGNAL(sent(bool) ), + SLOT(slotError() ) ); +} + +ObexBase::~ObexBase() { +} + +void ObexBase::receive() { + m_receive = true; + m_outp = QString::null; +} + +void ObexBase::send( const QString& fileName, const QString& bdaddr) { + // if currently receiving stop it send receive + m_count = 0; + m_file = fileName; + m_bdaddr = bdaddr; +} + +void ObexBase::setReceiveEnabled(bool) { +} + +void ObexBase::slotError() { +} + +//eof diff --git a/core/obex/obexbase.h b/core/obex/obexbase.h new file mode 100644 index 0000000..f65d922 --- a/dev/null +++ b/core/obex/obexbase.h @@ -0,0 +1,99 @@ +/* + =. This file is part of the OPIE Project + .=l. Copyright (c) 2002 Maximilian Reiss <max.reiss@gmx.de> + .>+-= + _;:, .> :=|. This library is free software; you can +.> <, > . <= redistribute it and/or modify it under +:=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; version 2 of the License. + ._= =} : + .%+i> _;_. + .i_,=:_. -<s. This library 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 +..}^=.= = ; Library General Public License for more +++= -. . .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-= this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ +/* + * The basic class for OBEX manipulating classes declaration + */ +#ifndef ObexBase_H +#define ObexBase_H + +#include <qobject.h> + +namespace Opie {namespace Core {class OProcess;}} +class QCopChannel; +namespace OpieObex { + class ObexBase : public QObject { + Q_OBJECT + public: + /** + * ObexBase constructor look + */ + ObexBase(QObject *parent, const char* name); + /** + * d'tor + */ + virtual ~ObexBase(); + /** + * Starting listening to an interface after enabled by the applet + * a signal gets emitted when received a file + */ + virtual void receive(); + /** + * Send the file + * @param the name of the file + * @param the address of the device + */ + virtual void send(const QString&, const QString&); + /** + * Stop receiving + * @param if true - does nothing if false - stops receiving + */ + virtual void setReceiveEnabled(bool = false); + signals: + /** + * Notify the upper level that we have received the file + * @param path The path to the received file + */ + void receivedFile(const QString& path); + /** + * error signal if the program couldn't be started or the + * the connection timed out + */ + void error(int); + /** + * The current try to receive data + */ + void currentTry(unsigned int); + /** + * signal sent The file got beamed to the remote location + */ + void sent(bool); + void done(bool); + protected: + uint m_count; + QString m_file; + QString m_outp; + QString m_bdaddr; + bool m_receive : 1; + protected slots: + virtual void slotError(); + }; +}; + +#endif +//eof + diff --git a/core/obex/obexhandler.cpp b/core/obex/obexhandler.cpp index 28f9b5b..5d98ded 100644 --- a/core/obex/obexhandler.cpp +++ b/core/obex/obexhandler.cpp @@ -1,67 +1,79 @@ #include <qpe/qcopenvelope_qws.h> #include <qpe/qpeapplication.h> #include "obexsend.h" #include "receiver.h" #include "obexhandler.h" using namespace OpieObex; /* TRANSLATOR OpieObex::ObexHandler */ ObexHandler::ObexHandler() { - m_wasRec = false; + m_wasRec[REC_IRDA] = false; + m_receiver[REC_IRDA] = 0l; + m_wasRec[REC_BLUETOOTH] = false; + m_receiver[REC_BLUETOOTH] = 0l; m_sender = 0l; - m_receiver = 0l; + m_type = REC_IRDA; //FIXME: Just to init to something QCopChannel* chan = new QCopChannel("QPE/Obex"); connect(chan, SIGNAL(received(const QCString&,const QByteArray&) ), this, SLOT(irdaMessage(const QCString&,const QByteArray&) ) ); } ObexHandler::~ObexHandler() { delete m_sender; - delete m_receiver; + delete m_receiver[REC_IRDA]; + delete m_receiver[REC_BLUETOOTH]; } void ObexHandler::doSend(const QString& str, const QString& desc) { delete m_sender; m_sender = new SendWidget; m_sender->raise(); QPEApplication::showWidget( m_sender ); connect(m_sender, SIGNAL(done() ), this, SLOT(slotSent() ) ); m_sender->send( str, desc ); } -void ObexHandler::doReceive(bool b) { - if (m_receiver && b ) return; // we should enable receiver and it is on - else if (!m_receiver && !b ) return; // we should disbale receiver and it is off - else if (m_receiver && !b ) { - delete m_receiver; - m_receiver=0; - }else if (!m_receiver && b ) { - m_receiver= new Receiver; +void ObexHandler::doReceive(RecType type, bool b) { + if (m_receiver[type] && b ) return; // we should enable receiver and it is on + else if (!m_receiver[type] && !b ) return; // we should disbale receiver and it is off + else if (m_receiver[type] && !b ) { + delete m_receiver[type]; + m_receiver[type] = 0; + }else if (!m_receiver[type] && b ) { + m_receiver[type] = new Receiver(type); } } void ObexHandler::slotSent() { QString file = m_sender->file(); delete m_sender; m_sender = 0; QCopEnvelope e ("QPE/Obex", "done(QString)" ); e << file; - doReceive(m_wasRec ); - m_wasRec = false; + doReceive(REC_IRDA, m_wasRec[REC_IRDA]); + doReceive(REC_BLUETOOTH, m_wasRec[REC_BLUETOOTH]); + m_wasRec[REC_IRDA] = false; + m_wasRec[REC_BLUETOOTH] = false; } void ObexHandler::irdaMessage( const QCString& msg, const QByteArray& data) { QDataStream stream( data, IO_ReadOnly ); if ( msg == "send(QString,QString,QString)" ) { QString name, desc; stream >> desc; stream >> name; - m_wasRec = (m_receiver != 0 ); - doReceive( false ); + m_wasRec[REC_IRDA] = (m_receiver[REC_IRDA] != 0 ); + m_wasRec[REC_BLUETOOTH] = (m_receiver[REC_BLUETOOTH] != 0 ); + doReceive(REC_IRDA, false); + doReceive(REC_BLUETOOTH, false); doSend(name, desc); }else if (msg == "receive(int)") { int rec; stream >> rec; - doReceive(rec); + doReceive(REC_IRDA, rec); + }else if (msg == "btreceive(int)") { + int rec; + stream >> rec; + doReceive(REC_BLUETOOTH, rec); } } diff --git a/core/obex/obexhandler.h b/core/obex/obexhandler.h index 230c4f0..de2232e 100644 --- a/core/obex/obexhandler.h +++ b/core/obex/obexhandler.h @@ -1,39 +1,40 @@ #ifndef OPIE_OBEX_HANDLER_H #define OPIE_OBEX_HANDLER_H #include <qobject.h> #include <qstring.h> +#include "receiver.h" namespace OpieObex { /* * The handler is responsible for handling receiving * and sending * It will connect to the IrDa QCOP channel and then * wait for activation... */ class SendWidget; class Receiver; class ObexHandler : public QObject { Q_OBJECT public: ObexHandler(); ~ObexHandler(); private slots: void doSend(const QString&,const QString& ); - void doReceive(bool b); + void doReceive(RecType type, bool b); void slotSent(); private slots: // QCOP message void irdaMessage( const QCString&, const QByteArray& ); private: SendWidget* m_sender; - Receiver* m_receiver; - bool m_wasRec : 1; - + Receiver* m_receiver[2]; //For IRDA and Bluetooth + bool m_wasRec[2]; + RecType m_type; //receiver type (IRDA or Bluetooth) }; } #endif diff --git a/core/obex/obexsend.cpp b/core/obex/obexsend.cpp index 8432d16..9a30a0a 100644 --- a/core/obex/obexsend.cpp +++ b/core/obex/obexsend.cpp @@ -1,252 +1,252 @@ // 7-Jul-2005 mbh@sdgsystems.com: replace hand coded form with one // generated via QT2 Designer. The new form supports // selection of target devices, as opposed to sending to // all. #include "obex.h" #include "btobex.h" #include "obexsend.h" using namespace OpieObex; /* OPIE */ #include <opie2/odebug.h> #include <qpe/qcopenvelope_qws.h> #include <qpe/resource.h> using namespace Opie::Core; /* QT */ #include <qlabel.h> #include <qpushbutton.h> #include <qpixmap.h> #include <qlistview.h> #include <unistd.h> /* TRANSLATOR OpieObex::SendWidget */ SendWidget::SendWidget( QWidget* parent, const char* name ) : obexSendBase( parent, name ) { initUI(); } SendWidget::~SendWidget() { } void SendWidget::initUI() { m_obex = new Obex(this, "obex"); connect(m_obex, SIGNAL(error(int) ), this, SLOT(slotIrError(int) ) ); connect(m_obex, SIGNAL(sent(bool) ), this, SLOT(slotIrSent(bool) ) ); connect(m_obex, SIGNAL(currentTry(unsigned int) ), this, SLOT(slotIrTry(unsigned int) ) ); QCopChannel* chan = new QCopChannel("QPE/IrDaAppletBack", this ); connect(chan, SIGNAL(received(const QCString&,const QByteArray&) ), this, SLOT(dispatchIrda(const QCString&,const QByteArray&) ) ); m_btobex = new BtObex(this, "btobex"); connect(m_btobex, SIGNAL(error(int) ), this, SLOT(slotBtError(int) ) ); connect(m_btobex, SIGNAL(sent(bool) ), this, SLOT(slotBtSent(bool) ) ); connect(m_btobex, SIGNAL(currentTry(unsigned int) ), this, SLOT(slotBtTry(unsigned int) ) ); chan = new QCopChannel("QPE/BluetoothBack", this ); connect(chan, SIGNAL(received(const QCString&,const QByteArray&) ), this, SLOT(dispatchBt(const QCString&,const QByteArray&) ) ); } /* * in send we'll first set everything up * and then wait for a list of devices. */ void SendWidget::send( const QString& file, const QString& desc ) { m_file = file; m_irDa.clear(); m_start = 0; fileToSend->setText(desc.isEmpty() ? file : desc ); scan_for_receivers(); } int SendWidget::addReceiver(const char *r, const char *icon) { QListViewItem * item = new QListViewItem( receiverList, 0 ); item->setText( 0, r); item->setPixmap( 1, Resource::loadPixmap( icon ) ); int id=receivers.count(); receivers[id]=item; return id; } bool SendWidget::receiverSelected(int id) { return (bool)(receivers[id]->pixmap(2) != NULL); } void SendWidget::setReceiverStatus( int id, const QString& status ) { if ( !receivers.contains(id) ) return; receivers[id]->setText(3, status ); } void SendWidget::slotIrDaDevices( const QStringList& list) { for (QStringList::ConstIterator it = list.begin(); it != list.end(); ++it ) { int id = addReceiver(*it, "obex/irda.png"); m_irDa.insert( id, (*it) ); } irdaStatus->setText( tr("ready.")); m_irDaIt = m_irDa.begin(); } void SendWidget::slotBTDevices( const QMap<QString, QString>& str ) { for(QMap<QString, QString>::ConstIterator it = str.begin(); it != str.end(); ++it ) { int id = addReceiver(it.key(), "obex/bt.png"); m_bt.insert( id, Pair( it.key(), it.data() ) ); } btStatus->setText(tr("ready.")); m_btIt = m_bt.begin(); } void SendWidget::slotSelectedDevice( int, int ) { /* if ( name == m_irDeSearch ) { for (QMap<int, QString>::Iterator it= m_irDa.begin(); it != m_irDa.end(); ++it ) m_devBox->removeDevice( it.key() ); QCopEnvelope e2("QPE/IrDaApplet", "listDevices()"); }*/ } void SendWidget::dispatchIrda( const QCString& str, const QByteArray& ar ) { if ( str == "devices(QStringList)" ) { QDataStream stream( ar, IO_ReadOnly ); QStringList list; stream >> list; slotIrDaDevices( list ); } } void SendWidget::slotIrError( int ) { irdaStatus->setText(tr("error :(")); } void SendWidget::slotIrSent( bool b) { QString text = b ? tr("Sent") : tr("Failure"); setReceiverStatus( m_irDaIt.key(), text ); ++m_irDaIt; slotStartIrda(); } void SendWidget::slotIrTry(unsigned int trI) { setReceiverStatus(m_irDaIt.key(), tr("Try %1").arg( QString::number( trI ) )); } void SendWidget::slotStartIrda() { if ( !m_irDa.count() ) return; if ( m_irDaIt == m_irDa.end() || !receiverSelected(m_irDaIt.key())) { irdaStatus->setText(tr("complete.")); return; } setReceiverStatus( m_irDaIt.key(), tr("Start sending") ); - m_obex->send( m_file ); + m_obex->send( m_file, tr("noaddress") ); } void SendWidget::dispatchBt( const QCString& str, const QByteArray& ar ) { if ( str == "devices(QStringMap)" ) { QDataStream stream( ar, IO_ReadOnly ); QMap<QString, QString> btmap; stream >> btmap; slotBTDevices( btmap ); } } void SendWidget::slotBtError( int ) { btStatus->setText(tr("error :(")); } void SendWidget::slotBtSent( bool b) { QString text = b ? tr("Sent") : tr("Failure"); setReceiverStatus( m_btIt.key(), text ); ++m_btIt; slotStartBt(); } void SendWidget::slotBtTry(unsigned int trI) { setReceiverStatus( m_btIt.key(), tr("Try %1").arg( QString::number( trI ) ) ); } void SendWidget::slotStartBt() { // skip past unselected receivers while((m_btIt != m_bt.end()) && !receiverSelected(m_btIt.key())) ++m_btIt; if (m_btIt == m_bt.end() ) { btStatus->setText(tr("complete.")); return; } setReceiverStatus( m_btIt.key(), tr("Start sending") ); m_btobex->send( m_file, m_btIt.data().second() ); } void SendWidget::send_to_receivers() { slotStartIrda(); slotStartBt(); } void SendWidget::scan_for_receivers() { receiverList->clear(); receivers.clear(); sendButton->setDisabled( true ); if ( !QCopChannel::isRegistered("QPE/IrDaApplet") ) { irdaStatus->setText(tr("not enabled.")); } else { QCopEnvelope e1("QPE/IrDaApplet", "enableIrda()"); irdaStatus->setText(tr("searching...")); sendButton->setEnabled( true ); QCopEnvelope e2("QPE/IrDaApplet", "listDevices()"); } if ( !QCopChannel::isRegistered("QPE/Bluetooth") ) { btStatus->setText(tr("not enabled.")); } else { QCopEnvelope e1("QPE/Bluetooth", "enableBluetooth()"); btStatus->setText(tr("searching...")); sendButton->setEnabled( true ); QCopEnvelope e3("QPE/Bluetooth", "listDevices()"); } } void SendWidget::toggle_receiver(QListViewItem* item) { // toggle the state of an individual receiver. if(item->pixmap(2)) item->setPixmap(2,QPixmap()); else item->setPixmap(2,Resource::loadPixmap("obex/check.png")); } void SendWidget::closeEvent( QCloseEvent* evt) { delete m_obex; m_obex = NULL; delete m_btobex; m_btobex = NULL; obexSendBase::closeEvent(evt); { QCopEnvelope e("QPE/IrDaApplet", "disableIrda()"); } { QCopEnvelope e("QPE/Bluetooth", "disableBluetooth()"); } } void SendWidget::userDone() { close(); } QString SendWidget::file()const { return m_file; } diff --git a/core/obex/obexserver.cpp b/core/obex/obexserver.cpp new file mode 100644 index 0000000..95196de --- a/dev/null +++ b/core/obex/obexserver.cpp @@ -0,0 +1,514 @@ +/* + =. This file is part of the OPIE Project + .=l. Copyright (c) 2002 Maximilian Reiss <max.reiss@gmx.de> + .>+-= + _;:, .> :=|. This library is free software; you can +.> <, > . <= redistribute it and/or modify it under +:=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; version 2 of the License. + ._= =} : + .%+i> _;_. + .i_,=:_. -<s. This library 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 +..}^=.= = ; Library General Public License for more +++= -. . .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-= this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ +/* + * The OBEX server class implementation + * Based on OBEX server from GPE (thanks, guys) + */ + +#include "obexserver.h" +#include <unistd.h> +#include <opie2/odebug.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <errno.h> +#include <stdlib.h> +#include <stdio.h> +#include <fcntl.h> +#include <qapplication.h> +#include <opie2/oprocctrl.h> +#include <qstring.h> +#include <qfile.h> + +using namespace Opie::Core; +using namespace Opie::Core::Internal; +using namespace OpieObex; + +ObexServer::ObexServer() : + OProcess(tr("ObexServer"), 0, "ObexServer") +{ + m_obex = NULL; +} + +ObexServer::~ObexServer() +{ + stop(); +} + +/** + * Function handles the file received + * @param name the file name + * @param data the file data + * @param data_len the data length + * @return 0 on success -1 on error + */ +static int file_received(uint8_t* name, const uint8_t* data, size_t data_len) +{ + QString path("/tmp/"); + path += (char*)name; + QFile out(path); + int err = 0; + + if (!out.open(IO_Raw | IO_ReadWrite | IO_Truncate)) { + printf("File %s open error %d\n", (const char*)path, errno); + err = -1; + goto out; + } + if (out.writeBlock((const char*)data, data_len) < 0) { + printf("File %s write error %d\n", (const char*)path, errno); + err = -1; + goto out; + } +out: + out.close(); + if (err == 0) { + printf("Wrote %s (%d bytes)\n", (const char*)path, data_len); + fflush(stdout); + } + return err; +} + +/** + * Function handles the situation when the PUT request has been done + * @param handle OBEX connection handle + * @param object OBEX object itself + */ +static int put_done(obex_t* handle, obex_object_t* object) +{ + obex_headerdata_t hv; //Received file header + uint8_t hi; //Type of the request + uint32_t hlen; //File (file name) length + int err = 0; + + const uint8_t *body = NULL; + int body_len = 0; + uint8_t* name = NULL; + + while (OBEX_ObjectGetNextHeader (handle, object, &hi, &hv, &hlen)) { + switch(hi) { + case OBEX_HDR_BODY: + body = hv.bs; + body_len = hlen; + break; + + case OBEX_HDR_NAME: + name = new uint8_t[(hlen / 2) + 1]; + OBEX_UnicodeToChar(name, hv.bs, hlen); + break; + + default: + break; + } + } + + if (body) + err = file_received(name, body, body_len); + + if (name) + delete[] name; + return err; +} + +/** + * Function handles OBEX request + * @param handle OBEX connection handle + * @param object OBEX object itself + * @param mode + * @param event event code + * @param cmd OBEX command itself + */ +static void handle_request (obex_t* handle, obex_object_t* object, + int event, int cmd) +{ + (void)event; + switch(cmd) { + case OBEX_CMD_SETPATH: + OBEX_ObjectSetRsp (object, OBEX_RSP_CONTINUE, OBEX_RSP_SUCCESS); + break; + case OBEX_CMD_PUT: + if (put_done (handle, object) < 0) + OBEX_ObjectSetRsp (object, OBEX_RSP_INTERNAL_SERVER_ERROR, + OBEX_RSP_INTERNAL_SERVER_ERROR); + else + OBEX_ObjectSetRsp (object, OBEX_RSP_CONTINUE, OBEX_RSP_SUCCESS); + break; + case OBEX_CMD_CONNECT: + OBEX_ObjectSetRsp (object, OBEX_RSP_SUCCESS, OBEX_RSP_SUCCESS); + break; + case OBEX_CMD_DISCONNECT: + OBEX_ObjectSetRsp (object, OBEX_RSP_SUCCESS, OBEX_RSP_SUCCESS); + break; + default: + printf("Denied %02x request\n", cmd); + fflush(stdout); + OBEX_ObjectSetRsp (object, OBEX_RSP_NOT_IMPLEMENTED, + OBEX_RSP_NOT_IMPLEMENTED); + break; + } +} + + +/** + * Function handles OBEX event when a client is connected to the server + * @param handle OBEX connection handle + * @param object OBEX object itself + * @param mode + * @param event event code + * @param obex_cmd OBEX command itself + * @param obex_rsp OBEX responce + */ +static void obex_conn_event (obex_t *handle, obex_object_t *object, + int mode, int event, int obex_cmd, int obex_rsp) +{ + (void)mode; + (void)obex_rsp; + + switch(event) { + case OBEX_EV_REQHINT: + switch(obex_cmd) { + case OBEX_CMD_PUT: + case OBEX_CMD_CONNECT: + case OBEX_CMD_DISCONNECT: + OBEX_ObjectSetRsp (object, OBEX_RSP_CONTINUE, OBEX_RSP_SUCCESS); + break; + default: + OBEX_ObjectSetRsp (object, OBEX_RSP_NOT_IMPLEMENTED, + OBEX_RSP_NOT_IMPLEMENTED); + break; + } + break; + + case OBEX_EV_REQ: + /* Comes when a server-request has been received. */ + handle_request (handle, object, event, obex_cmd); + break; + + case OBEX_EV_LINKERR: + break; + } +} + +/** + * Function handles OBEX event + * @param handle OBEX connection handle + * @param object OBEX object itself + * @param mode + * @param event event code + * @param obex_cmd OBEX command itself + * @param obex_rsp OBEX responce + */ +static void obex_event (obex_t* handle, obex_object_t* object, int mode, + int event, int obex_cmd, int obex_rsp) +{ + + obex_t *obex; //OBEX connection handle + + switch (event) { + case OBEX_EV_ACCEPTHINT: + obex = OBEX_ServerAccept (handle, obex_conn_event, NULL); + break; + + default: + obex_conn_event(handle, object, mode, event, obex_cmd, obex_rsp); + } +} + +/** + * Function registers OBEX push service on a specified channel + * Based on The same function from GPE. + * @param session SDP session + * @param chan channel to listen + * @name name to show + */ +sdp_session_t* ObexServer::addOpushSvc(uint8_t chan, const char* name) +{ + sdp_list_t *svclass_id, *pfseq, *apseq, *root; + uuid_t root_uuid, opush_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid; + sdp_profile_desc_t profile[1]; + sdp_list_t *aproto, *proto[3]; + sdp_record_t record; + sdp_data_t *channel; + uint8_t formats[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06 }; + //uint8_t formats[] = { 0xff }; + void *dtds[sizeof(formats)], *values[sizeof(formats)]; + unsigned int i; + uint8_t dtd = SDP_UINT8; + sdp_data_t *sflist; + int err = 0; + sdp_session_t* lsession = 0; + + memset((void *)&record, 0, sizeof(sdp_record_t)); + record.handle = 0xffffffff; + sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP); + root = sdp_list_append(0, &root_uuid); + sdp_set_browse_groups(&record, root); + + sdp_uuid16_create(&opush_uuid, OBEX_OBJPUSH_SVCLASS_ID); + svclass_id = sdp_list_append(0, &opush_uuid); + sdp_set_service_classes(&record, svclass_id); + + sdp_uuid16_create(&profile[0].uuid, OBEX_OBJPUSH_PROFILE_ID); + profile[0].version = 0x0100; + pfseq = sdp_list_append(0, profile); + sdp_set_profile_descs(&record, pfseq); + + sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID); + proto[0] = sdp_list_append(0, &l2cap_uuid); + apseq = sdp_list_append(0, proto[0]); + + sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID); + proto[1] = sdp_list_append(0, &rfcomm_uuid); + channel = sdp_data_alloc(SDP_UINT8, &chan); + proto[1] = sdp_list_append(proto[1], channel); + apseq = sdp_list_append(apseq, proto[1]); + + sdp_uuid16_create(&obex_uuid, OBEX_UUID); + proto[2] = sdp_list_append(0, &obex_uuid); + apseq = sdp_list_append(apseq, proto[2]); + + aproto = sdp_list_append(0, apseq); + sdp_set_access_protos(&record, aproto); + + for (i = 0; i < sizeof(formats); i++) + { + dtds[i] = &dtd; + values[i] = &formats[i]; + } + sflist = sdp_seq_alloc(dtds, values, sizeof(formats)); + sdp_attr_add(&record, SDP_ATTR_SUPPORTED_FORMATS_LIST, sflist); + + sdp_set_info_attr(&record, name, 0, 0); + + // connect to the local SDP server, register the service record, and + // disconnect + lsession = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY); + if (lsession == NULL) + goto errout; + err = sdp_record_register(lsession, &record, 0); + if (err) { + sdp_close(lsession); + lsession = NULL; + } +errout: + sdp_data_free(channel); + sdp_list_free(proto[0], 0); + sdp_list_free(proto[1], 0); + sdp_list_free(proto[2], 0); + sdp_list_free(apseq, 0); + sdp_list_free(aproto, 0); + + return lsession; +} + +int ObexServer::initObex(void) +{ + int channel = 10; //Channel on which we do listen + if (m_obex) + return 0; + m_obex = ::OBEX_Init(OBEX_TRANS_BLUETOOTH, obex_event, 0); + if (!m_obex) { + printf("OBEX initialization error %d\n", errno); + return -1; + } + ::BtOBEX_ServerRegister(m_obex, NULL, channel); + m_session = addOpushSvc(channel, "OBEX push service"); + if (!m_session) { + printf("OBEX registration error %d\n", errno); + ::OBEX_Cleanup(m_obex); + m_obex = NULL; + return -1; + } + return 0; +} + +bool ObexServer::start(RunMode runmode, Communication comm) +{ + if ( runs ) + { + return false; // cannot start a process that is already running + // or if no executable has been assigned + } + run_mode = runmode; + status = 0; + + if ( !setupCommunication( comm ) ) + qWarning( "Could not setup Communication!" ); + + // We do this in the parent because if we do it in the child process + // gdb gets confused when the application runs from gdb. + uid_t uid = getuid(); + gid_t gid = getgid(); +#ifdef HAVE_INITGROUPS + + struct passwd *pw = getpwuid( uid ); +#endif + + int fd[ 2 ]; + if ( 0 > pipe( fd ) ) + { + fd[ 0 ] = fd[ 1 ] = 0; // Pipe failed.. continue + } + + runs = true; + + QApplication::flushX(); + + // WABA: Note that we use fork() and not vfork() because + // vfork() has unclear semantics and is not standardized. + pid_ = fork(); + + if ( 0 == pid_ ) + { + if ( fd[ 0 ] ) + close( fd[ 0 ] ); + if ( !runPrivileged() ) + { + setgid( gid ); +#if defined( HAVE_INITGROUPS) + + if ( pw ) + initgroups( pw->pw_name, pw->pw_gid ); +#endif + + setuid( uid ); + } + // The child process + if ( !commSetupDoneC() ) + qWarning( "Could not finish comm setup in child!" ); + + setupEnvironment(); + + // Matthias + if ( run_mode == DontCare ) + setpgid( 0, 0 ); + // restore default SIGPIPE handler (Harri) + struct sigaction act; + sigemptyset( &( act.sa_mask ) ); + sigaddset( &( act.sa_mask ), SIGPIPE ); + act.sa_handler = SIG_DFL; + act.sa_flags = 0; + sigaction( SIGPIPE, &act, 0L ); + + // We set the close on exec flag. + // Closing of fd[1] indicates that the execvp succeeded! + if ( fd[ 1 ] ) + fcntl( fd[ 1 ], F_SETFD, FD_CLOEXEC ); + + if (initObex() == 0) { + do { + int result; //Connection result + if ( fd[ 1 ] ) { + ::close(fd[1]); + fd[1] = 0; + } + if ((result = OBEX_HandleInput(m_obex, 60)) < 0) { + if (errno != ECONNRESET) { + printf("OBEX_HandleInput error %d\n", errno); + fflush(stdout); + _exit(-1); + } + else + _exit(0); + } + } while(1); + } + char resultByte = 1; + if ( fd[ 1 ] ) + write( fd[ 1 ], &resultByte, 1 ); + _exit( -1 ); + } + else if ( -1 == pid_ ) + { + // forking failed + + runs = false; + return false; + } + else + { + if ( fd[ 1 ] ) + close( fd[ 1 ] ); + // the parent continues here + + // Discard any data for stdin that might still be there + input_data = 0; + + // Check whether client could be started. + if ( fd[ 0 ] ) + for ( ;; ) + { + char resultByte; + int n = ::read( fd[ 0 ], &resultByte, 1 ); + if ( n == 1 ) + { + // Error + runs = false; + close( fd[ 0 ] ); + pid_ = 0; + return false; + } + if ( n == -1 ) + { + if ( ( errno == ECHILD ) || ( errno == EINTR ) ) + continue; // Ignore + } + break; // success + } + if ( fd[ 0 ] ) + close( fd[ 0 ] ); + + if ( !commSetupDoneP() ) // finish communication socket setup for the parent + qWarning( "Could not finish comm setup in parent!" ); + + if ( run_mode == Block ) + { + commClose(); + + // The SIGCHLD handler of the process controller will catch + // the exit and set the status + while ( runs ) + { + OProcessController::theOProcessController-> + slotDoHousekeeping( 0 ); + } + runs = FALSE; + emit processExited( this ); + } + } + return true; +} + +/* + * Stop forwarding process + */ +int ObexServer::stop() +{ + kill(SIGTERM); + return 0; +} + +//eof diff --git a/core/obex/obexserver.h b/core/obex/obexserver.h new file mode 100644 index 0000000..8567105 --- a/dev/null +++ b/core/obex/obexserver.h @@ -0,0 +1,83 @@ +/* + =. This file is part of the OPIE Project + .=l. Copyright (c) 2002 Maximilian Reiss <max.reiss@gmx.de> + .>+-= + _;:, .> :=|. This library is free software; you can +.> <, > . <= redistribute it and/or modify it under +:=1 )Y*s>-.-- : the terms of the GNU Library General Public +.="- .-=="i, .._ License as published by the Free Software + - . .-<_> .<> Foundation; version 2 of the License. + ._= =} : + .%+i> _;_. + .i_,=:_. -<s. This library 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 +..}^=.= = ; Library General Public License for more +++= -. . .: details. + : = ...= . :.=- + -. .:....=;==+<; You should have received a copy of the GNU + -_. . . )=. = Library General Public License along with + -- :-= this library; see the file COPYING.LIB. + If not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. + +*/ +/* + * The OBEX server class declaration + * Based on OBEX server from GPE (thanks, guys) + */ +#ifndef ObexServer_H +#define ObexServer_H + +#include <qobject.h> +#include <opie2/oprocess.h> + +#include <bluetooth/sdp.h> +#include <bluetooth/sdp_lib.h> + +#include <openobex/obex.h> + +namespace Opie { + namespace Core { + class OProcess; + namespace Internal { + class OProcessController; + } + } +}; + +namespace Opie {namespace Core {class OProcess;}} +namespace OpieObex { + class ObexServer : public Opie::Core::OProcess { + Q_OBJECT + public: + /** + * ObexServer constructor + */ + ObexServer(); + /** + * + */ + ~ObexServer(); + //Function starts the server process + virtual bool start( RunMode runmode = NotifyOnExit, + Communication comm = NoCommunication ); + //Stop the server process + int stop(); + protected: //variables + obex_t* m_obex; //Obex server handler + sdp_session_t* m_session; //SDP session handler; + protected: //functions + //Funtion initializes obex server return 0 on success and -1 on error + int initObex(void); + //Function registers an OBEX push service + sdp_session_t* addOpushSvc(uint8_t chan, const char* name); + signals: + protected slots: + }; +}; + +#endif diff --git a/core/obex/receiver.cpp b/core/obex/receiver.cpp index 7d9a42a..e153152 100644 --- a/core/obex/receiver.cpp +++ b/core/obex/receiver.cpp @@ -1,198 +1,203 @@ #include "obex.h" +#include "btobex.h" +#include "obexbase.h" #include "receiver.h" using namespace OpieObex; /* OPIE */ #include <opie2/odebug.h> #include <qpe/applnk.h> #include <qpe/qpeapplication.h> #include <qpe/qcopenvelope_qws.h> #include <qpe/filemanager.h> using namespace Opie::Core; /* QT */ #include <qfileinfo.h> #include <qlabel.h> #include <qtextview.h> #include <qpushbutton.h> /* STD */ #include <sys/types.h> #include <sys/stat.h> #include <sys/mman.h> #include <stdlib.h> // int system #include <unistd.h> #include <fcntl.h> /* TRANSLATOR OpieObex::Receiver */ -Receiver::Receiver() { - m_obex = new Obex(this, "Receiver"); +Receiver::Receiver(RecType type) { + if (type == REC_IRDA) + m_obex = new Obex(this, "Receiver"); + else + m_obex = new BtObex(this, "Receiver"); connect(m_obex, SIGNAL(receivedFile(const QString&) ), this, SLOT(slotReceived(const QString&) ) ); m_obex->receive(); } Receiver::~Receiver() { m_obex->setReceiveEnabled( false ); delete m_obex; } void Receiver::slotReceived( const QString& _file ) { QString file = _file; int check = checkFile(file); if ( check == AddressBook ) handleAddr( file ); else if ( check == Datebook ) handleDateTodo( file ); else handleOther( file ); } void Receiver::handleAddr( const QString& str ) { QCopEnvelope e("QPE/Application/addressbook", "setDocument(QString)" ); e << str; } /* we can not say for sure if it's a VEevent ot VTodo */ void Receiver::handleDateTodo( const QString& str ) { QCopEnvelope e0("QPE/Application/todolist", "setDocument(QString)"); e0 << str; QCopEnvelope e1("QPE/Application/datebook", "setDocument(QString)" ); e1 << str; } /* * Handle other asks if it should accept the * beamed object and creates a DocLnk */ void Receiver::handleOther( const QString& other ) { OtherHandler* hand = new OtherHandler(); hand->handle( other ); } void Receiver::tidyUp( QString& _file, const QString& ending) { /* libversit fails on BASE64 encoding we try to sed it away */ QString file = _file; char foo[24]; // big enough (void)::strcpy(foo, "/tmp/opie-XXXXXX"); int fd = ::mkstemp(foo); if ( fd == -1 ) return; (void)::strncat( foo, QFile::encodeName(ending), 4 ); _file = QString::fromLocal8Bit( foo ); QString cmd = QString("sed -e \"s/^\\(X-MICROSOFT-BODYINK\\)\\;/\\1:/;\" < %2 > %2 ").arg( Global::shellQuote(file)).arg( Global::shellQuote(_file) ); (void)::system( QFile::encodeName(cmd) ); cmd = QString("rm %1").arg( Global::shellQuote(file) ); (void)::system( QFile::encodeName(cmd) ); } int Receiver::checkFile( QString& file ) { int ret; QString ending; if (file.right(4) == ".vcs" ) { ret = Datebook; ending = QString::fromLatin1(".vcs"); }else if ( file.right(4) == ".vcf") { ret = AddressBook; ending = QString::fromLatin1(".vcf"); }else ret = Other; if (ending.isEmpty() ) return ret; /** * currently the parser is broken in regard of BASE64 encoding * and M$ likes to send that. So we will executed a small * tidy up system sed script * At this point we can also remove umlaute from the filename */ tidyUp( file, ending ); return ret; } /* TRANSLATOR OpieObex::OtherHandler */ OtherHandler::OtherHandler() : QVBox() { QHBox* box = new QHBox(this); QLabel* lbl = new QLabel(box); lbl->setText(tr("<qt><b>Received:</b></qt>")); m_na = new QLabel(box); QFrame* frame = new QFrame(this); frame->setFrameShape( QFrame::HLine ); frame->setFrameShadow( QFrame::Sunken ); m_view = new QTextView(this); box = new QHBox(this); QPushButton *but = new QPushButton(box); but->setText(tr("Accept") ); connect(but, SIGNAL(clicked() ), this, SLOT(accept()) ); but = new QPushButton(box); but->setText(tr("Deny") ); connect(but, SIGNAL(clicked() ), this, SLOT(deny() ) ); raise(); showMaximized(); } OtherHandler::~OtherHandler() { } void OtherHandler::handle( const QString& file ) { m_file = file; m_na->setText(file); DocLnk lnk(file); QString str = tr("<p>You received a file of type %1 (<img src=\"%2\"> )What do you want to do?").arg(lnk.type() ).arg(lnk.icon() ); m_view->setText( str ); } /* * hehe evil evil mmap ahead :) * we quickly copy the file and then we'll create a DocLnk for it */ void OtherHandler::accept() { QString na = targetName( m_file ); copy(m_file, na ); DocLnk lnk(na); lnk.writeLink(); QFile::remove(m_file); delete this; } void OtherHandler::deny() { QFile::remove( m_file ); delete this; } QString OtherHandler::targetName( const QString& file ) { QFileInfo info( file ); /* $HOME needs to be set!!!! */ Global::createDocDir(); QString newFile = QPEApplication::documentDir()+ "/"+ info.baseName(); QString newFileBase = newFile; int trie = 0; while (QFile::exists(newFile + "."+info.extension() ) ) { newFile = newFileBase + "_"+QString::number(trie) ; trie++; } newFile += "." + info.extension(); return newFile; } /* fast cpy */ void OtherHandler::copy(const QString& src, const QString& file) { FileManager *fm; if(!fm->copyFile(src,file)) { owarn << "Copy failed" << oendl; } } diff --git a/core/obex/receiver.h b/core/obex/receiver.h index e1d54df..a10ea13 100644 --- a/core/obex/receiver.h +++ b/core/obex/receiver.h @@ -1,58 +1,64 @@ #ifndef OPIE_OBEX_RECEIVER_H #define OPIE_OBEX_RECEIVER_H #include <qobject.h> #include <qvbox.h> #include <qstring.h> +//Receiver type +typedef enum _RecType { + REC_IRDA = 0, + REC_BLUETOOTH = 1 +} RecType; + class QLabel; class QTextView; namespace OpieObex { - class Obex; + class ObexBase; class OtherHandler; class Receiver : public QObject { Q_OBJECT public: enum { Datebook , AddressBook, Other }; - Receiver(); + Receiver(RecType type); ~Receiver(); private: void handleAddr(const QString& ); void handleDateTodo(const QString& ); void handleOther(const QString& ); /* will alter the file name */ int checkFile( QString& file ); bool testDateTodo(const QString& file); bool testAddressbook(const QString& file); /* called by checkFile */ void tidyUp( QString& file, const QString& ending ); private slots: void slotReceived( const QString& ); private: - Obex* m_obex; + ObexBase* m_obex; //IR obex }; class OtherHandler : public QVBox { Q_OBJECT public: OtherHandler(); ~OtherHandler(); void handle( const QString& file ); private slots: void accept(); void deny(); private: QString targetName( const QString& file ); void copy( const QString& src, const QString& dest ); QLabel* m_na; QTextView* m_view; QString m_file; }; } #endif |