📄 qirserver.cpp
字号:
/************************************************************************ Copyright (C) 2000-2005 Trolltech AS and its licensors.** All rights reserved.**** This file is part of the Qtopia Environment.**** This file may be distributed and/or modified under the terms of the** GNU General Public License version 2 as published by the Free Software** Foundation and appearing in the file LICENSE.GPL included in the** packaging of this file.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.**** See http://www.trolltech.com/gpl/ for GPL licensing information.** See below for additional copyright and license information**** Contact info@trolltech.com if any conditions of this licensing are** not clear to you.************************************************************************/#include "qirserver.h"#include <qtopia/mimetype.h>#include <qtopia/qcopenvelope_qws.h>#include <qtopia/private/task.h>#include <qsocketnotifier.h>#include <qfile.h>#include <qtimer.h>#include <sys/stat.h>#include <sys/types.h>#include <fcntl.h>#include <unistd.h>#include <stdlib.h>#define QTOPIA_DEBUG_OBEXextern "C" { #include "openobex/obex.h"}class QObexBase :public QObject{ Q_OBJECT;public: QObexBase( QObject *parent = 0, const char *name = 0 ); ~QObexBase();signals: void error(); void statusMsg(const QString &); void aboutToDelete();public slots: void abort();protected slots: void deleteMeLater(); void processInput(); protected: virtual void doPending() = 0; void connectSocket(); obex_t *self; bool finished; bool aborted;private slots: void deleteThis();};QObexBase::QObexBase( QObject *parent , const char *name ) :QObject( parent, name ){ finished = FALSE; aborted = FALSE;}QObexBase::~QObexBase(){ OBEX_Cleanup( self );}void QObexBase::connectSocket(){ QSocketNotifier *sn = new QSocketNotifier( OBEX_GetFD( self ), QSocketNotifier::Read, this ); connect( sn, SIGNAL(activated(int)), this, SLOT(processInput()) );}void QObexBase::deleteMeLater(){ QTimer::singleShot( 0, this, SLOT(deleteThis()) );}void QObexBase::deleteThis(){ emit aboutToDelete(); delete this;}void QObexBase::abort(){ aborted = TRUE; finished = TRUE;}void QObexBase::processInput(){ if ( !aborted ) OBEX_HandleInput( self, 0 ); if ( aborted ) deleteMeLater(); if ( finished ) doPending();}static void qobex_sender_callback(obex_t *handle, obex_object_t *obj, int mode, int event, int obex_cmd, int obex_rsp);class QObexSender : public QObexBase{ Q_OBJECT;public: QObexSender( QObject *parent = 0, const char *name = 0 ); ~QObexSender(); void beam( const QString& filename, const QString& mimetype );signals: void done(); void progress(int);private slots: void tryConnecting(); private: friend void qobex_sender_callback(obex_t *handle, obex_object_t *obj, int mode, int event, int obex_cmd, int obex_rsp); enum State { Init, Connecting, Streaming, Disconnecting, Error }; void process( obex_object_t *object ) { if( object && OBEX_Request(self, object) < 0) { /* Error */ qWarning( "could not request" ); state = Error; finished = TRUE; } else { finished = FALSE; } } void feedStream( obex_object_t *); void updateProgress( obex_object_t *); void doPending(); void putFile( const QString&, const QString& ); QString file_to_send; QString mime_to_send; QFile *file_being_sent; State state; int connectCount;};class QObexReceiver;static void qobex_server_callback(obex_t *handle, obex_object_t *object, int mode, int event, int obex_cmd, int obex_rsp);class QObexServer : public QObexBase{ friend void qobex_server_callback(obex_t *handle, obex_object_t *object, int mode, int event, int obex_cmd, int obex_rs); Q_OBJECT;public: QObexServer( QObject *parent = 0, const char *name = 0 ); ~QObexServer();protected: void doPending();private slots: void slotReceiving(bool); void sessionEnded(); void finishedReceive();signals: void receiving(bool);private: QTimer *m_timer; QObexReceiver *m_receiver; bool m_receiving; void spawnReceiver( obex_t *handle ); enum State { Init, Connecting, Receiving, Disconnecting, Finished, Error, Aborted }; State state;};static void qobex_receiver_callback(obex_t *handle, obex_object_t *object, int mode, int event, int obex_cmd, int obex_rsp);class QObexReceiver : public QObexBase{ Q_OBJECT;public: QObexReceiver( obex_t *handle, QObject *parent = 0, const char *name = 0 ); ~QObexReceiver(); //a link error finish is a successful finish of a beamed file //but terminates with a LINKERR message. some phones do this //and create an obex session for each file they want to send //sending a link error after each bool linkErrFinish() const { return m_linkErrFinish; }protected: void doPending();signals: void receiving(bool); void receiving( int size, const QString & name, const QString & mime ); void progress( int size ); void fileComplete(); //void received( const QString & name, const QString & mime ); //there is no easy way to emit this signal inbetween sends without //screwing devices like the S45 which are tempremental over timing //don't need it anywayprivate: friend void qobex_receiver_callback(obex_t *handle, obex_object_t *object, int mode, int event, int obex_cmd, int obex_rsp); enum State { Init, Connecting, Receiving, Disconnecting, Finished, Error, Aborted }; void readData( obex_object_t *); void updateProgress( obex_object_t *); void getHeaders( obex_object_t *object ); State state; QString filename; QString mimetype; int reclen; bool m_linkErrFinish; QFile outfile;};/* QObexSender functions */void QObexSender::feedStream( obex_object_t *object ){ static char buf[4096]; ASSERT( state == Streaming && file_being_sent ); obex_headerdata_t hd; int len = file_being_sent->readBlock( buf, 4096 ); if ( len > 0 ) { hd.bs = (uchar*)buf; OBEX_ObjectAddHeader(self, object, OBEX_HDR_BODY, hd, len, OBEX_FL_STREAM_DATA); } else { /* EOF */ hd.bs = 0; OBEX_ObjectAddHeader(self, object, OBEX_HDR_BODY, hd, 0, OBEX_FL_STREAM_DATAEND); file_being_sent->close(); delete file_being_sent; file_being_sent = 0; } }void QObexSender::updateProgress( obex_object_t * /* obj */){ emit progress( file_being_sent->at() );}static bool hasTasks( const QString &filename ){ QValueList<Task> tasks = Task::readVCalendar( filename ); return tasks.count();}void QObexSender::putFile( const QString &filename, const QString& mimetype ){ obex_headerdata_t hd; obex_object_t *object = OBEX_ObjectNew(self, OBEX_CMD_PUT); if (object == NULL) { /* Error */ qWarning( "null object" ); state = Error; finished = TRUE; return; } file_being_sent = new QFile( filename ); if ( file_being_sent->open(IO_ReadOnly) ) { int body_size = file_being_sent->size(); /* Add length header */ hd.bq4 = body_size; OBEX_ObjectAddHeader(self, object, OBEX_HDR_LENGTH, hd, 4, 0); /* Add type header */ hd.bs = (uchar*)mimetype.latin1(); OBEX_ObjectAddHeader(self, object, OBEX_HDR_TYPE, hd, mimetype.length()+1, 0); /* Add PalmOS-style application id header */ // ####### if more PalmOS applications have this problem, // ####### a more general solution is required. if ( mimetype == "text/x-vCalendar" ) { if ( hasTasks( filename ) ) hd.bq4 = 0x746F646F; // "todo" else hd.bq4 = 0x64617465; // "date" OBEX_ObjectAddHeader(self, object, 0xcf, hd, 4, 0); } /* Add unicode name header*/ QString uc = filename + QChar( 0x0 ); uc = uc.mid( uc.findRev("/")+1 ); int name_size = uc.length() * 2; hd.bs = (uchar*) uc.unicode(); OBEX_ObjectAddHeader(self, object, OBEX_HDR_NAME, hd, name_size, 0); state = Streaming; hd.bs = 0; OBEX_ObjectAddHeader(self, object, OBEX_HDR_BODY, hd, 0, OBEX_FL_STREAM_START); process( object ); }}static bool transmitDone = FALSE;void QObexSender::doPending(){#ifdef QTOPIA_DEBUG_OBEX qDebug( "QObexSender::doPending %d", state );#endif if ( state == Connecting ) {#ifdef QTOPIA_DEBUG_OBEX qDebug( "state Connecting" );#endif // finished connecting; time to send putFile( file_to_send, mime_to_send ); file_to_send = QString::null; } else if ( state == Streaming ) {#ifdef QTOPIA_DEBUG_OBEX qDebug( "state Streaming" );#endif //finished streaming obex_object_t *object = OBEX_ObjectNew(self, OBEX_CMD_DISCONNECT); process( object ); state = Disconnecting; } else if ( state == Disconnecting ) {#ifdef QTOPIA_DEBUG_OBEX qDebug( "state Disconnecting" );#endif OBEX_TransportDisconnect(self); state = Init; emit done(); deleteMeLater(); }}static void qobex_sender_callback(obex_t *handle, obex_object_t *obj, int mode, int event, int obex_cmd, int obex_rsp){ QObexSender *sender = (QObexSender*)OBEX_GetUserData( handle );#ifdef QTOPIA_DEBUG_OBEX qDebug( "qobex_sender_callback %p, %p, %p, %d, event %x, cmd %x, rsp %x", sender, handle, obj, mode, event, obex_cmd, obex_rsp );#else Q_UNUSED(mode); Q_UNUSED(obex_rsp);#endif switch (event) { case OBEX_EV_REQDONE:#ifdef QTOPIA_DEBUG_OBEX qDebug("OBEX_EV_REQDONE");#endif sender->finished = TRUE; if ( obex_cmd == OBEX_CMD_DISCONNECT ) { transmitDone = TRUE; } // else if OBEX_CMD_CONNECT, we could give feedback break; case OBEX_EV_LINKERR:#ifdef QTOPIA_DEBUG_OBEX qDebug("OBEX_EV_LINKRER");#endif // sometime we get a link error after we believed the connection was done. Ignore this // as emitting an error after done does not make sense if ( !transmitDone ) { emit sender->error(); sender->abort(); sender->state = QObexSender::Error; } else { sender->abort();#ifdef QTOPIA_DEBUG_OBEX qDebug("QIrServer:: got link error after done signal, no external signals sent");#endif } break; case OBEX_EV_PROGRESS:#ifdef QTOPIA_DEBUG_OBEX qDebug("OBEX_EV_PROGRESS");#endif // report progress? sender->updateProgress( obj ); break; case OBEX_EV_STREAMEMPTY:#ifdef QTOPIA_DEBUG_OBEX qDebug("OBEX_EV_STREAMEMPTY");#endif // when streaming: add more sender->feedStream( obj ); break; default:#ifdef QTOPIA_DEBUG_OBEX qDebug("qobex_sender_callback:: did not recongnize event signal %d", event);#endif break; }}QObexSender::QObexSender( QObject *parent, const char *name ) :QObexBase( parent, name ){ self = OBEX_Init( OBEX_TRANS_IRDA, qobex_sender_callback, OBEX_FL_KEEPSERVER ); finished = FALSE; state = QObexSender::Init; OBEX_SetUserData( self, this );}QObexSender::~QObexSender(){}void QObexSender::beam( const QString& filename, const QString& mimetype ){ file_to_send = filename; mime_to_send = mimetype; transmitDone = FALSE; connectCount = 0; tryConnecting();}void QObexSender::tryConnecting(){ connectCount++; if ( aborted ) { deleteMeLater(); return; } int retc = IrOBEX_TransportConnect(self, "OBEX"); if ( retc < 0 ) { const int normalTry = 5; const int maxTry = 20; if ( connectCount > maxTry ) { abort(); emit error(); deleteMeLater(); } else { QString str; if ( connectCount <= normalTry ) str = tr("Searching..."); else str = tr("Beam failed (%1/%2). Retrying...","eg. 1/3").arg(connectCount).arg(maxTry); emit statusMsg( str ); // Semi-random retry time to avoid re-collision QTimer::singleShot(200 + rand()%400, this, SLOT(tryConnecting()) ); } return; }#ifdef QTOPIA_DEBUG_OBEX qDebug("QObexSender::tryConnecting() - Success");#endif QString str = tr("Sending..."); emit statusMsg( str ); connectSocket(); obex_object_t *object; // connecting object = OBEX_ObjectNew(self, OBEX_CMD_CONNECT); state = QObexSender::Connecting; process( object );}//-----------------------------------------------------------------------/* QObexServer / functions*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -