-rw-r--r-- | noncore/net/opieirc/dccprogress.cpp | 75 | ||||
-rw-r--r-- | noncore/net/opieirc/dccprogress.h | 35 | ||||
-rw-r--r-- | noncore/net/opieirc/dcctransfer.cpp | 41 | ||||
-rw-r--r-- | noncore/net/opieirc/dcctransfer.h | 44 | ||||
-rw-r--r-- | noncore/net/opieirc/dcctransferrecv.cpp | 53 | ||||
-rw-r--r-- | noncore/net/opieirc/dcctransferrecv.h | 21 | ||||
-rw-r--r-- | noncore/net/opieirc/dcctransfertab.cpp | 81 | ||||
-rw-r--r-- | noncore/net/opieirc/dcctransfertab.h | 41 | ||||
-rw-r--r-- | noncore/net/opieirc/ircmessageparser.cpp | 30 | ||||
-rw-r--r-- | noncore/net/opieirc/ircservertab.cpp | 4 | ||||
-rw-r--r-- | noncore/net/opieirc/ircservertab.h | 1 | ||||
-rw-r--r-- | noncore/net/opieirc/ircsession.cpp | 5 | ||||
-rw-r--r-- | noncore/net/opieirc/ircsession.h | 4 | ||||
-rw-r--r-- | noncore/net/opieirc/mainwindow.cpp | 20 | ||||
-rw-r--r-- | noncore/net/opieirc/mainwindow.h | 8 | ||||
-rw-r--r-- | noncore/net/opieirc/opieirc.pro | 9 |
16 files changed, 459 insertions, 13 deletions
diff --git a/noncore/net/opieirc/dccprogress.cpp b/noncore/net/opieirc/dccprogress.cpp new file mode 100644 index 0000000..28277f7 --- a/dev/null +++ b/noncore/net/opieirc/dccprogress.cpp @@ -0,0 +1,75 @@ +#include <qprogressbar.h> +#include <qlabel.h> +#include <qvbox.h> + +#include "dcctransfer.h" +#include "dcctransferrecv.h" +#include "dccprogress.h" + +DCCProgress::DCCProgress(DCCTransfer::Type type, Q_UINT32 ip4Addr, Q_UINT16 port, + const QString &filename, const QString &nickname, unsigned int size, QWidget *parent, char *name, WFlags f) + : QWidget(parent, name, f), m_vbox(new QVBox(this)), + m_label(new QLabel(m_vbox)), + m_bar(new QProgressBar(m_vbox)) +{ + + if (DCCTransfer::Recv == type) + m_transfer = new DCCTransferRecv(ip4Addr, port, filename, size); + + + connect(m_transfer, SIGNAL(progress(int)), this, SLOT(slotSetProgress(int))); + connect(m_transfer, SIGNAL(finished(DCCTransfer *, DCCTransfer::EndCode)), + this, SLOT(slotFinished(DCCTransfer *, DCCTransfer::EndCode))); + + m_label->setText(tr("Receiving file %1 from %2...").arg(m_transfer->filename()).arg(nickname)); + + m_label->show(); + m_bar->show(); + show(); + +} + +bool DCCProgress::finished() +{ + return ( m_transfer == 0); +} + +void DCCProgress::cancel() +{ + if (m_transfer) + m_transfer->cancel(); +} + +void DCCProgress::slotSetProgress(int progress) +{ + m_bar->setProgress(progress); +} + +void DCCProgress::slotFinished(DCCTransfer *transfer, DCCTransfer::EndCode code) +{ + if(transfer != m_transfer) + // WTF!! + return; + + QString msg; + + switch(code) { + case DCCTransfer::Successfull: + msg = tr("Successfully received %1").arg(m_transfer->filename()); + break; + case DCCTransfer::SelfAborted: + msg = tr("Aborted"); + break; + case DCCTransfer::PeerAborted: + msg = tr("Peer Aborted"); + break; + case DCCTransfer::Timeout: + msg = tr("Timeout"); + break; + } + + m_label->setText(msg); + delete m_transfer; + m_transfer = 0; +} + diff --git a/noncore/net/opieirc/dccprogress.h b/noncore/net/opieirc/dccprogress.h new file mode 100644 index 0000000..81b922e --- a/dev/null +++ b/noncore/net/opieirc/dccprogress.h @@ -0,0 +1,35 @@ +#ifndef DCCPROGRESS_H +#define DCCPROGRESS_H + + +#include <qwidget.h> + +#include "dcctransfer.h" + +class QProgressBar; +class QLabel; +class QVBox; + +class DCCProgress: public QWidget { + + Q_OBJECT +public: + DCCProgress(DCCTransfer::Type type, Q_UINT32 ip4Addr, Q_UINT16 port, + const QString &filename, const QString &nickname, unsigned int size, + QWidget *parent = 0, char *name = 0, WFlags f = 0); + + bool finished(); + void cancel(); + +public slots: + void slotSetProgress(int progress); + void slotFinished(DCCTransfer *transfer, DCCTransfer::EndCode code); + +private: + QVBox *m_vbox; + QLabel *m_label; + QProgressBar *m_bar; + DCCTransfer *m_transfer; +}; + +#endif diff --git a/noncore/net/opieirc/dcctransfer.cpp b/noncore/net/opieirc/dcctransfer.cpp new file mode 100644 index 0000000..cfa9f74 --- a/dev/null +++ b/noncore/net/opieirc/dcctransfer.cpp @@ -0,0 +1,41 @@ +#include <qsocket.h> +#include <qfile.h> + +#include "dcctransfer.h" + + +DCCTransfer::DCCTransfer(Q_UINT32 ip4Addr, Q_UINT16 port, const QString &filename, unsigned int size) + : m_socket(new QSocket), m_file(new QFile), m_bufSize(4096), m_buffer(new char[m_bufSize]), + m_ip4Addr(ip4Addr), m_port(port), m_totalSize(size), m_processedSize(0) +{ + m_file->setName(filename); +} + +DCCTransfer::~DCCTransfer() +{ + if(m_socket) + delete m_socket; + if(m_file) { + m_file->close(); + delete m_file; + } + if(m_buffer) + delete []m_buffer; +} + + +void DCCTransfer::cancel() +{ + if(m_socket) + m_socket->close(); + + emit(finished(DCCTransfer::SelfAborted)); +} + +QString DCCTransfer::filename() +{ + if(!m_file) + return QString::null; + + return m_file->name().mid(m_file->name().findRev('/') + 1); +} diff --git a/noncore/net/opieirc/dcctransfer.h b/noncore/net/opieirc/dcctransfer.h new file mode 100644 index 0000000..775ed24 --- a/dev/null +++ b/noncore/net/opieirc/dcctransfer.h @@ -0,0 +1,44 @@ +#ifndef DCCTRANSFER_H +#define DCCTRANSFER_H + +#include <qobject.h> + +class QSocket; +class QFile; +class QString; + +class DCCTransfer: public QObject { + Q_OBJECT +public: + enum Type { Send, Recv }; + enum EndCode { Successfull, SelfAborted, PeerAborted, Timeout }; + + DCCTransfer(Q_UINT32 ip4Addr, Q_UINT16 port, const QString &filename, unsigned int size); + virtual ~DCCTransfer(); + + void cancel(); + + QString filename(); + +signals: + virtual void finished(DCCTransfer *transfer, EndCode code); + virtual void progress(int progress); + +protected slots: + virtual void slotProcess() = 0; + virtual void slotFinished() = 0; + +protected: + QSocket *m_socket; + QFile *m_file; + unsigned int m_bufSize; + char *m_buffer; + Q_UINT32 m_ip4Addr; + Q_UINT16 m_port; + unsigned int m_totalSize; + unsigned int m_processedSize; + bool m_cancel; + bool m_timeout; +}; + +#endif diff --git a/noncore/net/opieirc/dcctransferrecv.cpp b/noncore/net/opieirc/dcctransferrecv.cpp new file mode 100644 index 0000000..58e8d09 --- a/dev/null +++ b/noncore/net/opieirc/dcctransferrecv.cpp @@ -0,0 +1,53 @@ +#include <netinet/in.h> + +#include <qfile.h> +#include <qsocket.h> +#include <qhostaddress.h> + +#include <opie2/odebug.h> + + +#include "dcctransferrecv.h" + + +DCCTransferRecv::DCCTransferRecv(Q_UINT32 ip4Addr, Q_UINT16 port, const QString &filename, unsigned int size) + : DCCTransfer(ip4Addr, port, filename, size) +{ + QHostAddress ip(ip4Addr); + m_socket->connectToHost(ip.toString(), m_port); + connect(m_socket, SIGNAL(readyRead()), this, SLOT(slotProcess())); + connect(m_socket, SIGNAL(connectionClosed()), this, SLOT(slotFinished())); + + m_file->open(IO_WriteOnly); +} + + +void DCCTransferRecv::slotProcess() +{ + int availableBytes = m_socket->bytesAvailable(); + int receivedBytes = 0; + + while(receivedBytes < availableBytes) { + int bytes = m_socket->readBlock(m_buffer, m_bufSize); + receivedBytes += bytes; + m_file->writeBlock(m_buffer, bytes); + } + + m_file->flush(); + m_processedSize += availableBytes; + unsigned long value = htonl(m_processedSize); + m_socket->writeBlock((char*)&value, sizeof(unsigned long)); + + emit (progress((m_processedSize * 100) / m_totalSize)); +} + +void DCCTransferRecv::slotFinished() +{ + m_file->close(); + + if(m_processedSize == m_totalSize) + emit(finished(this, DCCTransfer::Successfull)); + else + emit(finished(this, DCCTransfer::PeerAborted)); +} + diff --git a/noncore/net/opieirc/dcctransferrecv.h b/noncore/net/opieirc/dcctransferrecv.h new file mode 100644 index 0000000..bfc55ef --- a/dev/null +++ b/noncore/net/opieirc/dcctransferrecv.h @@ -0,0 +1,21 @@ +#ifndef DCCTRANSFERRECV_H +#define DCCTRANSFERRECV_H + +#include "dcctransfer.h" + + +class DCCTransferRecv: public DCCTransfer { + Q_OBJECT +public: + DCCTransferRecv(Q_UINT32 ip4Addr, Q_UINT16 port, const QString &filename, unsigned int size); + +signals: + void finished(DCCTransfer *transfer, DCCTransfer::EndCode code); + +public slots: + void slotProcess(); + void slotFinished(); +}; + +#endif + diff --git a/noncore/net/opieirc/dcctransfertab.cpp b/noncore/net/opieirc/dcctransfertab.cpp new file mode 100644 index 0000000..ea0ff1f --- a/dev/null +++ b/noncore/net/opieirc/dcctransfertab.cpp @@ -0,0 +1,81 @@ +#include <qlist.h> +#include <qlabel.h> +#include <qstring.h> +#include <qvbox.h> +#include <qmessagebox.h> + +#include "dcctransfer.h" +#include "dccprogress.h" +#include "mainwindow.h" +#include "dcctransfertab.h" + +#include <stdio.h> + +DCCTransferTab::DCCTransferTab(QWidget *parent, const char *name, WFlags f) + :IRCTab(parent, name, f), m_hbox(new QHBox(this)), m_parent(static_cast<MainWindow*>(parent)) +{ + m_description->setText(""); + m_layout->add(m_hbox); + m_hbox->show(); +} + +DCCTransferTab::~DCCTransferTab() +{ + if(m_hbox) + delete m_hbox; +} + +QString DCCTransferTab::title() +{ + return "DCC"; +} + +void DCCTransferTab::remove() +{ + //Clean finished transfers + for(QListIterator <DCCProgress> it(m_progressList); it.current(); ++it) { + DCCProgress *current = it.current(); + if (current->finished()) { + m_progressList.remove(current); + current->hide(); + delete current; + } + } + + if (m_progressList.count() > 0) { + int retval = QMessageBox::information( parentWidget() , tr("DCC Transfers in Progress"), + tr( "There are transfers in progress. <br>If you close this tab, they will be canceled." + "<br>Do you want to close it anyway?"), + tr("&Close"), tr("&Don't Close")); + if ( retval != 0 ) { + return; + } + //Cancel active transfers (user accepted) + for(QListIterator <DCCProgress> itr(m_progressList); itr.current(); ++itr) { + DCCProgress *current = itr.current(); + m_progressList.remove(current); + current->hide(); + current->cancel(); + delete current; + } + } + + //Remove + m_parent->killTab(this); +} + +bool DCCTransferTab::confirm(QWidget *parent, const QString &nickname, const QString &filename, unsigned int size) +{ + int retval = QMessageBox::information(parent, tr("DCC Transfer from %1").arg(nickname), + tr( "%1 is trying to send you the file %2\n(%3 bytes)").arg(nickname).arg(filename).arg(size), + tr("&Accept"), tr("&Reject")); + + return ( 0 == retval); + +} + +void DCCTransferTab::addTransfer(DCCTransfer::Type type, Q_UINT32 ip4Addr, Q_UINT16 port, + const QString &filename, const QString &nickname, unsigned int size) +{ + m_progressList.append(new DCCProgress(type, ip4Addr, port, filename, nickname, size, this)); +} diff --git a/noncore/net/opieirc/dcctransfertab.h b/noncore/net/opieirc/dcctransfertab.h new file mode 100644 index 0000000..a21323d --- a/dev/null +++ b/noncore/net/opieirc/dcctransfertab.h @@ -0,0 +1,41 @@ +#ifndef DCCTRANSFERTAB_H +#define DCCTRANSFERTAB_H + +#include "dcctransfer.h" +#include "irctab.h" + +template <class T> class QList; + +class DCCProgress; +class IRCSession; +class QString; +class QHBox; +class MainWindow; + +class DCCTransferTab: public IRCTab { + Q_OBJECT +public: + + DCCTransferTab(QWidget *parent = 0, const char *name = 0, WFlags f = 0); + ~DCCTransferTab(); + virtual QString DCCTransferTab::title(); + virtual IRCSession* DCCTransferTab::session(){return 0;}; + virtual void DCCTransferTab::appendText(QString){}; + virtual void DCCTransferTab::remove(); + virtual void DCCTransferTab::settingsChanged() {}; + void addTransfer(DCCTransfer::Type type, Q_UINT32 ip4Addr, + Q_UINT16 port, const QString &filename, + const QString &nickname, unsigned int size); + static bool confirm(QWidget *parent = 0, + const QString &nickname = QString::null, + const QString &filename = QString::null, + unsigned int size = 0); +private: + QHBox *m_hbox; + QList <DCCProgress> m_progressList; + MainWindow *m_parent; + +}; + +#endif + diff --git a/noncore/net/opieirc/ircmessageparser.cpp b/noncore/net/opieirc/ircmessageparser.cpp index ad9de2b..939cdae 100644 --- a/noncore/net/opieirc/ircmessageparser.cpp +++ b/noncore/net/opieirc/ircmessageparser.cpp @@ -1,11 +1,16 @@ #include <qtextstream.h> #include <qdatetime.h> +#include <opie2/ofiledialog.h> +#include <opie2/ofileselector.h> +#include <opie2/odebug.h> + #include "ircmessageparser.h" #include "ircversion.h" #include "ircchannelperson.h" -//#include "transferreceiver.h" +#include "dcctransfertab.h" +#include "ircservertab.h" /* Lookup table for literal commands */ IRCLiteralMessageParserStruct IRCMessageParser::literalParserProcTable[] = { { "PING", FUNC(parseLiteralPing) }, @@ -460,14 +465,27 @@ void IRCMessageParser::parseCTCPAction(IRCMessage *message) { } void IRCMessageParser::parseCTCPDCC(IRCMessage *message) { QStringList params = QStringList::split(' ', message->param(0).stripWhiteSpace()); - if( params.count() != 5) { - emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Malformed DCC request from ") + IRCPerson(message->prefix()).nick())); - return; + + if(params[0] == "SEND") { + QString nickname = IRCPerson(message->prefix()).nick(); + if( params.count() != 5) { + emit outputReady(IRCOutput(OUTPUT_ERROR, tr("Malformed DCC request from %1").arg(nickname))); + return; + } + bool accepted = DCCTransferTab::confirm(static_cast<QWidget*>(m_session->parent()), nickname, params[1], params[4].toUInt()); + if(!accepted) + return; + QString filename = Opie::Ui::OFileDialog::getSaveFileName(Opie::Ui::OFileSelector::EXTENDED_ALL, + QString::null, params[1], MimeTypes(), 0, tr("Save As")); + if(filename.isEmpty()) + return; + + odebug << "Receiving file " << filename << " from " << nickname << oendl; + static_cast<IRCServerTab*>(m_session->parent())->mainwindow()->addDCC(DCCTransfer::Recv, params[2].toUInt(), params[3].toUInt(), + filename, nickname, params[4].toUInt()); } - - //TransferReceiver *foo = new TransferReceiver(params[2].toUInt(), params[3].toUInt(), params[1], params[4].toUInt()); } void IRCMessageParser::parseLiteralMode(IRCMessage *message) { IRCPerson mask(message->prefix()); diff --git a/noncore/net/opieirc/ircservertab.cpp b/noncore/net/opieirc/ircservertab.cpp index 62a06e8..d3c0448 100644 --- a/noncore/net/opieirc/ircservertab.cpp +++ b/noncore/net/opieirc/ircservertab.cpp @@ -411,5 +411,9 @@ void IRCServerTab::slotUpdateChannels() { for (; it.current(); ++it) { it.current()->list()->update(); } } + +MainWindow *IRCServerTab::mainwindow() { + return m_mainWindow; +} diff --git a/noncore/net/opieirc/ircservertab.h b/noncore/net/opieirc/ircservertab.h index 42f6f57..fe48a3b 100644 --- a/noncore/net/opieirc/ircservertab.h +++ b/noncore/net/opieirc/ircservertab.h @@ -40,8 +40,9 @@ public: ~IRCServerTab(); QString title(); IRCSession *session(); IRCServer *server(); + MainWindow *mainwindow(); /* Start the server session */ void doConnect(); // QString *mynick(); diff --git a/noncore/net/opieirc/ircsession.cpp b/noncore/net/opieirc/ircsession.cpp index fd8ba72..c8d7869 100644 --- a/noncore/net/opieirc/ircsession.cpp +++ b/noncore/net/opieirc/ircsession.cpp @@ -3,13 +3,14 @@ #include "ircmessageparser.h" #include "ircchannelperson.h" #include "ircversion.h" -IRCSession::IRCSession(QWidget *parent, IRCServer *server) { +IRCSession::IRCSession(QObject *parent, IRCServer *server) + : QObject(parent) +{ m_server = server; m_connection = new IRCConnection(m_server); m_parser = new IRCMessageParser(this); - m_parent = parent; connect(m_connection, SIGNAL(messageArrived(IRCMessage*)), this, SLOT(handleMessage(IRCMessage*))); connect(m_parser, SIGNAL(outputReady(IRCOutput)), this, SIGNAL(outputReady(IRCOutput))); connect(m_connection, SIGNAL(outputReady(IRCOutput)), this, SIGNAL(outputReady(IRCOutput))); } diff --git a/noncore/net/opieirc/ircsession.h b/noncore/net/opieirc/ircsession.h index 7c91893..23a2540 100644 --- a/noncore/net/opieirc/ircsession.h +++ b/noncore/net/opieirc/ircsession.h @@ -29,8 +29,9 @@ #include "ircchannel.h" #include "ircoutput.h" class IRCMessageParser; +class IRCServerTab; /* The IRCSession stores all information relating to the connection to one IRC server. IRCSession makes it possible to run multiple IRC server connections from within the same program */ @@ -38,9 +39,9 @@ class IRCMessageParser; class IRCSession : public QObject { friend class IRCMessageParser; Q_OBJECT public: - IRCSession(QWidget *parent, IRCServer *server); + IRCSession(QObject *parent, IRCServer *server); ~IRCSession(); void join(QString channel); void quit(QString message); @@ -89,8 +90,7 @@ protected: QList<IRCChannel> m_channels; QList<IRCPerson> m_people; QString m_validUsermodes; QString m_validChannelmodes; - QWidget *m_parent; }; #endif /* __IRCSESSION_H */ diff --git a/noncore/net/opieirc/mainwindow.cpp b/noncore/net/opieirc/mainwindow.cpp index 1811a0c..3d60107 100644 --- a/noncore/net/opieirc/mainwindow.cpp +++ b/noncore/net/opieirc/mainwindow.cpp @@ -6,11 +6,15 @@ #include <qwhatsthis.h> #include "mainwindow.h" #include "ircservertab.h" +#include "dcctransfertab.h" #include "ircserverlist.h" #include "ircsettings.h" +#include <stdio.h> + + QString MainWindow::appCaption() { return QObject::tr("Opie IRC"); } @@ -32,8 +36,9 @@ MainWindow::MainWindow(QWidget *parent, const char *name, WFlags) : QMainWindow( a = new QAction(tr("Settings"), Resource::loadPixmap("SettingsIcon"), QString::null, 0, this, 0); a->setWhatsThis(tr("Configure OpieIRC's behavior and appearance")); connect(a, SIGNAL(activated()), this, SLOT(settings())); a->addTo(irc); + m_dccTab = 0; loadSettings(); } /*IRCTabWidget MainWindow::getTabWidget(){ @@ -76,8 +81,11 @@ void MainWindow::changeEvent(IRCTab *tab) { m_tabWidget->setTabColor(tab->id(), blue); } void MainWindow::killTab(IRCTab *tab, bool imediate) { + if (tab == m_dccTab) + m_dccTab = 0; + m_toDelete.append( tab ); if ( imediate ) slotKillTabsLater(); @@ -136,4 +144,16 @@ void MainWindow::slotPrevTab() { void MainWindow::slotPing( const QString& /*channel*/ ) { raise(); } +void MainWindow::addDCC(DCCTransfer::Type type, Q_UINT32 ip4Addr, Q_UINT16 port, + const QString &filename, const QString &nickname, unsigned int size) { + + if (!m_dccTab) { + m_dccTab = new DCCTransferTab(this); + addTab(m_dccTab); + m_dccTab->show(); + } + + m_dccTab->addTransfer(type, ip4Addr, port, filename, nickname, size); +} + diff --git a/noncore/net/opieirc/mainwindow.h b/noncore/net/opieirc/mainwindow.h index abf205d..873a685 100644 --- a/noncore/net/opieirc/mainwindow.h +++ b/noncore/net/opieirc/mainwindow.h @@ -23,12 +23,15 @@ #include <qmainwindow.h> #include <qaction.h> #include <qlist.h> -#include "mainwindow.h" + +#include "dcctransfer.h" #include "ircmisc.h" #include "irctab.h" +class DCCTransferTab; + class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = 0, const char *name = 0, WFlags f = 0); @@ -36,8 +39,10 @@ public: void addTab(IRCTab *tab); void killTab(IRCTab *tab, bool now = false); static QString appName() { return QString::fromLatin1("opieirc"); } static QString appCaption(); + void addDCC(DCCTransfer::Type type, Q_UINT32 ip4Addr, Q_UINT16 port, + const QString &filename, const QString &nickname, unsigned int size); signals: void updateScroll(); protected slots: void newConnection(); @@ -55,7 +60,8 @@ protected: protected: IRCTabWidget *m_tabWidget; QList<IRCTab> m_tabs; QList<IRCTab> m_toDelete; + DCCTransferTab *m_dccTab; }; #endif /* __MAINWINDOW_H */ diff --git a/noncore/net/opieirc/opieirc.pro b/noncore/net/opieirc/opieirc.pro index 1ef9be2..5e91450 100644 --- a/noncore/net/opieirc/opieirc.pro +++ b/noncore/net/opieirc/opieirc.pro @@ -6,9 +6,11 @@ HEADERS = ircchannel.h ircconnection.h \ mainwindow.h irctab.h ircservertab.h \ ircchanneltab.h ircchannellist.h \ ircserverlist.h ircservereditor.h \ ircquerytab.h ircsettings.h ircmisc.h \ - ircchannelperson.h + ircchannelperson.h dcctransfertab.h \ + dccprogress.h dcctransfer.h \ + dcctransferrecv.h SOURCES = ircchannel.cpp ircconnection.cpp \ ircmessage.cpp \ ircmessageparser.cpp ircoutput.cpp \ ircperson.cpp ircserver.cpp \ @@ -16,9 +18,12 @@ SOURCES = ircchannel.cpp ircconnection.cpp \ irctab.cpp ircservertab.cpp \ ircchanneltab.cpp ircchannellist.cpp \ ircserverlist.cpp ircservereditor.cpp \ ircquerytab.cpp ircsettings.cpp ircmisc.cpp \ - ircchannelperson.cpp + ircchannelperson.cpp dcctransfertab.cpp \ + dccprogress.cpp dcctransfer.cpp \ + dcctransferrecv.cpp + INCLUDEPATH += $(OPIEDIR)/include DEPENDPATH += $(OPIEDIR)/include PRECOMPILED_HEADER = stable.h |