From 32a745dd67e394fad6e5d37c9cb97a8f82d04e70 Mon Sep 17 00:00:00 2001
From: Marco Trevisan (Treviño) <mail@3v1n0.net>
Date: Fri, 26 Sep 2008 08:22:15 +0200
Subject: [PATCH] Add support for USSD requests to the network
 Added basic support for Unstructured Supplementary Service Data (USSD) requests
 following the rules stated in 3GPP TS 22.090 document.
 
 This fixes also the dialing of numbers containing '*' or '#' but that don't
 match the USSD rules removing also some duplications of the Qtopia code.
 I've also moved the parsing of these numbers in qmodemcall, this will allow
 to remember these special calls in the dialed numbers (imho it's better, but it
 could be easily moved back to gsmkeyactions).
 
 To support the UCS2 codec (and others I figure), I've added a small workaround to
 make the modem use always the GSM (using the IRA would have been the same) codec
 for placing USSD requests, while it should be able to get them in any format.
 
 This should fix the Openmoko bugs #1226, #1832, #2029.

---
 src/libraries/qtopiaphonemodem/qmodemcall.cpp      |   17 ++++--
 .../qmodemsupplementaryservices.cpp                |   59 ++++++++++++++------
 .../qtopiaphonemodem/qmodemsupplementaryservices.h |    5 +-
 .../telephony/dialfilter/gsm/gsmkeyactions.cpp     |   11 ----
 4 files changed, 57 insertions(+), 35 deletions(-)

diff --git a/src/libraries/qtopiaphonemodem/qmodemcall.cpp b/src/libraries/qtopiaphonemodem/qmodemcall.cpp
index c3a3df2..b58bf56 100644
--- a/src/libraries/qtopiaphonemodem/qmodemcall.cpp
+++ b/src/libraries/qtopiaphonemodem/qmodemcall.cpp
@@ -31,6 +31,7 @@
 #include <qvaluespace.h>
 #include <qtimer.h>
 #include <QApplication>
+#include <QSupplementaryServices>
 
 /*!
     \class QModemCall
@@ -99,6 +100,7 @@ public:
     QModemCallProvider *provider;
     uint modemIdentifier;
     QValueSpaceObject *modemIdObject;
+    QSupplementaryServices *supplementaryService;
 };
 
 /*!
@@ -119,6 +121,7 @@ QModemCall::QModemCall
     d->modemIdentifier = 0;
     d->modemIdObject = new QValueSpaceObject
         ( "/Communications/QPhoneCallProvider/ModemIdentifiers", this );
+    d->supplementaryService = new QSupplementaryServices( "modem", this );
 }
 
 
@@ -142,13 +145,17 @@ void QModemCall::dial( const QDialOptions& options )
     // Assign an identifier to this call.
     setModemIdentifier( provider()->nextModemIdentifier() );
 
-    // If the number starts with '*' or '#', then this is a request
-    // for a supplementary service, not an actual phone call.
+    // If the number starts with some '*' or '#' chars, followed by a "1" and
+    // some other digits and ends with a '#'; or if the number starts with a
+    // "7" followed by another digit, then assume that this is a request for
+    // an Unstructured Supplementary Service to be sent to the network
+    // (according to 3GPP TS 22.090).
     // So we dial and then immediately hang up, allowing the network
     // to send us the SS/USSD response when it is ready.
-    if ( number.startsWith("*") || number.startsWith("#") ) {
-        provider()->atchat()->chat
-            ( provider()->dialServiceCommand( options ) );
+    QRegExp ussd("[*#]{1,3}1[0-9][*+0-9]*#|7[0-9]");
+    if (ussd.exactMatch(number))
+    {
+        d->supplementaryService->sendUnstructuredData( number );
         setState( QPhoneCall::ServiceHangup );
         return;
     }
diff --git a/src/libraries/qtopiaphonemodem/qmodemsupplementaryservices.cpp b/src/libraries/qtopiaphonemodem/qmodemsupplementaryservices.cpp
index ed2921d..a8a72ee 100644
--- a/src/libraries/qtopiaphonemodem/qmodemsupplementaryservices.cpp
+++ b/src/libraries/qtopiaphonemodem/qmodemsupplementaryservices.cpp
@@ -24,6 +24,7 @@
 #include <qatutils.h>
 #include <qatresult.h>
 #include <qtextcodec.h>
+#include <qatresultparser.h>
 
 /*!
     \class QModemSupplementaryServices
@@ -56,6 +57,7 @@ QModemSupplementaryServices::QModemSupplementaryServices
         ( "+CSSU:", this, SLOT(cssu(QString)) );
     service->primaryAtChat()->registerNotificationType
         ( "+CUSD:", this, SLOT(cusd(QString)), true );
+    requestCharset();
 }
 
 /*!
@@ -75,25 +77,20 @@ void QModemSupplementaryServices::cancelUnstructuredSession()
 }
 
 /*!
-    \reimp
+    Do an Unstructured Supplementary Service request using the GSM charset
+    and setting the data coding scheme to 15 (that according to GSM 03.38 it
+    stands for "Language unspecified")
 */
 void QModemSupplementaryServices::sendUnstructuredData( const QString& data )
 {
+    requestCharset();
+    charset = "GSM";
+    service->primaryAtChat()->chat("AT+CSCS=\"" + QAtUtils::quote( charset ) + "\"");
     service->primaryAtChat()->chat
-        ( "AT+CUSD=1,\"" + QAtUtils::quote( data ) + "\"",
+        ( "AT+CUSD=1,\"" + QAtUtils::quote( data ) + "\",15",
           this, SLOT(cusdDone(bool,QAtResult)) );
 }
 
-/*!
-    \reimp
-*/
-void QModemSupplementaryServices::sendSupplementaryServiceData
-        ( const QString& data )
-{
-    service->primaryAtChat()->chat
-        ( "ATD" + data, this, SLOT(atdDone(bool,QAtResult)) );
-}
-
 void QModemSupplementaryServices::resetModem()
 {
     // Turn on [unstructured] supplementary service notifications.
@@ -102,6 +99,12 @@ void QModemSupplementaryServices::resetModem()
 
 }
 
+void QModemSupplementaryServices::requestCharset()
+{
+    service->secondaryAtChat()->chat
+        ( "AT+CSCS?", this, SLOT(cscsDone(bool,QAtResult)) );
+}
+
 void QModemSupplementaryServices::cusdDone( bool, const QAtResult& result )
 {
     emit unstructuredResult( (QTelephony::Result)result.resultCode() );
@@ -112,6 +115,21 @@ void QModemSupplementaryServices::atdDone( bool, const QAtResult& result )
     emit supplementaryServiceResult( (QTelephony::Result)result.resultCode() );
 }
 
+void QModemSupplementaryServices::cscsDone( bool, const QAtResult& result )
+{
+    QAtResultParser cmd( result );
+    cmd.next( "+CSCS:" );
+    QString name = cmd.readString();
+    if ( !name.isEmpty() ) {
+        if (!charset.isEmpty())
+            oldcharset = charset;
+        else
+            oldcharset = name;
+
+        charset = name;
+    }
+}
+
 void QModemSupplementaryServices::cssi( const QString& msg )
 {
     uint posn = 6;
@@ -140,12 +158,17 @@ void QModemSupplementaryServices::cusd( const QString& msg )
     uint posn = 6;
     uint mflag = QAtUtils::parseNumber( msg, posn );
     QString value = QAtUtils::nextString( msg, posn );
-    uint dcs = QAtUtils::parseNumber( msg, posn );
+    QString ussdcharset;
+
+    if (charset != oldcharset) {
+        service->primaryAtChat()->chat("AT+CSCS=\"" + QAtUtils::quote( charset ) + "\"");
+        ussdcharset = oldcharset;
+    } else {
+        ussdcharset = charset;
+    }
+    value = QAtUtils::codec(ussdcharset.toLower())->toUnicode(value.toLatin1());
+    requestCharset();
 
-    /* 00001111 is the default GSM alphabet as of ETSI TS 100 900 V7.2.0 */
-    if (dcs == 15 || dcs == 0)
-        value = QAtUtils::codec("gsm")->toUnicode(value.toLatin1());
-   
-    
     emit unstructuredNotification( (UnstructuredAction)mflag, value );
 }
+
diff --git a/src/libraries/qtopiaphonemodem/qmodemsupplementaryservices.h b/src/libraries/qtopiaphonemodem/qmodemsupplementaryservices.h
index ed46ee4..def9755 100644
--- a/src/libraries/qtopiaphonemodem/qmodemsupplementaryservices.h
+++ b/src/libraries/qtopiaphonemodem/qmodemsupplementaryservices.h
@@ -38,18 +38,21 @@ public:
 public slots:
     void cancelUnstructuredSession();
     void sendUnstructuredData( const QString& data );
-    void sendSupplementaryServiceData( const QString& data );
 
 private slots:
     void resetModem();
+    void requestCharset();
     void cusdDone( bool ok, const QAtResult& result );
     void atdDone( bool ok, const QAtResult& result );
+    void cscsDone( bool ok, const QAtResult& result );
     void cssi( const QString& msg );
     void cssu( const QString& msg );
     void cusd( const QString& msg );
 
 private:
     QModemService *service;
+    QString charset;
+    QString oldcharset;
 };
 
 #endif /* QMODEMSUPPLEMENTARYSERVICES_H */
diff --git a/src/server/phone/telephony/dialfilter/gsm/gsmkeyactions.cpp b/src/server/phone/telephony/dialfilter/gsm/gsmkeyactions.cpp
index 451c659..63104f1 100644
--- a/src/server/phone/telephony/dialfilter/gsm/gsmkeyactions.cpp
+++ b/src/server/phone/telephony/dialfilter/gsm/gsmkeyactions.cpp
@@ -634,17 +634,6 @@ void GsmKeyActions::modifyDial( QDialOptions& options, bool& handledAlready )
         }
     }
     options.setNumber( number );
-
-    // If the number starts with '*' or '#', and ends with a '#', then
-    // assume that this is a supplementary service request to be sent
-    // to the network.  TODO: USSD data?
-    if ( ( number.startsWith( QChar('*') ) ||
-           number.startsWith( QChar('#') ) ) &&
-         number.endsWith( QChar('#') ) ) {
-        d->supp->sendSupplementaryServiceData( number );
-        handledAlready = true;
-        return;
-    }
 }
 
 void GsmKeyActions::filterKeys( const QString& input, bool& filtered )
-- 
1.5.4.3


