void TLUserData::write(TLFrame& dest, size_t& wp) const { #if 1 // First write TP-User-Data-Length dest.writeField(wp,mLength,8); // Then write TP-User-Data // This tail() works because UD is always the last field in the PDU. BitVector ud_dest = dest.tail(wp); mRawData.copyTo(ud_dest); ud_dest.LSB8MSB(); #else // Stuff we don't support... assert(!mUDHI); assert(mDCS==0); unsigned numChar = strlen(mData); dest.writeField(wp,numChar,8); // This tail() works because UD is always the last field in the PDU. BitVector chars = dest.tail(wp); chars.zero(); for (unsigned i=0; i<numChar; i++) { char gsm = encodeGSMChar(mData[i]); dest.writeFieldReversed(wp,gsm,7); } chars.LSB8MSB(); #endif }
void TLAddress::write(TLFrame& dest, size_t& wp) const { dest.writeField(wp,mDigits.size(),8); dest.writeField(wp, 0x01, 1); dest.writeField(wp, mType, 3); dest.writeField(wp, mPlan, 4); mDigits.write(dest,wp); }
void TLDeliver::writeBody(TLFrame& dest, size_t& wp) const { writeMMS(dest); writeRP(dest); writeUDHI(dest, mUD.UDHI()); writeSRI(dest); mOA.write(dest,wp); dest.writeField(wp,mPID,8); dest.writeField(wp,mUD.DCS(),8); mSCTS.write(dest,wp); writeUnused(dest); mUD.write(dest,wp); }
// (pat) See 3GPP 3.40 9.2.2 void TLDeliver::writeBody(TLFrame& dest, size_t& wp) const { writeMMS(dest); // more messages to send bit. writeRP(dest); // reply path bit. writeUDHI(dest, mUD.UDHI()); // User-data-header-indicator bit writeSRI(dest); // status-report-indication bit mOA.write(dest,wp); // originating address dest.writeField(wp,mPID,8); // protocol id dest.writeField(wp,mUD.DCS(),8); // Data-coding-scheme mSCTS.write(dest,wp); // service-centre-time-stamp writeUnused(dest); // user-data-length. (pat) Why empty? mUD.write(dest,wp); // user data. }
/** Parse a TL address field, including length. */ void TLAddress::parse(const TLFrame& src, size_t& rp) { // GSM 03.40. // This is different from the BCD formats in GSM 04.08, // even though it looks very similar. // The difference is in the encoding of the length field. size_t numDigits = src.readField(rp,8); size_t length = numDigits/2 + (numDigits % 2); if (src.readField(rp, 1) != 1) SMS_READ_ERROR; mType = (TypeOfNumber)src.readField(rp, 3); mPlan = (NumberingPlan)src.readField(rp, 4); mDigits.parse(src,rp,length); }
void TLUserData::parse(const TLFrame& src, size_t& rp) { // The DCS is defined in GSM 03.38 4. assert(mDCS<0x100); // Someone forgot to initialize the DCS. // TP-User-Data-Length mLength = src.readField(rp,8); #if 1 // This tail() works because UD is always the last field in the PDU. mRawData.clone(src.tail(rp)); // Should we do this here? mRawData.LSB8MSB(); #else assert(!mUDHI); // We don't support user headers. switch (mDCS) { case 0: case 244: case 245: case 246: case 247: { // GSM 7-bit encoding, GSM 03.38 6. // Check bounds. if (numChar*7 > (src.size()-rp)) { LOG(NOTICE) << "badly formatted TL-UD"; SMS_READ_ERROR; } BitVector chars(src.tail(rp)); chars.LSB8MSB(); size_t crp=0; for (unsigned i=0; i<numChar; i++) { char gsm = chars.readFieldReversed(crp,7); mData[i] = decodeGSMChar(gsm); } mData[numChar]='\0'; if (crp%8) crp += 8 - crp%8; rp += crp; return; } default: { rp += numChar; sprintf(mData,"unsupported DCS 0x%x", mDCS); LOG(NOTICE) << mData; SMS_READ_ERROR; } } #endif }
void TLMessage::write(TLFrame& dest) const { dest.resize(bitsNeeded()); size_t wp=8; writeMTI(dest); writeBody(dest,wp); }
void TLSubmit::parseBody(const TLFrame& src, size_t& rp) { parseRD(src); parseVPF(src); parseRP(src); parseUDHI(src); parseSRR(src); mMR = src.readField(rp,8); mDA.parse(src,rp); mPI = src.readField(rp,8); mDCS = src.readField(rp,8); mVP.VPF(mVPF); mVP.parse(src,rp); mUD.DCS(mDCS); mUD.parse(src,rp); }
void TLUserData::write(TLFrame& dest, size_t& wp) const { // Stuff we don't support... assert(!mUDHI); assert(mDCS==0); unsigned numChar = strlen(mData); dest.writeField(wp,numChar,8); // This tail() works because UD is always the last field in the PDU. BitVector chars = dest.tail(wp); chars.zero(); for (unsigned i=0; i<numChar; i++) { char gsm = encodeGSMChar(mData[i]); dest.writeFieldReversed(wp,gsm,7); } chars.LSB8MSB(); }
void TLDeliver::parseBody(const TLFrame &src, size_t &rp) { // Note that offset is reversed, i'=7-i. // Ignore MTI, we already know it is DELIVER. // Note that these header fields come from src ignoring rp. parseMMS(src); parseRP(src); parseUDHI(src); parseSRI(src); // Now the 'body' assert(rp == 8); mOA.parse(src,rp); // originating address. mPID = src.readField(rp,8); // protocol id mUD.DCS(src.readField(rp,8)); // data coding scheme, stored in the TLUserData. mSCTS.parse(src,rp); // time stamp mUD.parse(src,rp); // user data. }
void TLSubmit::parseBody(const TLFrame& src, size_t& rp) { bool udhi; parseRD(src); parseVPF(src); parseRP(src); udhi = parseUDHI(src); parseSRR(src); mMR = src.readField(rp,8); mDA.parse(src,rp); //LOG(DEBUG) << "Destination " << mDA.digits(); mPI = src.readField(rp,8); mDCS = src.readField(rp,8); mVP.VPF(mVPF); mVP.parse(src,rp); mUD.DCS(mDCS); mUD.UDHI(udhi); mUD.parse(src,rp); }
void TLUserData::parse(const TLFrame& src, size_t& rp) { assert(!mUDHI); // We don't support user headers. // The DCS is defined in GSM 03.38 4. assert(mDCS<0x100); // Someone forgot to initialize the DCS. unsigned numChar = src.readField(rp,8); switch (mDCS) { case 0: case 244: case 245: case 246: case 247: { // GSM 7-bit encoding, GSM 03.38 6. // Check bounds. if (numChar*7 > (src.size()-rp)) { LOG(NOTICE) << "badly formatted TL-UD"; SMS_READ_ERROR; } BitVector chars(src.tail(rp)); chars.LSB8MSB(); size_t crp=0; for (unsigned i=0; i<numChar; i++) { char gsm = chars.readFieldReversed(crp,7); mData[i] = decodeGSMChar(gsm); } mData[numChar]='\0'; if (crp%8) crp += 8 - crp%8; rp += crp; return; } default: { rp += numChar; sprintf(mData,"unsupported DCS 0x%x", mDCS); LOG(NOTICE) << mData; SMS_READ_ERROR; } } }
void TLValidityPeriod::write(TLFrame& dest, size_t& wp) const { if (mVPF==0) return; // We only support VPF==1. assert(mVPF==1); int seconds = mExpiration.seconds() - time(NULL); int minutes = seconds/60; if (minutes<1) minutes=1; unsigned vp; if (minutes<=720) vp = (minutes-1)/5; else if (minutes<1440) vp = 143 + (minutes-720)/30; else if (minutes<43200) vp = 166 + minutes/(24*60); else vp = 192 + minutes/(7*24*60); if (vp>255) vp=255; dest.writeField(wp,vp,8); }
void TLValidityPeriod::parse(const TLFrame& src, size_t& rp) { // FIXME -- Check remaining message length before reading!! LOG(DEBUG) << "SMS: TLValidityPeriod::parse VPF=" << mVPF; switch (mVPF) { case 2: { // Relative format. // GSM 03.40 9.2.3.12.1 unsigned vp = src.readField(rp,8); unsigned minutes = 0; if (vp<144) minutes = (vp+1)*5; else if (vp<168) minutes = 12*60 + (vp-143)*30; else if (vp<197) minutes = 24*60*(vp-166); else minutes = 7*24*60*(vp-192); mExpiration = Timeval(); mExpiration.addMinutes(minutes); return; } case 3: { // Absolute format, borrowed from GSM 04.08 MM // GSM 03.40 9.2.3.12.2 L3TimeZoneAndTime decoder; decoder.parseV((TLFrame)(BitVector)src,rp); mExpiration = decoder.time(); return; } case 1: // Enhanced format. // GSM 03.40 9.2.3.12.3 LOG(NOTICE) << "SMS: ignoring grossly complex \"enhanced\" TP-VP and assuming 1 week."; rp += 7; // fall through... case 0: // No validity period field. LOG(DEBUG) << "SMS: no validity period, assuming 1 week"; mExpiration = Timeval(7*24*60*60*1000); return; default: assert(0); // someone forgot to initialize the VPF } }