/* * Copyright 2008, 2014 Free Software Foundation, Inc. * Copyright 2014 Range Networks, Inc. * * This software is distributed under multiple licenses; see the COPYING file in the main directory for licensing information for this specific distribution. * * This use of this software may be subject to additional restrictions. * See the LEGAL file in the main directory for details. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. */ /* As a simplification, we are supporting only the default 7-bit alphabet. */ #ifndef SMS_MESSAGE_H #define SMS_MESSAGE_H #include #include "SMSTransfer.h" #include #include #include #include namespace SMS { class SMSReadError : public GSM::GSMError { public: SMSReadError():GSMError() {} }; #define SMS_READ_ERROR {throw SMSReadError();} /**@name SMS Transport Layer (TL) */ //@{ // FIXME -- All parsers for TL messages and elements should return a success/fail indication. /**@name Elements for SMS Transport Layer (TL) */ //@{ /** A base class for elements of GSM 03.40 9.1.2 and 9.2.3 */ class TLElement { public: virtual ~TLElement() {} virtual size_t length() const =0; virtual void parse(const TLFrame&, size_t&) =0; virtual void write(TLFrame&, size_t&) const =0; virtual void text(std::ostream&) const {} }; std::ostream& operator<<(std::ostream& os, const TLElement& msg); /** GSM 03.40 9.1.2.5 This is very similar to a Q.931-style BCD number. Especially since we don't support non-numeric addresses. */ class TLAddress : public TLElement { private: GSM::TypeOfNumber mType; // International and other flags GSM::NumberingPlan mPlan; GSM::L3BCDDigits mDigits; public: TLAddress():TLElement() {} TLAddress(GSM::TypeOfNumber wType, GSM::NumberingPlan wPlan, const char* wDigits) :TLElement(), mPlan(wPlan), mDigits(wDigits) { mType = (wDigits[0] == '+') ? GSM::InternationalNumber : GSM::NationalNumber; LOG(DEBUG) << "TLaddrress ctor type=" << mType << " Digits " << wDigits; } TLAddress(const char* wDigits) :TLElement(), mPlan(GSM::E164Plan), mDigits(wDigits) { mType = (wDigits[0] == '+') ? GSM::InternationalNumber : GSM::NationalNumber; LOG(DEBUG) << "TLaddrress ctor type=" << mType << " Digits " << wDigits; } const char *digits() const { return mDigits.digits(); } GSM::TypeOfNumber type() const { return mType; } GSM::NumberingPlan plan() const { return mPlan; } size_t length() const { return 2 + mDigits.lengthV(); } void parse(const TLFrame&, size_t&); void write(TLFrame&, size_t&) const; void text(std::ostream&) const; }; /** GSM 03.40 9.2.3.12 */ class TLValidityPeriod : public TLElement { private: unsigned mVPF; Timeval mExpiration; public: /** Default validity period of one week, no format specified. */ TLValidityPeriod(unsigned wVPF=0xFF) :TLElement(), mVPF(wVPF), mExpiration(7*24*60*60*1000) { } void VPF(unsigned wVPF) { mVPF=wVPF; } size_t length() const; void parse(const TLFrame&, size_t&); void write(TLFrame&, size_t&) const; void text(std::ostream&) const; }; class TLTimestamp : public TLElement { private: GSM::L3TimeZoneAndTime mTime; public: const Timeval& time() const { return mTime.time(); } void time(const Timeval& wTime) { mTime.time(wTime); } size_t length() const { return mTime.lengthV(); } void write(TLFrame& dest, size_t& wp) const { mTime.writeV((GSM::L3Frame&)(BitVector2&)dest, wp); } void parse(const TLFrame& src, size_t& rp) { mTime.parseV((GSM::L3Frame&)(BitVector2&)src, rp); } void text(std::ostream&os) const; }; /** GSM 03.40 9.2.3.24 */ class TLUserData : public TLElement { private: unsigned mDCS; ///< data coding scheme bool mUDHI; ///< header indicator unsigned mLength; ///< TP-User-Data-Length, see GSM 03.40 Fig. 9.2.3.24(a), ///< GSM 03.40 Fig. 9.2.3.24(b) and GSM 03.40 9.2.3.16. BitVector2 mRawData; ///< raw packed data public: /** Initialize the DCS with a non-valid value. */ TLUserData(unsigned wDCS=0x100, bool wUDHI=false) :TLElement(), mDCS(wDCS), mUDHI(wUDHI), mLength(0) { } /** Initialize from a raw encoded data. */ TLUserData(unsigned wDCS, const BitVector2 wRawData, unsigned wLength, bool wUDHI=false) :TLElement(), mDCS(wDCS), mUDHI(wUDHI), mLength(wLength) { mRawData.clone(wRawData); } /** Initialize from a simple C string. */ TLUserData(const char* text, GSM::GSMAlphabet alphabet=GSM::ALPHABET_7BIT, bool wUDHI=false) :TLElement(), mDCS(0), mUDHI(wUDHI), mLength(0) { switch(alphabet) { case GSM::ALPHABET_7BIT: encode7bit(text); break; case GSM::ALPHABET_8BIT: case GSM::ALPHABET_UCS2: default: //LOG(WARNING) << "Unsupported alphabet: " << alphabet; break; } } void DCS(unsigned wDCS) { mDCS=wDCS; } unsigned DCS() const { return mDCS; } void UDHI(unsigned wUDHI) { mUDHI=wUDHI; } unsigned UDHI() const { return mUDHI; } /** Encode text into this element, using 7-bit alphabet */ void encode7bit(const char *text); /** Decode text from this element, using 7-bit alphabet */ std::string decode() const; /** This length includes a byte for the length field. */ size_t length() const; /** Parse, including the initial length byte. */ void parse(const TLFrame&, size_t&); void write(TLFrame&, size_t&) const; void text(std::ostream&) const; }; //@} // SMS TL Elements /**@name Messages for SMS Transport Layer (TL) */ //@{ /** GSM 03.40 9.2 */ class TLMessage { protected: /**@name Standard TLheader bits from GSM 03.40 9.2.3. - 0 MTI (9.2.3.1) - 1 MTI - 2 MMS (9.2.3.2), RD (9.2.3.25) - 3 VPF (9.2.3.3) - 4 VPF - 5 SRI (9.2.3.4), SRR (9.2.3.5), SRQ (9.2.3.26) - 6 UDHI (9.2.3.23) - 7 RP (9.2.3.17) */ //@{ bool mMMS; ///< more messages to send (reversed-sense) bool mRD; ///< reject duplicates unsigned mVPF; ///< validity period format bool mSRR; ///< status report request bool mSRI; ///< status report indication bool mSRQ; ///< status report qualifier bool mUDHI; ///< user-data header-indicator bool mRP; ///< reply path //@} public: /** Maximum size of user data field. */ static const unsigned maxData = 160; /** GSM 03.40 9.2.3.1 */ enum MessageType { DELIVER = 0x0, // SC -> MS DELIVER_REPORT = 0x0, // MS -> SC STATUS_REPORT = 0x2, // SC -> MS COMMAND = 0x02, // MS -> SC SUBMIT = 0x1, // MS -> SC SUBMIT_REPORT = 0x1 // SC -> MS }; TLMessage() :mMMS(true),mSRI(false),mRP(false) {} virtual ~TLMessage(){} virtual int MTI() const=0; /** The bodyLength is everything beyond the header byte. */ virtual size_t l2BodyLength() const = 0; virtual size_t length() const { return 1+l2BodyLength(); } size_t bitsNeeded() const { return length()*8; } virtual void parse( const TLFrame& frame ); virtual void parseBody( const TLFrame& frame, size_t &rp) =0; virtual void write( TLFrame& frame ) const; virtual void writeBody( TLFrame& frame, size_t &rp) const =0; virtual void text(std::ostream& os) const { os << "MTI="<