summaryrefslogtreecommitdiffstats
path: root/kopete/protocols/sms/services
diff options
context:
space:
mode:
Diffstat (limited to 'kopete/protocols/sms/services')
-rw-r--r--kopete/protocols/sms/services/Makefile.am18
-rw-r--r--kopete/protocols/sms/services/gsmlib.cpp462
-rw-r--r--kopete/protocols/sms/services/gsmlib.h151
-rw-r--r--kopete/protocols/sms/services/gsmlibprefs.ui100
-rw-r--r--kopete/protocols/sms/services/kopete_unix_serial.cpp445
-rw-r--r--kopete/protocols/sms/services/kopete_unix_serial.h70
-rw-r--r--kopete/protocols/sms/services/smsclient.cpp192
-rw-r--r--kopete/protocols/sms/services/smsclient.h65
-rw-r--r--kopete/protocols/sms/services/smsclientprefs.ui135
-rw-r--r--kopete/protocols/sms/services/smssend.cpp254
-rw-r--r--kopete/protocols/sms/services/smssend.h66
-rw-r--r--kopete/protocols/sms/services/smssendprefs.ui188
-rw-r--r--kopete/protocols/sms/services/smssendprovider.cpp288
-rw-r--r--kopete/protocols/sms/services/smssendprovider.h82
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 &amp;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&amp;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 &amp;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&amp;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&amp;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