continua (next page) Index of UNOFFICIAL Circumvesuviana Home Page Linux pages main index Clamoroso: l'ho fatto! Sono finalmente riuscito a prelevare i messaggi SMS dal mio telechiodo Nokia 7110 via porta IrDA sul mio arcipotenziatissimo notebook. Qui sotto, il sorgente in C del programma. Buon divertimento!
N.B.: per ora (e per chissà quant'altro tempo) non sono disposto a meglio documentare e meglio umanamente interfacciare alcunché, per cui rinvio volentieri alla poderosa gsmlib per qualsiasi uso più serio.



YES, I did it! I finally could download, in the (almost) simplest manner, the SMS messages from my Nokia 7110 via IrDA port on my extremely powerful notebook. Below, the C source. Have fun! (note: if you don't want to fiddle with sources and IrDA stuff, you may want to have a look to a true GSM-phone utility package).

//
//      nokia7110getsms.c
//         created:      2001-05-21
//         updated:      2002-02-27
//         last update:  2002-07-08 also for Nokia 6310i (see below)
//
//      http://www.alfonsomartone.itb.it
//      gets SMS messages from Nokia 7110 to stdout
//      under GNU (GPL) license
//
//      WARNING: stuff for programmers only; I don't make any warranty;
//
//      quick notes:
//
//      1)  almost all information is taken from gsmlib 1.6 source;
//          the gsmlib is at least 100 times better than my source,
//          (Peter Hoffman, http://pxh.de, is a TRUE programmer!!!)
//          but it reads only SiMcard messages;
//
//      2)  the information that is not from gsmlib was obtained just by
//          trial and error. That is, using a terminal program (xminicom)
//          I tried "AT+CGMS?" and "AT+CGMS=?" standard ETSI sequences
//          and discovered how to use the +CMGS command on the 7110
//          (that sounds a little different from original ETSI specs
//          on which gsmlib is based);
//
//      3)  the program relies on a standard IrCOMM port (that is, you need
//          to add _lots_ of termios stuff to get it running on a standard
//          serial port): on IrDA, I just hadn't to set up things like
//          handshaking, port speed, etc. Tested under Linux 2.4.4 up to
//          Linux 2.4.21: it works!
//
//      4)  greatest known bugs: some connection errors (maybe you have to
//          run xminicom to flush IrDA serial buffers); sometimes, stored
//          SMS messages or received multipart (hex-only) messages will
//          be read untraslated by program!!! you have to clear them by
//          hand on the phone.
//          another weird-WEIRD-weird problem: dunnowhy, the 7110 reenables
//          echo frequently (so I have to use "ate0" command frequently).
//
//   build: cc -O2 nokia7110getsms.c -o nokia7110getsms
//          strip -s -R .comment -R .note nokia7110getsms
//
//   usage: nokia7110getsms /dev/ircomm0            gets received-read SMS's
//          nokia7110getsms /dev/ircomm0 sto        gets stored-sent SMS's
//
// ----------------------------------------------------------------------------
// config options

#ifndef  TIMEOUT
#define  TIMEOUT  270             // timeout in jiffies after an AT command
#endif

// debugging (should be undefined)
//
//efine DO_NOT_DELETE_SMS        // if defined, do not delete any SMS message
#define  ONLY_SMS_FROM_2000_A_D   // ifdef'd, exclude messages before 1-1-2000

// end of configurable options
// ----------------------------------------------------------------------------

#define _ { fprintf(stderr,"%s:%d (%s)\n",__FILE__,__LINE__,__FUNCTION__); }

#include <stdio.h>
#include <time.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/times.h>

#define jiffies()  times((struct tms*)NULL)         // eeeeyow!!!!
#define schedule() usleep(5000)                     // slurp!!!


int modem;                   //  YES, I also hate global vars, but I wanted to
static char buf[1024];       //    complete this program in less than 2 hours!

char *recread="+CMGR: \"REC READ\"";             // response string
int rcv=1;

int check(char *buf, char *str, int bufsiz)      // returns 1 if str is in buf
{                                                //   (tests begin at buf end)
  int len=strlen(str), k=bufsiz-len;
  if(k<0) return 0;                              // I know this func is an
  while(k>=0)                                    //   ugly hack, but I wanted
  {                                              //   to be REALLY sure of
    if(!strncmp(buf+k, str, len)) return 1;      //   what I was doing!
    k--;                                         // it's not really nice to
  }                                              //   find out a nasty bug
  return 0;                                      //   at 5:54am! :-(
}


void mwrite(int modem, char *s, int len)  // modem paced write
{
  while(len--)                            // strange, eh? some releases of
  {                                       //   Linux IrDA stack were able
    write(modem, s++, 1);                 //   to use standard "write"
    fsync(modem);                         //   instead of this paced write
  }                                       //   function; this weird hack is
}                                         //   to get it running everywhere


int command(char *cmd)       //  send a command to the modem; return 0 if "OK"
{                            //    return 1 if local err; exit prog if timeout
  char *p=buf;
  int n;

  while(read(modem,p,1)==1);            // paranoid flush
  memset(buf, 0, sizeof(buf));          // clear response buffer
  mwrite(modem, cmd, strlen(cmd));      // send command
  mwrite(modem, "\r", 1);               // send "Enter" at the end
  schedule();                           // yield for a moment before reading
  n=jiffies();
  for(;;)
  {
    while(read(modem, p, 1)==1) p++;    // get any chars

    if(check(buf,"\r\n+CMS ERROR: 321\r\n", p-buf))     // check AT+CMGR errs
    {
      schedule();
      while(read(modem,p,1)==1);        // flush buffer
      return 1;
    }

    if(check(buf,"\r\nOK\r\n", p-buf))  // got final OK?
    {
      schedule();
      while(read(modem,p,1)==1);        // flush buffer
      break;
    }

    if(jiffies()-n>TIMEOUT)             // check for timeout
    {
      if(*buf)
        fprintf(stderr, "\n\ntimeout while waiting '%s', exiting;"
                        " last error:\n%s\n\n", cmd, buf);
      else
        fprintf(stderr, "\n\ntimeout while waiting '%s', exiting...\n\n", cmd);
      exit(1);
    }

    schedule();                         // be nice with the operating system
  }

  return 0;
}


void readmsg(int n)    //  read SMS from mobilephone and xlate accented vowels
{
  char cmd[50], *p=buf, num[50], *q=num, dat[50], *r=dat, msg[5000], *s=msg;

// fill this table for your needs... currently there are only Italian accents
  char chars[]={ '@', '', '$', '', '', '', '', '', '', '',
                 ' ', '', '', ' ', '', '', '', '', '', '',
                 '', '', '', '', '', '', '', '', '', '', '', '' };

  char chars2[]={ '', '', '', '' };

  fprintf(stderr, ">%d \r", n);

  sprintf(cmd, "at+cmgr=%d", n);                  // read message n

  schedule();                                     // be nice with the OS

  command("ate0");    // because of a 7110 v4.84 firmware bug: get rid of echo

  if(command(cmd)) return;

//{ int i=command(cmd);
//if(!i) eutput(n,i,buf);  // debug what did we get from the phone
//if(i) return; }

  while(*p=='\r' || *p=='\n') p++;                // skip useless cr/lf's
  if(strncmp(p,recread,strlen(recread))) return;  // accept only selected msgs
  memset(msg, 0, sizeof(msg));
  while(*p!=',') p++;                             // skip sto/sent or rec/read
  for(p++,p++; *p!='"';) *q++=*p++;               // fetch receiver number
  if(rcv)
  {                                               // fetch date if rec/read
    for(*q='\0', p++; *p!='"'; p++);
    for(p++; *p!='"'; p++) *r++=*p==','?' ':(*p=='/'?'-':*p);
  }
  else
  {
    time_t tt;
    struct tm *t;
    time(&tt);
    t=localtime(&tt);
    sprintf(dat, "%02d-%02d-%02d.%02d:%02d:%02d", t->tm_year-100,
      t->tm_mon+1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec);
  }

  while(*p!='\r') p++;                         // skip everything up to eol

  while(*p=='\r' || *p=='\n') p++;             // does anyone remember ye olde
  for(;strncmp(p,"\r\n\r\n",4); p++)           //   Obfuscated C Code Contest?
    *s++=*p<0 ?'?': (*p<' '?chars[(unsigned)*p]:
      ((*p<0x7b||*p>0x7e)?*p:chars2[(unsigned)*p-0x7b]));

#ifdef ONLY_SMS_FROM_2000_A_D
  if(*dat!='0') return;  // exclude messages before 2000 and after 2009
#endif

  if(!isatty(fileno(stdout)))
    fprintf(stderr, "%2d:  20%-17.17s  %-16.16s  %-29.29s...\n",n,dat,num,msg);

  printf("20%-17.17s  %-16.16s  %s\n", dat, num, msg);  // output to stdout

#ifndef DO_NOT_DELETE_SMS
  sprintf(cmd, "at+cmgd=%d", n);                        // delete message
  command(cmd);
#endif
}


int main(int argc, char **argv)                         // whoopeee!
{
  int n;
  char buf[200];

  if((argc!=2 && argc!=3) || (modem=open(argv[1], O_RDWR|O_NDELAY))<0)
  {
    fprintf(stderr,
      "\nusage: %s /dev/modemfilename [sentflag]\n\n",
        argv[0]);
    return 1;
  }

  if(argc==3)     // well, one day I will check what was the 3rd arg... :-)
  {
    // "+CMGR: \"STO UNSENT\"         // get stored/unsent SMS's

    recread="+CMGR: \"STO SENT\"";                         // get stored-sent
    fprintf(stderr,"reading stored/sent messages...\n");
    rcv=0;
  }

  mwrite(modem, "\r", 1);
  fsync(modem);
  schedule();
  while(read(modem, &n, 1)==1);                 // forget rubbish

  fprintf(stderr, ">\r");
  fflush(stderr);

  command("atz");                               // init modem
  command("ate0");                              // don't want command echo
  command("at+cmgf=1");                         // use ascii (non-PDU) mode
  command("at+cscs=\"GSM\"");                   // use GSM character set

  command("at+cpms=\"SM\",\"SM\",\"SM\"");      // select SiMcard messages
  for(n=1; n<=10; n++) readmsg(n);

  command("at+cpms=\"ME\",\"ME\",\"SM\"");      // select MEmory messages
  for(n=1; n<=50; n++) readmsg(n);

  // --- a little important note from Vicente ("QuasaR!") from Espaa: ---
  // if you want to use this program with Nokia 6310i, please suppress in
  // the above AT+CPMS commands the third parameter; that is, change to:
  //    command("at+cpms=\"SM\",\"SM\"");
  //    ...
  //    command("at+cpms=\"ME\",\"ME\"");
  // --- so it'll work perfectly under Linux 2.4.18 on the Nokia 6310i ---

  fprintf(stderr, ">ok\n");

  command("atz");                               // reset modem before exit
  return 0;
}
// --- the end. Below, a great shot of Positano from Santa Maria del Castello

Click here for index page.

send e-mail - continua (next page)