API to access Message entry (SMS, MMS)

7 posts / 0 new
Last post
ezyclie
ezyclie's picture
Offline
Mobile Wizard
Joined: 4 Mar 2010
Posts:
API to access Message entry (SMS, MMS)

Hi,

I think we need API to get access to Message Entry (SMS, MMS, Email, etc) to get/set message details like Subject, Body, Attachment, etc. So we can develop Messaging related Application like Threaded SMS kind of app, Fake SMS application, SMS Backup application, etc

Thanks

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Sam Pickard
rival's picture
Offline
Mobile Archmage
Joined: 19 Mar 2009
Posts:

I think the problems here are around compatibility, when every manufacturer does something different, and security. There is a PIM API for accessing contents, but I don't think that there is a standard method for reading the SMS inbox in J2ME. Sending SMS is already available in MoSync.

I've written a POP3 connector, but it needs some substantial refactoring. If you want POP3 access, then this may help

/*
 * POP3Connection.h
 *
 *  Created on: 9 Feb 2010
 *      Author: sjp
 */

#ifndef POP3CONNECTION_H_
#define POP3CONNECTION_H_
#include <MAUtil/Connection.h>
#include <MAUtil/String.h>
#include <MAUtil/Vector.h>
#include <MAUtil/Map.h>
#include <matime.h>
#include "DataSource.h"

using namespace MAUtil;

//POP states
#define CLOSED -1
#define AUTHORISATION 0
#define TRANSACTION 1

//Operations
#define NULLOP 0
#define SENDUSER 1
#define SENDPASSWORD 2
#define SENDSTAT 3
#define RETRMAIL 4
#define GETMAIL 5
#define MAILCLOSE 6

struct Email
{
  public:
    Map<String, String> headers;
    Vector<String> parts;
};

class POP3Listener
{
  public:
    virtual void emailReceived(Email& m) = 0;
};

class POP3Connection : public ConnectionListener, public DataSource
{
  public:
    POP3Connection(String& server, String& username, String& password, int port = 110);
    ~POP3Connection();

    void getMessages(int max = 10);

    //ConnectionListener
    void connectFinished(Connection* conn, int result);
    void connRecvFinished(Connection* conn, int result);
    void connWriteFinished(Connection* conn, int result);
    void connReadFinished(Connection* conn, int result);

    void addListener(POP3Listener* l);

    void processDataSource();

  private:
    Connection* _conn;
    Vector<POP3Listener*> _listeners;
    Email _mail;
    String _username;
    String _password;
    String _server;

    int _port;
    int _max;
    int _state;
    int _nextop;
    int _highestMailID;
    int _curMailID;
    int _sentInSession;
    time_t _mostRecentSent;
    time_t _mostRecentInSession;

    char _linebuffer[1024];
    String _mBuffer;
    String _boundary;
    bool _inProgress;
    bool _append;
    bool _isMultipart;
    bool _headersFinished;

    void login();
    void error(const char* message);

    void processMail();
    void getMail();
    void getNextResponse();
    void sendCommand(const char* command);

    void processHeaders();
    void processBody();
    //Messages
    void throwMail();

    time_t parseDate(const char* strdate);
};

#endif /* POP3CONNECTION_H_ */
/*
 * POP3Connection.cpp
 *
 *  Created on: 9 Feb 2010
 *      Author: sjp
 */
#include "POP3Connection.h"
#include <mavsprintf.h>
#include <mastring.h>
#include "../std.h"
#include <mastdlib.h>
#include <MAUtil/util.h>
#include <MAP/DateTime.h>
#include "../Utilities/Util.h"

using namespace MAUtil;
using namespace MAPUtil;

POP3Connection::POP3Connection(String& server, String& username, String& password, int port)
{
  _server = server;
  _port = port;
  _username = username;
  _password = password;

  _isMultipart = false;
  _headersFinished = false;
  _append = false;

  _conn = new Connection(this);

  _state = CLOSED;
  _nextop = NULLOP;

  _inProgress = false;
  _mostRecentSent = 0;

  _curMailID = -1;
  _highestMailID = -1;
}

POP3Connection::~POP3Connection()
{
  if(_conn->isOpen())
    _conn->close();

  delete _conn;
}

void POP3Connection::getMessages(int max)
{
  _max = max;
  _sentInSession = 0;
  if(_conn->isOpen() == false)
    login();
}

void POP3Connection::processDataSource()
{
  //Get the updates
  getMessages(5);
}

void POP3Connection::sendCommand(const char* command)
{
  //LOG("Sending command:%s", command);
 // //LOG("Command len %d", strlen(command));
  _conn->write(command, strlen(command));
}

//ConnectionListener
void POP3Connection::connectFinished(Connection* conn, int result)
{
  getNextResponse();
}

void POP3Connection::connWriteFinished(Connection* conn, int result)
{
 // ////lprintfln("Write finished");
  getNextResponse();
}

void POP3Connection::connReadFinished(Connection* conn, int result)
{}

void POP3Connection::connRecvFinished(Connection* conn, int result)
{
 // ////lprintfln("response received");
  ////lprintfln("%s", _linebuffer);
  int ti;
  String ts;
  if(result < 0) {
      //LOG("mConnection.recv failed");
      return;
  }

  if(_inProgress || strncmp(_linebuffer, "+OK", 3) == 0)
  {
    char buffer[255];
    //LOG("NextOP:%d", _nextop);
    switch(_nextop)
    {
        case SENDUSER:
          sprintf(buffer, "USER %s\015\012", _username.c_str());
          _nextop = SENDPASSWORD;
          sendCommand(buffer);
          break;
        case SENDPASSWORD:
          sprintf(buffer, "PASS %s\015\012", _password.c_str());
          _nextop = SENDSTAT;
          sendCommand(buffer);
          break;
        case SENDSTAT:
          _nextop = RETRMAIL;
          sendCommand("STAT\015\012");
          break;
        case RETRMAIL:
          //Get the max mail ID from the response.
          ti = 3; //ignore the first three digits
          while(_linebuffer[ti]==' ') { ti++; } // trim spaces in the beginning
          while(isdigit(_linebuffer[ti]))
          {
            ts.append(&_linebuffer[ti],1);
            ti++;
          }
          _highestMailID = stringToInteger(ts);
          if(_curMailID == -1)
            _curMailID = _highestMailID - _max;

          getMail();
          break;
        case GETMAIL:
          processMail();
          break;
        case MAILCLOSE:
          //LOG("Closing connection");
          _conn->close();
          break;
    }
  }
  else
  {
    error(_linebuffer);
  }
}

void POP3Connection::getNextResponse()
{
  //Clear the buffer
  memset(_linebuffer, 0, 1024);
  _conn->recv(_linebuffer, 1000);
  ////lprintfln("Requested receive");
}

void POP3Connection::login()
{
  if(_conn->isOpen() || _nextop != NULLOP)
    return;
  char buffer[255];
  sprintf(buffer, "socket://%s:%d", _server.c_str(), _port);
  LOG("Connecting to:%s", buffer);
  _nextop = SENDUSER;
  _state = AUTHORISATION;
  int res = _conn->connect(buffer);
  if(res < 0)
    error("Connection failed");
}

void POP3Connection::error(const char* message)
{
  LOG("Error:%s", message);
}

void POP3Connection::getMail()
{
  //Start a new email
  _inProgress = true; //Redirect all responses back to here
  _isMultipart = false;
  _headersFinished = false;
  _append = false;
  _mBuffer.clear();

  //Reset the email
  _mail.headers.clear();
  _mail.parts.clear();

  //Get the next one
  char buffer[255];
  sprintf(buffer, "TOP %d 10\015\012", _curMailID);
  _curMailID++;
  _nextop = GETMAIL;

  sendCommand(buffer);
}

void POP3Connection::processMail()
{
  ////lprintfln("processing mail");
  //Append new data to the buffer
  _mBuffer.append(_linebuffer, strlen(_linebuffer));
  ////lprintfln("last 5: %s", _mBuffer.substr(_mBuffer.length() - 5, 5).c_str());

  String mailend = "\015\012.\015\012";
  if(_mBuffer.find(mailend) >= 0)
  {
    processHeaders();
    processBody();
    throwMail();

    if(_highestMailID == _curMailID)
    {
      //We've finished
      _nextop = MAILCLOSE;
      _mostRecentSent = _mostRecentInSession;
      sendCommand("quit\015\012");
    //  //LOG("Finished");
      _conn->close();
      _nextop = NULLOP;

      //Let the carousel tell the screens they can get new messages
      APPCONTROLLER->getCarousel()->cycleFinished();
    }
    else
    {
      getMail();
    }
  }
  else
  {
   // ////lprintfln("need more data");
    //Get some more data
    getNextResponse();
  }
}

void POP3Connection::processHeaders()
{
 // ////lprintfln("Processing headers");

  String tempBuffer;

  int crlfpair = _mBuffer.find("\015\012\015\012");

  tempBuffer = _mBuffer.substr(0, crlfpair);

  //Remove the headers from the downloaded data
  _mBuffer.remove(0, crlfpair);

  //Split the data by lines
  int nextcrlf = 0;
  String findValue;
  String hName;
  String hValue;
  int colon = tempBuffer.find(": ", 0);
  if(colon > 0)
  {
    ////lprintfln("Getting first header");
    hName = upperString(tempBuffer.substr(0, colon));
   ////lprintfln("First header: %s", header->name.c_str());
    tempBuffer.remove(0, colon + 1);
    while(colon > 0)
    {
      //Need to find the next colon, *after* the next crlf
      nextcrlf = tempBuffer.find("\015\12");
      ////lprintfln("looking for next value");
      colon = tempBuffer.find(": ", nextcrlf);
      if(colon > 0)
      {
        findValue.clear();
        findValue = tempBuffer.substr(0, colon);
        nextcrlf = findValue.findLastOf('\012');
        hValue = findValue.substr(0, nextcrlf);
        ////lprintfln("Value:%s", header->value.c_str());
        trim(hName);
        trim(hValue);
        _mail.headers.insert(hName, hValue);

        nextcrlf += 1;
        hName = upperString(findValue.substr(nextcrlf, colon - nextcrlf));
        ////lprintfln("Next header: %s", header->name.c_str());
        tempBuffer.remove(0, colon+1);
      }
      else
      {
        //remainder is the value
        hValue = tempBuffer;
        ////lprintfln("Final value:%s", header->value.c_str());
        trim(hName);
        trim(hValue);
        _mail.headers.insert(hName, hValue);
      }
    }
  }
}
void POP3Connection::processBody()
{
  //Check to see if this is multipart message
  String ct = _mail.headers["CONTENT-TYPE"];
  //LOG("Content-type:%s", ct.c_str());
  if(ct.find("multipart") > 0)
  {
    _isMultipart = true;
    //Get the boundary message
    _boundary.clear();
    int bstart =ct.findFirstOf('\"') + 1;
    ////lprintfln("Boundary starts at %d", bstart);
    _boundary = ct.substr(
            bstart,
            ct.length() - bstart -2);

    stringSplit(_mBuffer, _boundary, _mail.parts);
  }

  if(!_isMultipart)
  {
   // //LOG("Not multipart");
    _mail.parts.add(_mBuffer);
  }
}

void POP3Connection::throwMail()
{
  LOG("Creating date from '%s'", _mail.headers["DATE"].c_str());
  if(_mail.headers["DATE"].length() > 20)
  {
    DateTime* dt = new DateTime(_mail.headers["DATE"].c_str());

    if(dt->getTicks() > _mostRecentInSession)
       _mostRecentInSession = dt->getTicks();
    LOG("Date created '%s'", sprint_time(dt->getTicks()));

    if(dt->getTicks() > _mostRecentSent)
    {
      Vector_each(POP3Listener*, itr, _listeners)
        (*itr)->emailReceived(_mail);
    }

    delete dt;
  }
}


void POP3Connection::addListener(POP3Listener* l)
{
  _listeners.add(l);
}
ezyclie
ezyclie's picture
Offline
Mobile Wizard
Joined: 4 Mar 2010
Posts:
"rival" wrote:

I think the problems here are around compatibility, when every manufacturer does something different, and security. There is a PIM API for accessing contents, but I don't think that there is a standard method for reading the SMS inbox in J2ME. Sending SMS is already available in MoSync.

Thanks rival, I think we shouldn't support this API for all platforms, we cant sacrificed important/nice feature that is supported for platform A becoz of platform B is not supported. So if its not supported for some platform the API have to return an error code (error code for not supported, eg: "MoSync: Feature not supported -5").

Thanks

Fredrik Eldh
Fredrik's picture
Offline
Mobile Sorcerer
Joined: 16 Feb 2009
Posts:
"ezyclie" wrote:

Thanks rival, I think we shouldn't support this API for all platforms, we cant sacrificed important/nice feature that is supported for platform A becoz of platform B is not supported. So if its not supported for some platform the API have to return an error code (error code for not supported, eg: "MoSync: Feature not supported -5").

Agreed. Incidentally, the error code for not supported is "IOCTL_UNAVAILABLE" (-1). ;)

David Freitas
jddcef's picture
Offline
Mobile Conjurer
Joined: 28 Jul 2011
Posts:

See also: http://www.mosync.com/content/receive-sms
It seems only Android and maybe Symbian or Bada allow for users to read SMS's from the device's current SMS's.

mikewen
mikewen's picture
Offline
Joined: 2 Jan 2012
Posts:

BlackBerry allow listen to incoming SMS as well.

I can post my code if you guys need it.

Chimaobi
Chimaobi's picture
Offline
Joined: 23 Apr 2012
Posts:

Hi mikewen,

Please can you post the code for Blackberry.

Thanks.