diff options
author | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
---|---|---|
committer | toma <toma@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2009-11-25 17:56:58 +0000 |
commit | bcb704366cb5e333a626c18c308c7e0448a8e69f (patch) | |
tree | f0d6ab7d78ecdd9207cf46536376b44b91a1ca71 /kopete/protocols/sms/services | |
download | tdenetwork-bcb704366cb5e333a626c18c308c7e0448a8e69f.tar.gz tdenetwork-bcb704366cb5e333a626c18c308c7e0448a8e69f.zip |
Copy the KDE 3.5 branch to branches/trinity for new KDE 3.5 features.
BUG:215923
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/kdenetwork@1054174 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kopete/protocols/sms/services')
-rw-r--r-- | kopete/protocols/sms/services/Makefile.am | 18 | ||||
-rw-r--r-- | kopete/protocols/sms/services/gsmlib.cpp | 462 | ||||
-rw-r--r-- | kopete/protocols/sms/services/gsmlib.h | 151 | ||||
-rw-r--r-- | kopete/protocols/sms/services/gsmlibprefs.ui | 100 | ||||
-rw-r--r-- | kopete/protocols/sms/services/kopete_unix_serial.cpp | 445 | ||||
-rw-r--r-- | kopete/protocols/sms/services/kopete_unix_serial.h | 70 | ||||
-rw-r--r-- | kopete/protocols/sms/services/smsclient.cpp | 192 | ||||
-rw-r--r-- | kopete/protocols/sms/services/smsclient.h | 65 | ||||
-rw-r--r-- | kopete/protocols/sms/services/smsclientprefs.ui | 135 | ||||
-rw-r--r-- | kopete/protocols/sms/services/smssend.cpp | 254 | ||||
-rw-r--r-- | kopete/protocols/sms/services/smssend.h | 66 | ||||
-rw-r--r-- | kopete/protocols/sms/services/smssendprefs.ui | 188 | ||||
-rw-r--r-- | kopete/protocols/sms/services/smssendprovider.cpp | 288 | ||||
-rw-r--r-- | kopete/protocols/sms/services/smssendprovider.h | 82 |
14 files changed, 2516 insertions, 0 deletions
diff --git a/kopete/protocols/sms/services/Makefile.am b/kopete/protocols/sms/services/Makefile.am new file mode 100644 index 00000000..e21f1505 --- /dev/null +++ b/kopete/protocols/sms/services/Makefile.am @@ -0,0 +1,18 @@ +METASOURCES = AUTO +AM_CPPFLAGS = $(KOPETE_INCLUDES) \ + -I$(srcdir)/.. \ + -I.. \ + $(all_includes) + +KDE_CXXFLAGS = $(USE_EXCEPTIONS) + +noinst_LTLIBRARIES = libkopetesmsservices.la + + +libkopetesmsservices_la_SOURCES = smssend.cpp smssendprefs.ui smssendprovider.cpp \ + smsclient.cpp smsclientprefs.ui gsmlib.cpp gsmlibprefs.ui kopete_unix_serial.cpp + +if include_smsgsm +libkopetesmsservices_la_LIBADD = -lgsmme +endif + diff --git a/kopete/protocols/sms/services/gsmlib.cpp b/kopete/protocols/sms/services/gsmlib.cpp new file mode 100644 index 00000000..e9b0542b --- /dev/null +++ b/kopete/protocols/sms/services/gsmlib.cpp @@ -0,0 +1,462 @@ +/* ************************************************************************* + * copyright: (C) 2005 Justin Huff <jjhuff@mspin.net> * + ************************************************************************* +*/ + +/* ************************************************************************* + * * + * 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. * + * * + ************************************************************************* +*/ +#include "config.h" +#ifdef INCLUDE_SMSGSM + +#include <qcombobox.h> +#include <qlayout.h> +#include <qapplication.h> +#include <qevent.h> +#include <qmutex.h> +#include <qthread.h> +#include <qcheckbox.h> + +#include <klocale.h> +#include <kurlrequester.h> +#include <kmessagebox.h> +#include <kprocess.h> +#include <kdebug.h> +#include <kconfigbase.h> + +#include <unistd.h> +#include <gsmlib/gsm_me_ta.h> +#include <gsmlib/gsm_sms.h> +#include <gsmlib/gsm_util.h> +#include <gsmlib/gsm_error.h> + +#include "kopeteaccount.h" +#include "kopeteuiglobal.h" +#include "kopetemetacontact.h" +#include "kopetecontactlist.h" +#include "kopetechatsessionmanager.h" + +#include "gsmlib.h" +#include "gsmlibprefs.h" +#include "smsprotocol.h" +#include "smscontact.h" + +#include "kopete_unix_serial.h" + +///////////////////////////////////////////////////////////////////// +#define GSMLIB_EVENT_ID 245 +GSMLibEvent::GSMLibEvent(SubType t) : QCustomEvent(QEvent::User+GSMLIB_EVENT_ID) +{ + setSubType(t); +} + +GSMLibEvent::SubType GSMLibEvent::subType() +{ + return m_subType; +} + +void GSMLibEvent::setSubType(GSMLibEvent::SubType t) +{ + m_subType = t; +} + +///////////////////////////////////////////////////////////////////// +GSMLibThread::GSMLibThread(QString dev, GSMLib* parent) +{ + m_device = dev; + m_parent = parent; + m_run = true; + m_MeTa = NULL; +} + +GSMLibThread::~GSMLibThread() +{ + m_run = false; +} + +void GSMLibThread::stop() +{ + m_run = false; + kdDebug( 14160 ) << "Waiting from GSMLibThread to die"<<endl; + if( wait(4000) == false ) + kdWarning( 14160 ) << "GSMLibThread didn't exit!"<<endl; +} +void GSMLibThread::run() +{ + if( doConnect() ) + { + while( m_run ) + { + pollForMessages(); + sendMessageQueue(); + } + } + + delete m_MeTa; + m_MeTa = NULL; + QApplication::postEvent(m_parent, new GSMLibEvent(GSMLibEvent::DISCONNECTED)); + kdDebug( 14160 ) << "GSMLibThread exited"<<endl; +} + +void GSMLibThread::send(const Kopete::Message& msg) +{ + if( m_MeTa ) + { + m_outMessagesMutex.lock(); + m_outMessages.push_back(msg); + m_outMessagesMutex.unlock(); + } + else + { + GSMLibEvent* e = new GSMLibEvent( GSMLibEvent::MSG_NOT_SENT ); + e->Reason = QString("GSMLib: Not Connected"); + e->Message = msg; + QApplication::postEvent(m_parent, e); + } +} + + +bool GSMLibThread::doConnect() +{ + // open the port and ME/TA + try + { + kdDebug( 14160 ) << "Connecting to: '"<<m_device<<"'"<<endl; + + gsmlib::Ref<gsmlib::Port> port = new gsmlib::KopeteUnixSerialPort(m_device.latin1(), 9600, gsmlib::DEFAULT_INIT_STRING, false); + + kdDebug( 14160 ) << "Port created"<<endl; + + m_MeTa = new gsmlib::MeTa(port); + std::string dummy1, dummy2, receiveStoreName; + m_MeTa->getSMSStore(dummy1, dummy2, receiveStoreName ); + m_MeTa->setSMSStore(receiveStoreName, 3); + + m_MeTa->setMessageService(1); + + // switch on SMS routing + m_MeTa->setSMSRoutingToTA(true, false, false, true); + + m_MeTa->setEventHandler(this); + QApplication::postEvent(m_parent, new GSMLibEvent(GSMLibEvent::CONNECTED)); + return true; + } + catch(gsmlib::GsmException &e) + { + kdWarning( 14160 ) << k_funcinfo<< e.what()<<endl; + m_run = false; + return false; + } +} + +void GSMLibThread::SMSReception(gsmlib::SMSMessageRef newMessage, SMSMessageType messageType) +{ + try + { + IncomingMessage m; + m.Type = messageType; + m.Message = newMessage; + + m_newMessages.push_back(m); + } + catch(gsmlib::GsmException &e) + { + kdWarning( 14160 ) << k_funcinfo<< e.what()<<endl; + m_run = false; + } +} + +void GSMLibThread::SMSReceptionIndication(std::string storeName, unsigned int index, SMSMessageType messageType) +{ + kdDebug( 14160 ) << k_funcinfo << "New Message in store: "<<storeName.c_str() << endl; + + try + { + if( messageType != gsmlib::GsmEvent::NormalSMS ) + return; + + IncomingMessage m; + m.Index = index; + m.StoreName = storeName.c_str(); + m.Type = messageType; + m_newMessages.push_back(m); + } + catch(gsmlib::GsmException &e) + { + kdWarning( 14160 ) << k_funcinfo<< e.what()<<endl; + m_run = false; + } +} + +void GSMLibThread::pollForMessages( ) +{ + if( m_MeTa == NULL ) + return; + + try + { + struct timeval timeoutVal; + timeoutVal.tv_sec = 1; + timeoutVal.tv_usec = 0; + m_MeTa->waitEvent(&timeoutVal); + + MessageList::iterator it; + for( it=m_newMessages.begin(); it!=m_newMessages.end(); it++) + { + IncomingMessage m = *it; + + // Do we need to fetch it from the ME? + if( m.Message.isnull() ) + { + gsmlib::SMSStoreRef store = m_MeTa->getSMSStore(m.StoreName.latin1()); + store->setCaching(false); + + m.Message = (*store.getptr())[m.Index].message(); + store->erase(store->begin() + m.Index); + } + + GSMLibEvent* e = new GSMLibEvent( GSMLibEvent::NEW_MESSAGE ); + e->Text = m.Message->userData().c_str(); + e->Number = m.Message->address().toString().c_str(); + + QApplication::postEvent(m_parent, e); + + } + m_newMessages.clear(); + } + catch(gsmlib::GsmException &e) + { + kdWarning( 14160 ) << k_funcinfo<< e.what()<<endl; + m_run = false; + } +} + +void GSMLibThread::sendMessageQueue() +{ + QMutexLocker _(&m_outMessagesMutex); + + if(m_outMessages.size() == 0 ) + return; + + KopeteMessageList::iterator it; + for( it=m_outMessages.begin(); it!=m_outMessages.end(); it++) + sendMessage(*it); + m_outMessages.clear(); +} + +void GSMLibThread::sendMessage(const Kopete::Message& msg) +{ + QString reason; + + if (!m_MeTa) + { + GSMLibEvent* e = new GSMLibEvent( GSMLibEvent::MSG_NOT_SENT ); + e->Reason = QString("GSMLib: Not Connected"); + e->Message = msg; + QApplication::postEvent(m_parent, e); + } + + QString message = msg.plainBody(); + QString nr = msg.to().first()->contactId(); + + // send SMS + try + { + gsmlib::Ref<gsmlib::SMSSubmitMessage> submitSMS = new gsmlib::SMSSubmitMessage(); + gsmlib::Address destAddr( nr.latin1() ); + submitSMS->setDestinationAddress(destAddr); + m_MeTa->sendSMSs(submitSMS, message.latin1(), true); + + GSMLibEvent* e = new GSMLibEvent( GSMLibEvent::MSG_SENT ); + e->Message = msg; + QApplication::postEvent(m_parent, e); + } + catch(gsmlib::GsmException &e) + { + GSMLibEvent* ev = new GSMLibEvent( GSMLibEvent::MSG_NOT_SENT ); + ev->Reason = QString("GSMLib: ") + e.what(); + ev->Message = msg; + QApplication::postEvent(m_parent, ev); + } +} + +///////////////////////////////////////////////////////////////////// + +GSMLib::GSMLib(Kopete::Account* account) + : SMSService(account) +{ + prefWidget = 0L; + m_thread = NULL; + + loadConfig(); +} + +GSMLib::~GSMLib() +{ + disconnect(); +} + +void GSMLib::saveConfig() +{ + if( m_account != NULL ) + { + KConfigGroup* c = m_account->configGroup(); + + c->writeEntry(QString("%1:%2").arg("GSMLib").arg("Device"), m_device); + } +} + +void GSMLib::loadConfig() +{ + m_device = "/dev/bluetooth/rfcomm0"; + if( m_account != NULL ) + { + QString temp; + KConfigGroup* c = m_account->configGroup(); + + temp = c->readEntry(QString("%1:%2").arg("GSMLib").arg("Device"), QString::null); + if( temp != QString::null ) + m_device = temp; + } +} + +void GSMLib::connect() +{ + + m_thread = new GSMLibThread(m_device, this); + m_thread->start(); + +} + +void GSMLib::disconnect() +{ + kdDebug( 14160 ) << k_funcinfo <<endl; + + if( m_thread ) + { + m_thread->stop(); + delete m_thread; + m_thread = NULL; + emit disconnected(); + } + +} + +void GSMLib::setWidgetContainer(QWidget* parent, QGridLayout* layout) +{ + m_parent = parent; + m_layout = layout; + QWidget *configWidget = configureWidget(parent); + layout->addMultiCellWidget(configWidget, 0, 1, 0, 1); + configWidget->show(); +} + +void GSMLib::send(const Kopete::Message& msg) +{ + m_thread->send(msg); +} + +QWidget* GSMLib::configureWidget(QWidget* parent) +{ + + if (prefWidget == 0L) + prefWidget = new GSMLibPrefsUI(parent); + + loadConfig(); + prefWidget->device->setURL(m_device); + + return prefWidget; +} + +void GSMLib::savePreferences() +{ + if( prefWidget ) + { + m_device = prefWidget->device->url(); + } + saveConfig(); +} + +int GSMLib::maxSize() +{ + return 160; +} + +void GSMLib::customEvent(QCustomEvent* e) +{ + if( e->type() != QEvent::User+GSMLIB_EVENT_ID ) + return; + + if( m_account == NULL ) + return; + + GSMLibEvent* ge = (GSMLibEvent*)e; + + kdDebug( 14160 ) << "Got event "<<ge->subType()<<endl; + switch( ge->subType() ) + { + case GSMLibEvent::CONNECTED: + emit connected(); + break; + case GSMLibEvent::DISCONNECTED: + disconnect(); + break; + case GSMLibEvent::MSG_SENT: + emit messageSent(ge->Message); + break; + case GSMLibEvent::MSG_NOT_SENT: + emit messageNotSent(ge->Message, ge->Reason); + break; + case GSMLibEvent::NEW_MESSAGE: + { + QString nr = ge->Number; + QString text = ge->Text; + + // Locate a contact + SMSContact* contact = static_cast<SMSContact*>( m_account->contacts().find( nr )); + if ( contact==NULL ) + { + // No contact found, make a new one + Kopete::MetaContact* metaContact = new Kopete::MetaContact (); + metaContact->setTemporary ( true ); + contact = new SMSContact(m_account, nr, nr, metaContact ); + Kopete::ContactList::self ()->addMetaContact( metaContact ); + contact->setOnlineStatus( SMSProtocol::protocol()->SMSOnline ); + } + + // Deliver the msg + Kopete::Message msg( contact, m_account->myself(), text, Kopete::Message::Inbound, Kopete::Message::RichText ); + contact->manager(Kopete::Contact::CanCreate)->appendMessage( msg ); + break; + } + } +} + + + + +const QString& GSMLib::description() +{ + QString url = "http://www.pxh.de/fs/gsmlib/"; + m_description = i18n("<qt>GSMLib is a library (and utilities) for sending SMS via a GSM device. The program can be found on <a href=\"%1\">%1</a></qt>").arg(url).arg(url); + return m_description; +} + +#include "gsmlib.moc" + +#endif +/* + * Local variables: + * c-indentation-style: k&r + * c-basic-offset: 8 + * indent-tabs-mode: t + * End: + */ +// vim: set noet ts=4 sts=4 sw=4: + diff --git a/kopete/protocols/sms/services/gsmlib.h b/kopete/protocols/sms/services/gsmlib.h new file mode 100644 index 00000000..fa9ef1d2 --- /dev/null +++ b/kopete/protocols/sms/services/gsmlib.h @@ -0,0 +1,151 @@ +/* ************************************************************************* + * copyright: (C) 2005 Justin Huff <jjhuff@mspin.net> * + ************************************************************************* +*/ + +/* ************************************************************************* + * * + * 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. * + * * + ************************************************************************* +*/ + +#ifndef GSMLIB_H_039562406 +#define GSMLIB_H_039562406 + +#include "config.h" +#ifdef INCLUDE_SMSGSM + +#include <unistd.h> + +#include <gsmlib/gsm_unix_serial.h> +#include <gsmlib/gsm_sms.h> +#include <gsmlib/gsm_me_ta.h> +#include <gsmlib/gsm_util.h> +#include <gsmlib/gsm_event.h> + +#include "smsservice.h" +#include "kopetemessage.h" + +#include <qobject.h> +#include <qevent.h> +#include <qthread.h> +#include <qmutex.h> +#include <qvaluelist.h> +#include <qstringlist.h> + +class GSMLibPrefsUI; +class SMSContact; +class QListViewItem; +class KProcess; +class GSMLibThread; + +class GSMLib : public SMSService +{ + Q_OBJECT +public: + GSMLib(Kopete::Account* account); + ~GSMLib(); + + void send(const Kopete::Message& msg); + void setWidgetContainer(QWidget* parent, QGridLayout* container); + + int maxSize(); + const QString& description(); + +public slots: + void savePreferences(); + virtual void connect(); + virtual void disconnect(); + +//signals: +// void messageSent(const Kopete::Message &); +protected: + virtual void customEvent(QCustomEvent* e); + + QWidget* configureWidget(QWidget* parent); + void saveConfig(); + void loadConfig(); + + GSMLibPrefsUI* prefWidget; + QStringList output; + + QString m_device; + + QString m_description; + + GSMLibThread* m_thread; + +} ; + + +/// Custom event for async-events +class GSMLibEvent : public QCustomEvent +{ +public: + enum SubType { CONNECTED, DISCONNECTED, NEW_MESSAGE, MSG_SENT, MSG_NOT_SENT }; + + GSMLibEvent(SubType t); + + SubType subType(); + void setSubType(SubType t); + + QString Text; + QString Number; + + QString Reason; + + Kopete::Message Message; +protected: + SubType m_subType; +}; + +/// Thread to deal with GsmLib's blocking +class GSMLibThread : public QThread, gsmlib::GsmEvent +{ +public: + GSMLibThread(QString dev, GSMLib* parent); + virtual ~GSMLibThread(); + + virtual void run(); + void stop(); + void send(const Kopete::Message& msg); +protected: + bool doConnect(); + void pollForMessages(); + void sendMessageQueue(); + void sendMessage(const Kopete::Message& msg); + void SMSReception(gsmlib::SMSMessageRef newMessage, SMSMessageType messageType); + void SMSReceptionIndication(std::string storeName, unsigned int index, SMSMessageType messageType); + + GSMLib* m_parent; + QString m_device; + + gsmlib::MeTa* m_MeTa; + + bool m_run; + + struct IncomingMessage + { + int Index; + QString StoreName; + gsmlib::SMSMessageRef Message; + GsmEvent::SMSMessageType Type; + + IncomingMessage() : Index(-1) + {} + }; + + typedef QValueList<IncomingMessage> MessageList; + MessageList m_newMessages; + + typedef QValueList<Kopete::Message> KopeteMessageList; + KopeteMessageList m_outMessages; + QMutex m_outMessagesMutex; +}; + +#endif +#endif //GSMLIB_H_039562406 diff --git a/kopete/protocols/sms/services/gsmlibprefs.ui b/kopete/protocols/sms/services/gsmlibprefs.ui new file mode 100644 index 00000000..108f6326 --- /dev/null +++ b/kopete/protocols/sms/services/gsmlibprefs.ui @@ -0,0 +1,100 @@ +<!DOCTYPE UI><UI version="3.3" stdsetdef="1"> +<class>GSMLibPrefsUI</class> +<widget class="QWidget"> + <property name="name"> + <cstring>GSMLibPrefsUI</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>375</width> + <height>168</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <spacer> + <property name="name"> + <cstring>spacer16</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>321</width> + <height>16</height> + </size> + </property> + </spacer> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel8</cstring> + </property> + <property name="font"> + <font> + <bold>1</bold> + </font> + </property> + <property name="text"> + <string>GSMLib Settings</string> + </property> + </widget> + <widget class="Line"> + <property name="name"> + <cstring>line14</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout13</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>Device:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>program</cstring> + </property> + </widget> + <widget class="KURLRequester" row="0" column="1"> + <property name="name"> + <cstring>device</cstring> + </property> + </widget> + </grid> + </widget> + </vbox> +</widget> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> +</includehints> +</UI> diff --git a/kopete/protocols/sms/services/kopete_unix_serial.cpp b/kopete/protocols/sms/services/kopete_unix_serial.cpp new file mode 100644 index 00000000..b694ab22 --- /dev/null +++ b/kopete/protocols/sms/services/kopete_unix_serial.cpp @@ -0,0 +1,445 @@ +// ************************************************************************* +// * Taken from the GSM TA/ME library +// * +// * File: gsm_unix_port.cc +// * +// * Purpose: UNIX serial port implementation with extras +// * +// * Original Author: Peter Hofmann (software@pxh.de) +// * Modified by: Justin Huff (jjhuff@mspin.net) +// * +// * Created: 10.5.1999 +// ************************************************************************* +#include "config.h" +#ifdef INCLUDE_SMSGSM + +#include <gsmlib/gsm_util.h> +#include <termios.h> +#include <fcntl.h> +#include <iostream> +#include <sstream> +#include <errno.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/ioctl.h> +#include <signal.h> +#include <pthread.h> +#include <cassert> +#include <assert.h> + +#include <qsocketnotifier.h> + +#include "kopete_unix_serial.h" + +using namespace std; +using namespace gsmlib; + +static const int holdoff[] = {2000000, 1000000, 400000}; +static const int holdoffArraySize = sizeof(holdoff)/sizeof(int); + +// alarm handling for socket read/write +// the timerMtx is necessary since several threads cannot use the +// timer indepently of each other + +static pthread_mutex_t timerMtx = PTHREAD_MUTEX_INITIALIZER; +#define pthread_mutex_lock(x) +#define pthread_mutex_unlock(x) + +// for non-GNU systems, define alarm() +#ifndef HAVE_ALARM +unsigned int alarm(unsigned int seconds) +{ + struct itimerval old, newt; + newt.it_interval.tv_usec = 0; + newt.it_interval.tv_sec = 0; + newt.it_value.tv_usec = 0; + newt.it_value.tv_sec = (long int)seconds; + if (setitimer(ITIMER_REAL, &newt, &old) < 0) + return 0; + else + return old.it_value.tv_sec; +} +#endif + +// this routine is called in case of a timeout +static void catchAlarm(int) +{ + // do nothing +} + +// start timer +static void startTimer() +{ + pthread_mutex_lock(&timerMtx); + struct sigaction newAction; + newAction.sa_handler = catchAlarm; + newAction.sa_flags = 0; + sigaction(SIGALRM, &newAction, NULL); + alarm(1); +} + +// reset timer +static void stopTimer() +{ + alarm(0); + sigaction(SIGALRM, NULL, NULL); + pthread_mutex_unlock(&timerMtx); +} + +// KopeteUnixSerialPort members + +void KopeteUnixSerialPort::throwModemException(string message) throw(GsmException) +{ + ostringstream os; + os << message << " (errno: " << errno << "/" << strerror(errno) << ")"; + throw GsmException(os.str(), OSError, errno); +} + +void KopeteUnixSerialPort::putBack(unsigned char c) +{ + assert(_oldChar == -1); + _oldChar = c; +} + +int KopeteUnixSerialPort::readByte() throw(GsmException) +{ + if (_oldChar != -1) + { + int result = _oldChar; + _oldChar = -1; + return result; + } + + unsigned char c; + int timeElapsed = 0; + struct timeval oneSecond; + bool readDone = false; + + while (! readDone && timeElapsed < _timeoutVal) + { + if (interrupted()) + throwModemException("interrupted when reading from TA"); + + // setup fd_set data structure for select() + fd_set fdSet; + oneSecond.tv_sec = 1; + oneSecond.tv_usec = 0; + FD_ZERO(&fdSet); + FD_SET(_fd, &fdSet); + + switch (select(FD_SETSIZE, &fdSet, NULL, NULL, &oneSecond)) + { + case 1: + { + int res = read(_fd, &c, 1); + if (res != 1) + throwModemException("end of file when reading from TA"); + else + readDone = true; + break; + } + case 0: + ++timeElapsed; + break; + default: + if (errno != EINTR) + throwModemException("reading from TA"); + break; + } + } + if (! readDone) + throwModemException("timeout when reading from TA"); + +#ifndef NDEBUG + if (debugLevel() >= 2) + { + // some useful debugging code + if (c == LF) + cerr << "<LF>"; + else if (c == CR) + cerr << "<CR>"; + else cerr << "<'" << (char) c << "'>"; + cerr.flush(); + } +#endif + return c; +} + +KopeteUnixSerialPort::KopeteUnixSerialPort(string device, speed_t lineSpeed, + string initString, bool swHandshake) + throw(GsmException) : + _oldChar(-1), _timeoutVal(TIMEOUT_SECS) +{ + _readNotifier = NULL; + + struct termios t; + + // open device + _fd = open(device.c_str(), O_RDWR | O_NOCTTY | O_NONBLOCK); + if (_fd == -1) + throwModemException("opening device"); + + // switch off non-blocking mode + int fdFlags; + if ((fdFlags = fcntl(_fd, F_GETFL)) == -1) + { + close(_fd); + throwModemException("getting file status flags failed"); + } + fdFlags &= ~O_NONBLOCK; + if (fcntl(_fd, F_SETFL, fdFlags) == -1) + { + close(_fd); + throwModemException("switching of non-blocking mode failed"); + } + + // Set the close on exec flag + if ((fdFlags = fcntl(_fd, F_GETFD)) == -1) + { + close(_fd); + throwModemException("getting file status flags failed"); + } + fdFlags |= FD_CLOEXEC; + if (fcntl(_fd, F_SETFD, fdFlags) == -1) + { + close(_fd); + throwModemException("switching of non-blocking mode failed"); + } + + long int saveTimeoutVal = _timeoutVal; + _timeoutVal = 3; + int initTries = holdoffArraySize; + while (initTries-- > 0) + { + // flush all pending output + tcflush(_fd, TCOFLUSH); + + // toggle DTR to reset modem + int mctl = TIOCM_DTR; + if (ioctl(_fd, TIOCMBIC, &mctl) < 0 && errno != ENOTTY) + { + close(_fd); + throwModemException("clearing DTR failed"); + } + // the waiting time for DTR toggling is increased with each loop + usleep(holdoff[initTries]); + if (ioctl(_fd, TIOCMBIS, &mctl) < 0 && errno != ENOTTY) + { + close(_fd); + throwModemException("setting DTR failed"); + } + // get line modes + if (tcgetattr(_fd, &t) < 0) + { + close(_fd); + throwModemException("tcgetattr device"); + } + + // set line speed + cfsetispeed(&t, lineSpeed); + cfsetospeed(&t, lineSpeed); + + // set the device to a sane state + t.c_iflag |= IGNPAR | (swHandshake ? IXON | IXOFF : 0); + t.c_iflag &= ~(INPCK | ISTRIP | IMAXBEL | + (swHandshake ? 0 : IXON | IXOFF) + | IXANY | IGNCR | ICRNL | IMAXBEL | INLCR | IGNBRK); + t.c_oflag &= ~(OPOST); + // be careful, only touch "known" flags + t.c_cflag &= ~(CSIZE | CSTOPB | PARENB | PARODD | + (swHandshake ? CRTSCTS : 0 )); + t.c_cflag |= CS8 | CREAD | HUPCL | (swHandshake ? 0 : CRTSCTS) | CLOCAL; + t.c_lflag &= ~(ECHO | ECHOE | ECHOPRT | ECHOK | ECHOKE | ECHONL | + ECHOCTL | ISIG | IEXTEN | TOSTOP | FLUSHO | ICANON); + t.c_lflag |= NOFLSH; + t.c_cc[VMIN] = 1; + t.c_cc[VTIME] = 0; + + t.c_cc[VSUSP] = 0; + + // write back + if(tcsetattr (_fd, TCSANOW, &t) < 0) + { + close(_fd); + throwModemException("tcsetattr device"); + } + // the waiting time for writing to the ME/TA is increased with each loop + usleep(holdoff[initTries]); + + // flush all pending input + tcflush(_fd, TCIFLUSH); + + try + { + // reset modem + putLine("ATZ"); + bool foundOK = false; + int readTries = 5; + while (readTries-- > 0) + { + // for the first call getLine() waits only 3 seconds + // because of _timeoutVal = 3 + string s = getLine(); + if (s.find("OK") != string::npos || + s.find("CABLE: GSM") != string::npos) + { + foundOK = true; + readTries = 0; // found OK, exit loop + } + else if (s.find("ERROR") != string::npos) + readTries = 0; // error, exit loop + } + + // set getLine/putLine timeout back to old value + _timeoutVal = saveTimeoutVal; + + if (foundOK) + { + // init modem + readTries = 5; + putLine("AT" + initString); + while (readTries-- > 0) + { + string s = getLine(); + if (s.find("OK") != string::npos || + s.find("CABLE: GSM") != string::npos) + { + _readNotifier = new QSocketNotifier(_fd, QSocketNotifier::Read); + connect( _readNotifier, SIGNAL(activated(int)), this, SIGNAL(activated())); + return; // found OK, return + } + } + } + } + catch (GsmException &e) + { + _timeoutVal = saveTimeoutVal; + if (initTries == 0) + { + close(_fd); + throw e; + } + } + } + // no response after 3 tries + close(_fd); + throwModemException("reset modem failed"); +} + +string KopeteUnixSerialPort::getLine() throw(GsmException) +{ + string result; + int c; + while ((c = readByte()) >= 0) + { + while (c == CR) + { + c = readByte(); + } + if (c == LF) + break; + result += c; + } + +#ifndef NDEBUG + if (debugLevel() >= 1) + cerr << "<-- " << result << endl; +#endif + + return result; +} + +void KopeteUnixSerialPort::putLine(string line, + bool carriageReturn) throw(GsmException) +{ +#ifndef NDEBUG + if (debugLevel() >= 1) + cerr << "--> " << line << endl; +#endif + + if (carriageReturn) line += CR; + const char *l = line.c_str(); + + int timeElapsed = 0; + struct timeval oneSecond; + + ssize_t bytesWritten = 0; + while (bytesWritten < (ssize_t)line.length() && timeElapsed < _timeoutVal) + { + if (interrupted()) + throwModemException("interrupted when writing to TA"); + + // setup fd_set data structure for select() + fd_set fdSet; + oneSecond.tv_sec = 1; + oneSecond.tv_usec = 0; + FD_ZERO(&fdSet); + FD_SET(_fd, &fdSet); + + switch (select(FD_SETSIZE, NULL, &fdSet, NULL, &oneSecond)) + { + case 1: + { + ssize_t bw = write(_fd, l + bytesWritten, line.length() - bytesWritten); + if (bw < 0) + throwModemException("writing to TA"); + bytesWritten += bw; + break; + } + case 0: + ++timeElapsed; + break; + default: + if (errno != EINTR) + throwModemException("writing to TA"); + break; + } + } + + while (timeElapsed < _timeoutVal) + { + if (interrupted()) + throwModemException("interrupted when writing to TA"); + ::startTimer(); + int res = tcdrain(_fd); // wait for output to be read by TA + ::stopTimer(); + if (res == 0) + break; + else + { + assert(errno == EINTR); + ++timeElapsed; + } + } + if (timeElapsed >= _timeoutVal) + throwModemException("timeout when writing to TA"); + + // echo CR LF must be removed by higher layer functions in gsm_at because + // in order to properly handle unsolicited result codes from the ME/TA +} + +bool KopeteUnixSerialPort::wait(GsmTime timeout) throw(GsmException) +{ + fd_set fds; + FD_ZERO(&fds); + FD_SET(_fd, &fds); + return select(FD_SETSIZE, &fds, NULL, NULL, timeout) != 0; +} + +// set timeout for read or write in seconds. +void KopeteUnixSerialPort::setTimeOut(unsigned int timeout) +{ + _timeoutVal = timeout; +} + +KopeteUnixSerialPort::~KopeteUnixSerialPort() +{ + delete _readNotifier; + _readNotifier = NULL; + if (_fd != -1) + close(_fd); +} + +#include "kopete_unix_serial.moc" + +#endif diff --git a/kopete/protocols/sms/services/kopete_unix_serial.h b/kopete/protocols/sms/services/kopete_unix_serial.h new file mode 100644 index 00000000..0248556b --- /dev/null +++ b/kopete/protocols/sms/services/kopete_unix_serial.h @@ -0,0 +1,70 @@ +// ************************************************************************* +// * Taken from the GSM TA/ME library +// * +// * File: gsm_unix_port.h +// * +// * Purpose: UNIX serial port implementation with extras +// * +// * Original Author: Peter Hofmann (software@pxh.de) +// * Modified by: Justin Huff (jjhuff@mspin.net) +// * +// * Created: 4.5.1999 +// ************************************************************************* + +#ifndef GSM_UNIX_SERIAL_KOPETE_H +#define GSM_UNIX_SERIAL_KOPETE_H + +#include "config.h" +#ifdef INCLUDE_SMSGSM + +#include <string> +#include <gsmlib/gsm_error.h> +#include <gsmlib/gsm_port.h> +#include <gsmlib/gsm_util.h> +#include <sys/types.h> +#include <termios.h> + +#include <qobject.h> + +class QSocketNotifier; +namespace gsmlib +{ + +class KopeteUnixSerialPort : public QObject, public Port +{ + Q_OBJECT; + +protected: + int _fd; // file descriptor for device + int _oldChar; // character set by putBack() (-1 == none) + long int _timeoutVal; // timeout for getLine/readByte + + QSocketNotifier* _readNotifier; + + // throw GsmException include UNIX errno + void throwModemException(std::string message) throw(GsmException); + +public: + // create Port given the UNIX device name + KopeteUnixSerialPort(std::string device, speed_t lineSpeed = DEFAULT_BAUD_RATE, + std::string initString = DEFAULT_INIT_STRING, + bool swHandshake = false) + throw(GsmException); + virtual ~KopeteUnixSerialPort(); + + // inherited from Port + void putBack(unsigned char c); + int readByte() throw(GsmException); + std::string getLine() throw(GsmException); + void putLine(std::string line, + bool carriageReturn = true) throw(GsmException); + bool wait(GsmTime timeout) throw(GsmException); + void setTimeOut(unsigned int timeout); + +signals: + void activated(); +}; + +} +#endif +#endif // GSM_UNIX_SERIAL_KOPETE_H diff --git a/kopete/protocols/sms/services/smsclient.cpp b/kopete/protocols/sms/services/smsclient.cpp new file mode 100644 index 00000000..96c04818 --- /dev/null +++ b/kopete/protocols/sms/services/smsclient.cpp @@ -0,0 +1,192 @@ +/* ************************************************************************* + * copyright: (C) 2003 Richard Lärkäng <nouseforaname@home.se> * + * copyright: (C) 2003 Gav Wood <gav@kde.org> * + ************************************************************************* +*/ + +/* ************************************************************************* + * * + * 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. * + * * + ************************************************************************* +*/ + +#include <qcombobox.h> +#include <qlayout.h> + +#include <klocale.h> +#include <kurlrequester.h> +#include <kmessagebox.h> +#include <kprocess.h> +#include <kdebug.h> +#include <kconfigbase.h> + +#include "kopeteaccount.h" +#include "kopeteuiglobal.h" + +#include "smsclient.h" +#include "smsclientprefs.h" +#include "smsprotocol.h" + +SMSClient::SMSClient(Kopete::Account* account) + : SMSService(account) +{ + prefWidget = 0L; +} + +SMSClient::~SMSClient() +{ +} + +void SMSClient::setWidgetContainer(QWidget* parent, QGridLayout* layout) +{ + kdWarning( 14160 ) << k_funcinfo << "ml: " << layout << ", " << "mp: " << parent << endl; + m_parent = parent; + m_layout = layout; + QWidget *configWidget = configureWidget(parent); + layout->addMultiCellWidget(configWidget, 0, 1, 0, 1); + configWidget->show(); +} + +void SMSClient::send(const Kopete::Message& msg) +{ + kdWarning( 14160 ) << k_funcinfo << "m_account = " << m_account << " (should be non-zero!!)" << endl; + if (!m_account) return; + + m_msg = msg; + + KConfigGroup* c = m_account->configGroup(); + QString provider = c->readEntry(QString("%1:%2").arg("SMSClient").arg("ProviderName"), QString::null); + + if (provider.isNull()) + { + KMessageBox::error(Kopete::UI::Global::mainWidget(), i18n("No provider configured"), i18n("Could Not Send Message")); + return; + } + + QString programName = c->readEntry(QString("%1:%2").arg("SMSClient").arg("ProgramName"). QString::null); + if (programName.isNull()) + programName = "/usr/bin/sms_client"; + + KProcess* p = new KProcess; + + QString message = msg.plainBody(); + QString nr = msg.to().first()->contactId(); + + *p << programName; + *p << provider + ":" + nr; + *p << message; + + QObject::connect(p, SIGNAL(processExited(KProcess *)), this, SLOT(slotSendFinished(KProcess*))); + QObject::connect(p, SIGNAL(receivedStdout(KProcess*, char*, int)), this, SLOT(slotReceivedOutput(KProcess*, char*, int))); + QObject::connect(p, SIGNAL(receivedStderr(KProcess*, char*, int)), this, SLOT(slotReceivedOutput(KProcess*, char*, int))); + + p->start(KProcess::Block, KProcess::AllOutput); +} + +QWidget* SMSClient::configureWidget(QWidget* parent) +{ + kdWarning( 14160 ) << k_funcinfo << "m_account = " << m_account << " (should be ok if zero!!)" << endl; + + if (prefWidget == 0L) + prefWidget = new SMSClientPrefsUI(parent); + + prefWidget->configDir->setMode(KFile::Directory); + QString configDir; + if (m_account) + configDir = m_account->configGroup()->readEntry(QString("%1:%2").arg("SMSClient").arg("ConfigDir"), QString::null); + if (configDir.isNull()) + configDir = "/etc/sms"; + prefWidget->configDir->setURL(configDir); + + QString programName; + if (m_account) + programName = m_account->configGroup()->readEntry(QString("%1:%2").arg("SMSClient").arg("ProgramName"), + QString::null); + if (programName.isNull()) + programName = "/usr/bin/sms_client"; + prefWidget->program->setURL(programName); + + prefWidget->provider->insertStringList(providers()); + + if (m_account) + { + QString pName = m_account->configGroup()->readEntry(QString("%1:%2").arg("SMSClient").arg("ProviderName")); + for (int i=0; i < prefWidget->provider->count(); i++) + { + if (prefWidget->provider->text(i) == pName) + { + prefWidget->provider->setCurrentItem(i); + break; + } + } + } + + return prefWidget; +} + +void SMSClient::savePreferences() +{ + kdWarning( 14160 ) << k_funcinfo << "m_account = " << m_account << " (should be work if zero!!)" << endl; + + if (prefWidget != 0L && m_account != 0L) + { + KConfigGroup* c = m_account->configGroup(); + + c->writeEntry(QString("%1:%2").arg("SMSClient").arg("ProgramName"), prefWidget->program->url()); + c->writeEntry(QString("%1:%2").arg("SMSClient").arg("ConfigDir"), prefWidget->configDir->url()); + c->writeEntry(QString("%1:%2").arg("SMSClient").arg("ProviderName"), prefWidget->provider->currentText()); + } +} + +QStringList SMSClient::providers() +{ + QStringList p; + + QDir d; + d.setPath(QString("%1/services/").arg(prefWidget->configDir->url())); + p += d.entryList("*", QDir::Files); + + return p; +} + +void SMSClient::slotReceivedOutput(KProcess*, char *buffer, int buflen) +{ + QStringList lines = QStringList::split("\n", QString::fromLocal8Bit(buffer, buflen)); + for (QStringList::Iterator it = lines.begin(); it != lines.end(); ++it) + output.append(*it); +} + +void SMSClient::slotSendFinished(KProcess* p) +{ + if (p->exitStatus() == 0) + emit messageSent(m_msg); + else + emit messageNotSent(m_msg, output.join("\n")); +} + +int SMSClient::maxSize() +{ + return 160; +} + +const QString& SMSClient::description() +{ + QString url = "http://www.smsclient.org"; + m_description = i18n("<qt>SMSClient is a program for sending SMS with the modem. The program can be found on <a href=\"%1\">%1</a></qt>").arg(url).arg(url); + return m_description; +} + +#include "smsclient.moc" +/* + * Local variables: + * c-indentation-style: k&r + * c-basic-offset: 8 + * indent-tabs-mode: t + * End: + */ +// vim: set noet ts=4 sts=4 sw=4: + diff --git a/kopete/protocols/sms/services/smsclient.h b/kopete/protocols/sms/services/smsclient.h new file mode 100644 index 00000000..bc260228 --- /dev/null +++ b/kopete/protocols/sms/services/smsclient.h @@ -0,0 +1,65 @@ +/* ************************************************************************* + * copyright: (C) 2003 Richard Lärkäng <nouseforaname@home.se> * + * copyright: (C) 2003 Gav Wood <gav@kde.org> * + ************************************************************************* +*/ + +/* ************************************************************************* + * * + * 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. * + * * + ************************************************************************* +*/ + +#ifndef SMSCLIENT_H +#define SMSCLIENT_H + +#include "smsservice.h" +#include "kopetemessage.h" + +#include <qobject.h> +#include <qstringlist.h> + +class SMSClientPrefsUI; +class SMSContact; +class QListViewItem; +class KProcess; + +class SMSClient : public SMSService +{ + Q_OBJECT +public: + SMSClient(Kopete::Account* account); + ~SMSClient(); + + void send(const Kopete::Message& msg); + void setWidgetContainer(QWidget* parent, QGridLayout* container); + + int maxSize(); + const QString& description(); + +public slots: + void savePreferences(); + +private slots: + void slotReceivedOutput(KProcess*, char *buffer, int buflen); + void slotSendFinished(KProcess* p); +signals: + void messageSent(const Kopete::Message &); + +private: + QWidget* configureWidget(QWidget* parent); + + SMSClientPrefsUI* prefWidget; + QStringList providers(); + QStringList output; + + Kopete::Message m_msg; + + QString m_description; +} ; + +#endif //SMSCLIENT_H diff --git a/kopete/protocols/sms/services/smsclientprefs.ui b/kopete/protocols/sms/services/smsclientprefs.ui new file mode 100644 index 00000000..363081e3 --- /dev/null +++ b/kopete/protocols/sms/services/smsclientprefs.ui @@ -0,0 +1,135 @@ +<!DOCTYPE UI><UI version="3.1" stdsetdef="1"> +<class>SMSClientPrefsUI</class> +<widget class="QWidget"> + <property name="name"> + <cstring>SMSClientPrefsUI</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>375</width> + <height>168</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <spacer> + <property name="name"> + <cstring>spacer16</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>321</width> + <height>16</height> + </size> + </property> + </spacer> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel8</cstring> + </property> + <property name="font"> + <font> + <bold>1</bold> + </font> + </property> + <property name="text"> + <string>SMSClient Settings</string> + </property> + </widget> + <widget class="Line"> + <property name="name"> + <cstring>line14</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout13</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="text"> + <string>SMSClient &program:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>program</cstring> + </property> + </widget> + <widget class="QLabel" row="2" column="0"> + <property name="name"> + <cstring>textLabel3</cstring> + </property> + <property name="text"> + <string>Pro&vider:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>provider</cstring> + </property> + </widget> + <widget class="KURLRequester" row="0" column="1"> + <property name="name"> + <cstring>program</cstring> + </property> + </widget> + <widget class="KURLRequester" row="1" column="1"> + <property name="name"> + <cstring>configDir</cstring> + </property> + </widget> + <widget class="QComboBox" row="2" column="1"> + <property name="name"> + <cstring>provider</cstring> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="text"> + <string>SMSClient &config path:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>configDir</cstring> + </property> + </widget> + </grid> + </widget> + </vbox> +</widget> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> +</includehints> +</UI> diff --git a/kopete/protocols/sms/services/smssend.cpp b/kopete/protocols/sms/services/smssend.cpp new file mode 100644 index 00000000..f3ea258c --- /dev/null +++ b/kopete/protocols/sms/services/smssend.cpp @@ -0,0 +1,254 @@ +/* ************************************************************************* + * copyright: (C) 2003 Richard L�k�g <nouseforaname@home.se> * + * copyright: (C) 2003 Gav Wood <gav@kde.org> * + ************************************************************************* +*/ + +/* ************************************************************************* + * * + * 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. * + * * + ************************************************************************* +*/ + +#include <qcombobox.h> +#include <qvgroupbox.h> +#include <qlayout.h> +#include <qlabel.h> +#include <qtooltip.h> + +#include <kconfigbase.h> +#include <klineedit.h> +#include <klocale.h> +#include <kurlrequester.h> +#include <kmessagebox.h> +#include <kdebug.h> + +#include "kopeteaccount.h" +#include "kopeteuiglobal.h" + +#include "smssend.h" +#include "smssendprefs.h" +#include "smssendprovider.h" +#include "smsprotocol.h" + +SMSSend::SMSSend(Kopete::Account* account) + : SMSService(account) +{ + kdWarning( 14160 ) << k_funcinfo << " this = " << this << endl; + prefWidget = 0L; + m_provider = 0L; +} + +SMSSend::~SMSSend() +{ +} + +void SMSSend::send(const Kopete::Message& msg) +{ + kdWarning( 14160 ) << k_funcinfo << "m_account = " << m_account << " (should be non-zero!!)" << endl; + QString provider = m_account->configGroup()->readEntry("SMSSend:ProviderName", QString::null); + + if (provider.length() < 1) + { + KMessageBox::error(Kopete::UI::Global::mainWidget(), i18n("No provider configured."), i18n("Could Not Send Message")); + return; + } + + QString prefix = m_account->configGroup()->readEntry("SMSSend:Prefix", QString::null); + if (prefix.isNull()) + { + KMessageBox::error(Kopete::UI::Global::mainWidget(), i18n("No prefix set for SMSSend, please change it in the configuration dialog."), i18n("No Prefix")); + return; + } + + m_provider = new SMSSendProvider(provider, prefix, m_account, this); + + QObject::connect( m_provider, SIGNAL(messageSent(const Kopete::Message &)), this, SIGNAL(messageSent(const Kopete::Message &))); + QObject::connect( m_provider, SIGNAL(messageNotSent(const Kopete::Message &, const QString &)), this, SIGNAL(messageNotSent(const Kopete::Message &, const QString &))); + + m_provider->send(msg); +} + +void SMSSend::setWidgetContainer(QWidget* parent, QGridLayout* layout) +{ + kdWarning( 14160 ) << k_funcinfo << "ml: " << layout << ", " << "mp: " << parent << endl; + m_parent = parent; + m_layout = layout; + + // could end up being deleted twice?? + delete prefWidget; + prefWidget = new SMSSendPrefsUI(parent); + layout->addMultiCellWidget(prefWidget, 0, 1, 0, 1); + + prefWidget->program->setMode(KFile::Directory); + + QString prefix = QString::null; + + if (m_account) + prefix = m_account->configGroup()->readEntry("SMSSend:Prefix", QString::null); + if (prefix.isNull()) + { + QDir d("/usr/share/smssend"); + if (d.exists()) + { + prefix = "/usr"; + } + d = "/usr/local/share/smssend"; + if (d.exists()) + { + prefix="/usr/local"; + } + else + { + prefix="/usr"; + } + } + + QObject::connect (prefWidget->program, SIGNAL(textChanged(const QString &)), + this, SLOT(loadProviders(const QString&))); + + prefWidget->program->setURL(prefix); + + QObject::connect(prefWidget->provider, SIGNAL(activated(const QString &)), + this, SLOT(setOptions(const QString &))); + + prefWidget->show(); +} + +void SMSSend::savePreferences() +{ + if (prefWidget != 0L && m_account != 0L && m_provider != 0L ) + { + m_account->configGroup()->writeEntry("SMSSend:Prefix", prefWidget->program->url()); + m_account->configGroup()->writeEntry("SMSSend:ProviderName", prefWidget->provider->currentText()); + m_provider->save(args); + } +} + +void SMSSend::loadProviders(const QString &prefix) +{ + kdWarning( 14160 ) << k_funcinfo << "m_account = " << m_account << " (should be ok if zero)" << endl; + + QStringList p; + + prefWidget->provider->clear(); + + QDir d(prefix + "/share/smssend"); + if (!d.exists()) + { + setOptions(QString::null); + return; + } + + p = d.entryList("*.sms"); + + d = QDir::homeDirPath()+"/.smssend/"; + + QStringList tmp(d.entryList("*.sms")); + + for (QStringList::Iterator it = tmp.begin(); it != tmp.end(); ++it) + p.prepend(*it); + + for (QStringList::iterator it = p.begin(); it != p.end(); ++it) + (*it).truncate((*it).length()-4); + + prefWidget->provider->insertStringList(p); + + bool found = false; + if (m_account) + { QString pName = m_account->configGroup()->readEntry("SMSSend:ProviderName", QString::null); + for (int i=0; i < prefWidget->provider->count(); i++) + { + if (prefWidget->provider->text(i) == pName) + { + found=true; + prefWidget->provider->setCurrentItem(i); + setOptions(pName); + break; + } + } + } + if (!found) + setOptions(prefWidget->provider->currentText()); +} + +void SMSSend::setOptions(const QString& name) +{ + kdWarning( 14160 ) << k_funcinfo << "m_account = " << m_account << " (should be ok if zero!!)" << endl; + if(!prefWidget) return; // sanity check + + prefWidget->providerLabel->setText(i18n("%1 Settings").arg(name)); + + labels.setAutoDelete(true); + labels.clear(); + args.setAutoDelete(true); + args.clear(); + + if (m_provider) delete m_provider; + m_provider = new SMSSendProvider(name, prefWidget->program->url(), m_account, this); + + for (int i=0; i < m_provider->count(); i++) + { + if (!m_provider->name(i).isNull()) + { + QLabel *l = new QLabel(m_parent); + l->setText("&" + m_provider->name(i) + ":"); + QToolTip::add(l, m_provider->description(i)); + m_layout->addWidget(l, i+2, 0); + KLineEdit *e = new KLineEdit(m_parent); + e->setText(m_provider->value(i)); + m_layout->addWidget(e, i+2, 1); + args.append(e); + labels.append(l); + l->setBuddy(e); + if(m_provider->isHidden(i)) + e->setEchoMode(QLineEdit::Password); + e->show(); + l->show(); + } + } +} +void SMSSend::setAccount(Kopete::Account* account) +{ + m_provider->setAccount(account); + SMSService::setAccount(account); +} + +int SMSSend::maxSize() +{ + kdWarning( 14160 ) << k_funcinfo << "m_account = " << m_account << " (should be non-zero!!)" << endl; + + QString pName = m_account->configGroup()->readEntry("SMSSend:ProviderName", QString::null); + if (pName.length() < 1) + return 160; + QString prefix = m_account->configGroup()->readEntry("SMSSend:Prefix", QString::null); + if (prefix.isNull()) + prefix = "/usr"; + // quick sanity check + if (m_provider) delete m_provider; + m_provider = new SMSSendProvider(pName, prefix, m_account, this); + return m_provider->maxSize(); +} + +const QString& SMSSend::description() +{ + QString url = "http://zekiller.skytech.org/smssend_en.php"; + m_description = i18n("<qt>SMSSend is a program for sending SMS through gateways on the web. It can be found on <a href=\"%1\">%2</a></qt>").arg(url).arg(url); + return m_description; +} + + +#include "smssend.moc" +/* + * Local variables: + * c-indentation-style: k&r + * c-basic-offset: 8 + * indent-tabs-mode: t + * End: + */ +// vim: set noet ts=4 sts=4 sw=4: + diff --git a/kopete/protocols/sms/services/smssend.h b/kopete/protocols/sms/services/smssend.h new file mode 100644 index 00000000..556a21ea --- /dev/null +++ b/kopete/protocols/sms/services/smssend.h @@ -0,0 +1,66 @@ +/* ************************************************************************* + * copyright: (C) 2003 Richard Lärkäng <nouseforaname@home.se> * + * copyright: (C) 2003 Gav Wood <gav@kde.org> * + ************************************************************************* +*/ + +/* ************************************************************************* + * * + * 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. * + * * + ************************************************************************* +*/ + +#ifndef SMSSEND_H +#define SMSSEND_H + +#include <qobject.h> +#include <qmap.h> +#include <qlabel.h> + +#include <klineedit.h> + +#include "smsservice.h" + +class SMSSendProvider; +class SMSSendPrefsUI; +class QListViewItem; +class QGridLayout; + +class SMSSend : public SMSService +{ + Q_OBJECT +public: + SMSSend(Kopete::Account* account); + ~SMSSend(); + + virtual void setAccount(Kopete::Account* account); + + void send(const Kopete::Message& msg); + void setWidgetContainer(QWidget* parent, QGridLayout* container); + + int maxSize(); + const QString& description(); + +public slots: + void savePreferences(); + +private slots: + void setOptions(const QString& name); + void loadProviders(const QString& prefix); +//signals: +// void messageSent(const Kopete::Message&); + +private: + QGridLayout *settingsBoxLayout; + SMSSendProvider* m_provider; + SMSSendPrefsUI* prefWidget; + QPtrList<KLineEdit> args; + QPtrList<QLabel> labels; + QString m_description; +} ; + +#endif //SMSSEND_H diff --git a/kopete/protocols/sms/services/smssendprefs.ui b/kopete/protocols/sms/services/smssendprefs.ui new file mode 100644 index 00000000..faf3a306 --- /dev/null +++ b/kopete/protocols/sms/services/smssendprefs.ui @@ -0,0 +1,188 @@ +<!DOCTYPE UI><UI version="3.1" stdsetdef="1"> +<class>SMSSendPrefsUI</class> +<widget class="QWidget"> + <property name="name"> + <cstring>SMSSendPrefsUI</cstring> + </property> + <property name="geometry"> + <rect> + <x>0</x> + <y>0</y> + <width>338</width> + <height>195</height> + </rect> + </property> + <vbox> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <property name="margin"> + <number>0</number> + </property> + <spacer> + <property name="name"> + <cstring>spacer14</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>311</width> + <height>16</height> + </size> + </property> + </spacer> + <widget class="QLabel"> + <property name="name"> + <cstring>textLabel7_2</cstring> + </property> + <property name="font"> + <font> + <bold>1</bold> + </font> + </property> + <property name="text"> + <string>SMSSend Options</string> + </property> + </widget> + <widget class="Line"> + <property name="name"> + <cstring>line6_2</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + <widget class="QLayoutWidget"> + <property name="name"> + <cstring>layout12</cstring> + </property> + <grid> + <property name="name"> + <cstring>unnamed</cstring> + </property> + <widget class="QComboBox" row="1" column="1"> + <property name="name"> + <cstring>provider</cstring> + </property> + </widget> + <widget class="KURLRequester" row="0" column="1"> + <property name="name"> + <cstring>program</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>7</hsizetype> + <vsizetype>4</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + </widget> + <widget class="QLabel" row="1" column="0"> + <property name="name"> + <cstring>textLabel2</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>4</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>Pro&vider:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>provider</cstring> + </property> + </widget> + <widget class="QLabel" row="0" column="0"> + <property name="name"> + <cstring>textLabel1</cstring> + </property> + <property name="sizePolicy"> + <sizepolicy> + <hsizetype>5</hsizetype> + <vsizetype>4</vsizetype> + <horstretch>0</horstretch> + <verstretch>0</verstretch> + </sizepolicy> + </property> + <property name="text"> + <string>SMSSend prefi&x:</string> + </property> + <property name="buddy" stdset="0"> + <cstring>program</cstring> + </property> + </widget> + </grid> + </widget> + <spacer> + <property name="name"> + <cstring>spacer15</cstring> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + <property name="sizeType"> + <enum>Expanding</enum> + </property> + <property name="sizeHint"> + <size> + <width>351</width> + <height>16</height> + </size> + </property> + </spacer> + <widget class="QLabel"> + <property name="name"> + <cstring>providerLabel</cstring> + </property> + <property name="font"> + <font> + <bold>1</bold> + </font> + </property> + <property name="text"> + <string>Provider Options</string> + </property> + </widget> + <widget class="Line"> + <property name="name"> + <cstring>line6</cstring> + </property> + <property name="frameShape"> + <enum>HLine</enum> + </property> + <property name="frameShadow"> + <enum>Sunken</enum> + </property> + <property name="orientation"> + <enum>Horizontal</enum> + </property> + </widget> + </vbox> +</widget> +<tabstops> + <tabstop>program</tabstop> + <tabstop>provider</tabstop> +</tabstops> +<layoutdefaults spacing="6" margin="11"/> +<includehints> + <includehint>kurlrequester.h</includehint> + <includehint>klineedit.h</includehint> + <includehint>kpushbutton.h</includehint> +</includehints> +</UI> diff --git a/kopete/protocols/sms/services/smssendprovider.cpp b/kopete/protocols/sms/services/smssendprovider.cpp new file mode 100644 index 00000000..82827aab --- /dev/null +++ b/kopete/protocols/sms/services/smssendprovider.cpp @@ -0,0 +1,288 @@ +/* ************************************************************************* + * copyright: (C) 2003 Richard Lärkäng <nouseforaname@home.se> * + * copyright: (C) 2003 Gav Wood <gav@kde.org> * + ************************************************************************* +*/ + +/* ************************************************************************* + * * + * 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. * + * * + ************************************************************************* +*/ + +#include <qvaluelist.h> +#include <qlabel.h> +#include <qfile.h> + +#include <kconfigbase.h> +#include <kprocess.h> +#include <klineedit.h> +#include <kmessagebox.h> +#include <kdebug.h> +#include <klocale.h> + +#include "kopeteaccount.h" +#include "kopeteuiglobal.h" + +#include "smssendprovider.h" +#include "smsprotocol.h" +#include "smscontact.h" + +SMSSendProvider::SMSSendProvider(const QString& providerName, const QString& prefixValue, Kopete::Account* account, QObject* parent, const char *name) + : QObject( parent, name ), m_account(account) +{ + kdWarning( 14160 ) << k_funcinfo << "this = " << this << ", m_account = " << m_account << " (should be ok if zero!!)" << endl; + + provider = providerName; + prefix = prefixValue; + m_maxSize = 160; + + messagePos = -1; + telPos = -1; + + QString file = prefix + "/share/smssend/" + provider + ".sms"; + QFile f(file); + if (f.open(IO_ReadOnly)) + { + QTextStream t(&f); + QString group = QString("SMSSend-%1").arg(provider); + bool exactNumberMatch = false; + QStringList numberWords; + numberWords.append("Tel"); + numberWords.append("Number"); + numberWords.append("number"); + numberWords.append("TelNum"); + numberWords.append("Recipient"); + numberWords.append("Tel1"); + numberWords.append("To"); + numberWords.append("nummer"); + numberWords.append("telefone"); + numberWords.append("ToPhone"); + + while( !t.eof()) + { + QString s = t.readLine(); + if( s[0] == '%') + { + QStringList args = QStringList::split(':',s); + QStringList options = QStringList::split(' ', args[0]); + + names.append(options[0].replace(0,1,"")); + + bool hidden = false; + for(unsigned i = 1; i < options.count(); i++) + if(options[i] == "Hidden") + { hidden = true; + break; + } + isHiddens.append(hidden); + + // Strip trailing whitespace in the end + // and '%' in the beginning + args[0] = args[0].simplifyWhiteSpace().mid(1); + + descriptions.append(args[1]); + if (m_account) + values.append(m_account->configGroup()->readEntry(QString("%1:%2").arg(group).arg(names[names.count()-1]), + QString::null)); + else + values.append(""); + + if( args[0].contains("Message") || args[0].contains("message") + || args[0].contains("message") || args[0].contains("nachricht") + || args[0].contains("Msg") || args[0].contains("Mensagem") ) + { + for( unsigned i = 0; i < options.count(); i++) + { + if (options[i].contains("Size=")) + { + QString option = options[i]; + option.replace(0,5,""); + m_maxSize = option.toInt(); + } + } + messagePos = names.count()-1; + } + else if (!exactNumberMatch) + { + for (QStringList::Iterator it=numberWords.begin(); it != numberWords.end(); ++it) + { + if (args[0].contains(*it)) + { + telPos = names.count() - 1; + if (args[0] == *it) + { +// kdDebug(14160) << "Exact match for " << args[0] << endl; + exactNumberMatch = true; + } +// kdDebug(14160) << "args[0] (" << args[0] << ") contains " << *it << endl; + } + } + } + } + } + } + f.close(); + + if ( messagePos == -1 || telPos == -1 ) + { + canSend = false; + return; + } + + canSend = true; +} + +SMSSendProvider::~SMSSendProvider() +{ + kdWarning( 14160 ) << k_funcinfo << "this = " << this << endl; +} + +void SMSSendProvider::setAccount(Kopete::Account *account) +{ + m_account = account; +} + +const QString& SMSSendProvider::name(int i) +{ + if ( telPos == i || messagePos == i) + return QString::null; + else + return names[i]; +} + +const QString& SMSSendProvider::value(int i) +{ + return values[i]; +} + +const QString& SMSSendProvider::description(int i) +{ + return descriptions[i]; +} + +const bool SMSSendProvider::isHidden(int i) +{ + return isHiddens[i]; +} + +void SMSSendProvider::save(QPtrList<KLineEdit>& args) +{ + kdDebug( 14160 ) << k_funcinfo << "m_account = " << m_account << " (should be non-zero!!)" << endl; + if (!m_account) return; // prevent crash in worst case + + QString group = QString("SMSSend-%1").arg(provider); + int namesI=0; + + for (unsigned i=0; i < args.count(); i++) + { + if (telPos == namesI || messagePos == namesI) + { +// kdDebug(14160) << k_funcinfo << "Skipping pos " << namesI << endl; + namesI++; + if (telPos == namesI || messagePos == namesI) + { +// kdDebug(14160) << k_funcinfo << "Skipping pos " << namesI << endl; + namesI++; + } + } + +// kdDebug(14160) << k_funcinfo << "saving " << args.at(i) << " to " << names[namesI] << endl; + if (!args.at(i)->text().isEmpty()) + { values[namesI] = args.at(i)->text(); + m_account->configGroup()->writeEntry(QString("%1:%2").arg(group).arg(names[namesI]), values[namesI]); + } + namesI++; + } +} + +int SMSSendProvider::count() +{ + return names.count(); +} + +void SMSSendProvider::send(const Kopete::Message& msg) +{ + if ( canSend == false ) + { + if ( messagePos == -1 ) + { + canSend = false; + KMessageBox::error(Kopete::UI::Global::mainWidget(), i18n("Could not determine which argument which should contain the message."), + i18n("Could Not Send Message")); + return; + } + if ( telPos == -1 ) + { + canSend = false; + + KMessageBox::error(Kopete::UI::Global::mainWidget(), i18n("Could not determine which argument which should contain the number."), + i18n("Could Not Send Message")); + return; + } + } + + m_msg = msg; + + QString message = msg.plainBody(); + QString nr = dynamic_cast<SMSContact *>(msg.to().first())->qualifiedNumber(); + + if (canSend = false) + return; + + values[messagePos] = message; + values[telPos] = nr; + + KProcess* p = new KProcess; + + kdWarning( 14160 ) << "Executing " << QString("%1/bin/smssend").arg(prefix) << " \"" << provider << "\" " << values.join("\" \"") << "\"" << endl; + + *p << QString("%1/bin/smssend").arg(prefix) << provider << values; + + output = ""; + connect( p, SIGNAL(processExited(KProcess *)), this, SLOT(slotSendFinished(KProcess *))); + connect( p, SIGNAL(receivedStdout(KProcess *, char *, int)), this, SLOT(slotReceivedOutput(KProcess *, char *, int))); +// connect( p, SIGNAL(receivedStderr(KProcess *, char *, int)), this, SLOT(slotReceivedOutput(KProcess *, char *, int))); + + p->start(KProcess::NotifyOnExit, KProcess::AllOutput); +} + +void SMSSendProvider::slotSendFinished(KProcess *p) +{ + kdWarning( 14160 ) << k_funcinfo << "this = " << this << ", es = " << p->exitStatus() << ", p = " << p << " (should be non-zero!!)" << endl; + if (p->exitStatus() == 0) + emit messageSent(m_msg); + else + emit messageNotSent(m_msg, QString().setLatin1(output)); + + p->deleteLater(); +} + +void SMSSendProvider::slotReceivedOutput(KProcess *, char *buffer, int buflen) +{ +// QStringList lines = QStringList::split("\n", QString::fromLocal8Bit(buffer, buflen)); +// for (QStringList::Iterator it = lines.begin(); it != lines.end(); ++it) + for(int i = 0; i < buflen; i++) + output += buffer[i]; + kdWarning( 14160 ) << k_funcinfo << " output now = " << output << endl; +} + +int SMSSendProvider::maxSize() +{ + return m_maxSize; +} + +#include "smssendprovider.moc" +/* + * Local variables: + * c-indentation-style: k&r + * c-basic-offset: 8 + * indent-tabs-mode: t + * End: + */ +// vim: set noet ts=4 sts=4 sw=4: + diff --git a/kopete/protocols/sms/services/smssendprovider.h b/kopete/protocols/sms/services/smssendprovider.h new file mode 100644 index 00000000..8560be15 --- /dev/null +++ b/kopete/protocols/sms/services/smssendprovider.h @@ -0,0 +1,82 @@ +/* ************************************************************************* + * copyright: (C) 2003 Richard Lärkäng <nouseforaname@home.se> * + * copyright: (C) 2003 Gav Wood <gav@kde.org> * + ************************************************************************* +*/ + +/* ************************************************************************* + * * + * 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. * + * * + ************************************************************************* +*/ + +#ifndef SMSSENDPROVIDER_H +#define SMSSENDPROVIDER_H + +#include <qstring.h> +#include <qstringlist.h> +#include <qptrlist.h> +#include <qlabel.h> +#include <qvaluelist.h> + +#include <klineedit.h> + +#include "kopetemessage.h" + +#include "smsaccount.h" + +class KProcess; +namespace Kopete { class Account; } +class SMSContact; + +class SMSSendProvider : public QObject +{ + Q_OBJECT +public: + SMSSendProvider(const QString& providerName, const QString& prefixValue, Kopete::Account* account, QObject* parent = 0, const char* name = 0); + ~SMSSendProvider(); + + void setAccount(Kopete::Account *account); + + int count(); + const QString& name(int i); + const QString& value(int i); + const QString& description(int i); + const bool isHidden(int i); + + void save(QPtrList<KLineEdit>& args); + void send(const Kopete::Message& msg); + + int maxSize(); +private slots: + void slotReceivedOutput(KProcess*, char *buffer, int buflen); + void slotSendFinished(KProcess*); +private: + QStringList names; + QStringList descriptions; + QStringList values; + QValueList<bool> isHiddens; + + int messagePos; + int telPos; + int m_maxSize; + + QString provider; + QString prefix; + QCString output; + + Kopete::Account* m_account; + + Kopete::Message m_msg; + + bool canSend; +signals: + void messageSent(const Kopete::Message& msg); + void messageNotSent(const Kopete::Message& msg, const QString &error); +} ; + +#endif //SMSSENDPROVIDER_H |