⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 gsm_sorted_sms_store.c

📁 这是一款VC++编写的软件
💻 C
字号:
// *************************************************************************
// * GSM TA/ME library
// *
// * File:    gsm_sorted_sms_store.cc
// *
// * Purpose: Sorted SMS store (residing in files or in the ME)
// *
// * Author:  Peter Hofmann (software@pxh.de)
// *
// * Created: 14.8.1999
// *************************************************************************

#ifdef HAVE_CONFIG_H
#include <gsm_config.h>
#endif
#include <gsmlib/gsm_nls.h>
#include <gsmlib/gsm_sysdep.h>
#include <gsmlib/gsm_sorted_sms_store.h>
#include <iostream>
#include <fstream>
#ifdef HAVE_NETINET_IN_H
#include <netinet/in.h>
#endif

using namespace std;
using namespace gsmlib;

// SMS message file format:
// version number of file format, unsigned short int, 2 bytes in network byte
// order
// then comes the message:
// 1. length of PDU (see 4. below): unsigned short int,
//    2 bytes in network byte order
// 2. index of message, unique for this file: unsigned long,
//    4 bytes in network byte order
// 3. MessageType (1 byte), any of:
//    0 SMS_DELIVER
//    1 SMS_SUBMIT
//    2 SMS_STATUS_REPORT
// 4. PDU in hexadecimal format

static const unsigned short int SMS_STORE_FILE_FORMAT_VERSION = 1;

// SortedSMSStore members

// aux function read bytes with error handling
// return false if EOF
static bool readnbytes(string &filename,
                       istream &is, int len, char *buf,
                       bool eofIsError = true) throw(GsmException)
{
  is.read(buf, len);
  if (is.bad() || (is.eof() && eofIsError))
    throw GsmException(stringPrintf(_("error reading from file '%s'"),
                                    (filename == "" ? _("<STDIN>") :
                                     filename.c_str())), OSError);
  return ! is.eof();
}

// aux function write bytes with error handling
static void writenbytes(string &filename, ostream &os,
                        int len, const char *buf) throw(GsmException)
{
  os.write(buf, len);
  if (os.bad())
    throw GsmException(stringPrintf(_("error writing to file '%s'"),
                                    (filename == "" ? _("<STDOUT>") :
                                     filename.c_str())), OSError);
}

void SortedSMSStore::readSMSFile(istream &pbs, string filename)
  throw(GsmException)
{
  char numberBuf[4];

  // check the version
  try
  {
    readnbytes(filename, pbs, 2, numberBuf);
  }
  catch (GsmException &ge)
  {
    // ignore error, file might be empty initially
  }
  unsigned_int_2 version = ntohs(*((unsigned_int_2*)numberBuf));
  if (! pbs.eof() && version != SMS_STORE_FILE_FORMAT_VERSION)
    throw GsmException(stringPrintf(_("file '%s' has wrong version"),
                                    filename.c_str()), ParameterError);

  // read entries
  while (1)
  {
    // read PDU length and exit loop if EOF
    if (! readnbytes(filename, pbs, 2, numberBuf, false))
      break;

    unsigned_int_2 pduLen = ntohs(*((unsigned_int_2*)numberBuf));
    if (pduLen > 500)
      throw GsmException(stringPrintf(_("corrupt SMS store file '%s'"),
                                      filename.c_str()), ParameterError);

    // read index of message
    readnbytes(filename, pbs, 4, numberBuf);
    unsigned_int_4 index = ntohl(*((unsigned_int_4*)numberBuf));
    
    // read message type
    readnbytes(filename, pbs, 1, numberBuf);
    SMSMessage::MessageType messageType =
      (SMSMessage::MessageType)numberBuf[0];
    if (messageType > 2)
      throw GsmException(stringPrintf(_("corrupt SMS store file '%s'"),
                                      filename.c_str()), ParameterError);

    char *pduBuf = (char*)alloca(sizeof(char) * pduLen);

    // read pdu
    readnbytes(filename, pbs, pduLen, pduBuf);
    SMSMessageRef message =
      SMSMessage::decode(string(pduBuf, pduLen),
                         (messageType != SMSMessage::SMS_SUBMIT));
    
    SMSStoreEntry *newEntry = new SMSStoreEntry(message, index);
    _sortedSMSStore.insert(
      SMSStoreMap::value_type(
        SMSMapKey(*this, message->serviceCentreTimestamp()),
        newEntry)
      );

    // update next index (that way only unique indices are generated)
    if (index >= _nextIndex)
      _nextIndex = index + 1;
  }
}

void SortedSMSStore::sync(bool fromDestructor) throw(GsmException)
{
  if (_fromFile && _changed)
  {
    checkReadonly();

    // if writing to stdout and not called from destructor ignore
    // (avoids writing to stdout multiple times)
    if (_filename == "" && ! fromDestructor) return;

    // create backup file - but only once
    if (! _madeBackupFile && _filename != "") // don't make backup of stdout
    {
      renameToBackupFile(_filename);
      _madeBackupFile = true;
    }

    // open stream
    ostream *pbs = NULL;
    try
    {
      if (_filename == "")
        pbs = &cout;
      else
		pbs = new ofstream(_filename.c_str(), ios::out | ios::binary);
      
      if (pbs->bad())
        throw GsmException(
          stringPrintf(_("error opening file '%s' for writing"),
                       (_filename == "" ? _("<STDOUT>") :
                        _filename.c_str())),
          OSError);

      // write version number
      unsigned_int_2 version = htons(SMS_STORE_FILE_FORMAT_VERSION);
      writenbytes(_filename, *pbs, 2, (char*)&version);

      // and write the entries
      for (SMSStoreMap::iterator i = _sortedSMSStore.begin();
           i != _sortedSMSStore.end(); ++i)
      {
        // create PDU and write length
        string pdu = i->second->message()->encode();
        unsigned_int_2 pduLen = htons(pdu.length());
        writenbytes(_filename, *pbs, 2, (char*)&pduLen);

        // write index
        unsigned_int_4 index = htonl(i->second->index());
        writenbytes(_filename, *pbs, 4, (char*)&index);
        
        // write message type
        char messageType = i->second->message()->messageType();
        writenbytes(_filename, *pbs, 1, (char*)&messageType);

        // write PDU
        writenbytes(_filename, *pbs, pdu.length(), pdu.data());
      }
    }
    catch(GsmException &e)
    {
      if (pbs != &cout) delete pbs;
      throw;
    }
    // close file
    if (pbs != &cout) delete pbs;

    _changed = false;
  }
}

void SortedSMSStore::checkReadonly() throw(GsmException)
{
  if (_readonly) throw GsmException(
    _("attempt to change SMS store read from <STDIN>"),
    ParameterError);
}

SortedSMSStore::SortedSMSStore(string filename) throw(GsmException) :
  _changed(false), _fromFile(true), _madeBackupFile(false),
  _sortOrder(ByDate), _readonly(false), _filename(filename), _nextIndex(0)
{
  // open the file
  ifstream pbs(filename.c_str(), ios::in | ios::binary);
  if (pbs.bad())
    throw GsmException(stringPrintf(_("cannot open file '%s'"),
                                    filename.c_str()), OSError);
  // and read the file
  readSMSFile(pbs, filename);
}

SortedSMSStore::SortedSMSStore(bool fromStdin) throw(GsmException) :
  _changed(false), _fromFile(true), _madeBackupFile(false),
  _sortOrder(ByDate), _readonly(fromStdin), _nextIndex(0)
  // _filename is "" - this means stdout
{
  // read from stdin
  if (fromStdin)
    readSMSFile(cin, (string)_("<STDIN>"));
}

SortedSMSStore::SortedSMSStore(SMSStoreRef meSMSStore)
  throw(GsmException) :
  _changed(false), _fromFile(false), _madeBackupFile(false),
  _sortOrder(ByDate), _readonly(false), _meSMSStore(meSMSStore)
{
  // It is necessary to count the entries read because
  // the maximum index into the SMS store may be larger than smsStore.size()
  int entriesRead = 0;
  for (int i = 0;; ++i)
  {
    if (entriesRead == _meSMSStore->size())
      break;                 // ready
    if (! _meSMSStore()[i].empty())
    {
      _sortedSMSStore.insert(
        SMSStoreMap::value_type(
          SMSMapKey(*this,
                    _meSMSStore()[i].message()->serviceCentreTimestamp()),
          &_meSMSStore()[i])
        );
      ++entriesRead;
    }
  }
}

void SortedSMSStore::setSortOrder(SortOrder newOrder)
{
  if (_sortOrder == newOrder) return; // nothing to be done

  SMSStoreMap savedSMSStore = _sortedSMSStore;
  _sortedSMSStore = SMSStoreMap();
  _sortOrder = newOrder;

  switch (newOrder)
  {
  case ByIndex:
  {
    for (SMSStoreMap::iterator i = savedSMSStore.begin();
         i != savedSMSStore.end(); ++i)
      _sortedSMSStore.insert(
        SMSStoreMap::value_type(SMSMapKey(*this, (i->second->index())),
                                i->second));
    break;
  }
  case ByDate:
  {
    for (SMSStoreMap::iterator i = savedSMSStore.begin();
         i != savedSMSStore.end(); ++i)
      _sortedSMSStore.insert(
        SMSStoreMap::value_type(
          SMSMapKey(*this, (i->second->message()->serviceCentreTimestamp())),
          i->second));
    break;
  }
  case ByAddress:
  {
    for (SMSStoreMap::iterator i = savedSMSStore.begin();
         i != savedSMSStore.end(); ++i)
      _sortedSMSStore.insert(
        SMSStoreMap::value_type(
          SMSMapKey(*this, (i->second->message()->address())),
          i->second));
    break;
  }
  case ByType:
  {
    for (SMSStoreMap::iterator i = savedSMSStore.begin();
         i != savedSMSStore.end(); ++i)
      _sortedSMSStore.insert(
        SMSStoreMap::value_type(
          SMSMapKey(*this, (i->second->message()->messageType())),
          i->second));
    break;
  }
  default:
    assert(0);
    break;
  }
}

int SortedSMSStore::max_size() const
{
  if (_fromFile)
    return _sortedSMSStore.max_size();
  else
    return _meSMSStore->max_size();
}

int SortedSMSStore::capacity() const
{
  if (_fromFile)
    return _sortedSMSStore.max_size();
  else
    return _meSMSStore->capacity();
}

SortedSMSStore::iterator
SortedSMSStore::insert(const SMSStoreEntry& x) throw(GsmException)
{
  checkReadonly();
  _changed = true;
  SMSStoreEntry *newEntry;

  if (_fromFile)
    newEntry = new SMSStoreEntry(x.message(), _nextIndex++);
  else
  {
    SMSStoreEntry newMEEntry(x.message());
    newEntry = _meSMSStore->insert(newMEEntry);
  }
  
  switch (_sortOrder)
  {
  case ByIndex:
    return
      _sortedSMSStore.
      insert(SMSStoreMap::value_type(SMSMapKey(*this, newEntry->index()),
                                     newEntry));
    break;
  case ByDate:
    return
      _sortedSMSStore.
      insert(SMSStoreMap::value_type(
        SMSMapKey(*this, newEntry->message()->serviceCentreTimestamp()),
        newEntry));
    break;
  case ByAddress:
    return
      _sortedSMSStore.
      insert(SMSStoreMap::value_type(
        SMSMapKey(*this, newEntry->message()->address()),
        newEntry));
    break;
  case ByType:
    return
      _sortedSMSStore.
      insert(SMSStoreMap::value_type(
        SMSMapKey(*this, newEntry->message()->messageType()),
        newEntry));
    break;
  default:
    assert(0);
    break;
  }
  return SortedSMSStore::iterator();
}

SortedSMSStore::iterator
SortedSMSStore::insert(iterator position, const SMSStoreEntry& x)
  throw(GsmException)
{
  return insert(x);
}

SortedSMSStore::size_type SortedSMSStore::erase(Address &key)
  throw(GsmException)
{
  assert(_sortOrder == ByAddress);

  SMSMapKey mapKey(*this, key);

  // deallocate memory or remove from underlying ME SMS store
  for (SMSStoreMap::iterator i = _sortedSMSStore.find(mapKey);
       i != _sortedSMSStore.end() && i->first == mapKey; ++i)
  {
    checkReadonly();
    _changed = true;
    if (_fromFile)
      delete i->second;
    else
      _meSMSStore->erase((SMSStore::iterator)i->second);
  }

  return _sortedSMSStore.erase(mapKey);
}

SortedSMSStore::size_type SortedSMSStore::erase(int key)
  throw(GsmException)
{
  assert(_sortOrder == ByIndex || _sortOrder == ByType);

  SMSMapKey mapKey(*this, key);

  // deallocate memory or remove from underlying ME SMS store
  for (SMSStoreMap::iterator i = _sortedSMSStore.find(mapKey);
       i != _sortedSMSStore.end() && i->first == mapKey; ++i)
  {
    checkReadonly();
    _changed = true;
    if (_fromFile)
      delete i->second;
    else
      _meSMSStore->erase((SMSStore::iterator)i->second);
  }

  return _sortedSMSStore.erase(mapKey);
}

SortedSMSStore::size_type SortedSMSStore::erase(Timestamp &key)
  throw(GsmException)
{
  assert(_sortOrder == ByDate);

  SMSMapKey mapKey(*this, key);

  // deallocate memory or remove from underlying ME SMS store
  for (SMSStoreMap::iterator i = _sortedSMSStore.find(mapKey);
       i != _sortedSMSStore.end() && i->first == mapKey; ++i)
  {
    checkReadonly();
    _changed = true;
    if (_fromFile)
      delete i->second;
    else
      _meSMSStore->erase((SMSStore::iterator)i->second);
  }

  return _sortedSMSStore.erase(mapKey);
}

void SortedSMSStore::erase(iterator position)
  throw(GsmException)
{
  checkReadonly();
  _changed = true;
  // deallocate memory or remove from underlying ME SMS store
  if (_fromFile)
    delete ((SMSStoreMap::iterator)position)->second;
  else
    _meSMSStore->erase((SMSStore::iterator)
                       ((SMSStoreMap::iterator)position)->second);
  _sortedSMSStore.erase(position);
}

void SortedSMSStore::erase(iterator first, iterator last)
  throw(GsmException)
{
  checkReadonly();
  _changed = true;
  for (SMSStoreMap::iterator i = first; i != last; ++i)
    if (_fromFile)
      delete i->second;
    else
      _meSMSStore->erase((SMSStore::iterator)i->second);
  _sortedSMSStore.erase(first, last);
}

void SortedSMSStore::clear() throw(GsmException)
{
  checkReadonly();
  _changed = true;
  for (iterator i = begin(); i != end(); i++)
    erase(i);
}

SortedSMSStore::~SortedSMSStore()
{
  if (_fromFile)
  {
    sync(true);
    for (SMSStoreMap::iterator i = _sortedSMSStore.begin();
         i != _sortedSMSStore.end(); ++i)
      delete i->second;
  }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -