Logo Search packages:      
Sourcecode: smstools version File versions

putsms.c

/*
SMS Server Tools
Copyright (C) Stefan Frings

This program is free software unless you got it under another license directly
from the author. You can redistribute it and/or modify it under the terms of
the GNU General Public License as published by the Free Software Foundation.
Either version 2 of the License, or (at your option) any later version.

http://www.meinemullemaus.de/
mailto: smstools@meinemullemaus.de
*/

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <syslog.h>
#include "charset.h"
#include "version.h"
#include "modeminit.h"
#include "logging.h"
#include "alarm.h"
#include <limits.h>

char message[500]={0};
int is_binary;  // 1 is binary file
int udh=1;       // disable UDH bit
int messagelen; // length of message
char filename[PATH_MAX]={0};
char logfile[PATH_MAX]={0};
char alarmhandler[PATH_MAX]={0};
int alarmlevel=LOG_WARNING;
int loglevel=9;
char to[50]={0};
int cs_convert=0;
int report=0;
int flash_sms=0;
char idfile[PATH_MAX]={0};

void help()
{
  printf("putsms sends an SMS through a GSM 07.05 compatible modem.\n");
  printf("Usage:\n");
  printf("              putsms [options] destination \"message\"\n");
  printf("Options:\n");
  printf("              -ax  set alarm handler to x (default none)\n");
  printf("              -Ax  set alarm level to x (default %i)\n",alarmlevel);
  printf("              -bx  set baudrate to x (default %i)\n",baudrate);
  printf("              -c   use character set conversion\n");
  printf("              -dx  set modem device to x (default %s)\n",device);
  printf("              -ex  wait x seconds before retry (default %d)\n",errorsleeptime);
  printf("              -fx  message file x (ascii)\n");
  printf("              -Fx  message file x (binary, only in pdu mode old or new)\n");
  printf("              -h   this help\n");
  printf("              -H   disable hardware handshake RTS/CTS\n");
  printf("              -ix  modem init string x\n");
  printf("              -I   send as a flash SMS (class 0)\n");
  printf("              -lx  use logfile x (filename or handle) (default syslog)\n");
  printf("              -Lx  use loglevel x (default %i)\n",loglevel);
  printf("              -mx  set the PDU mode to x (default %s)\n",mode);
  printf("                   x can be old, new, ascii or digicom\n");
  printf("              -nx  set modem name to x\n");
  printf("              -px  set pin to x (default %s. Only needed if\n",pin);
  printf("                   modem not initialized)\n");
  printf("              -q   quick initialisation\n");
  printf("              -r   request status report SMS (not in ascii mode)\n");
  printf("              -Rx  report message ID in file x\n");
  printf("              -sx  set SMSC Number to x\n");
  printf("              -u   no user data header (UDH bit). Only used with -F.\n");
  printf("              -V   print version info and copyright\n\n");
  printf("All options may be omitted.\n\n");
  printf("If you've specified a message file you may omitt the message argument.\n");
  printf("If the message file has a To: header you may omitt the destination argument.\n\n");
  printf("The destination number and SMSC have to be the format like below.\n");
  printf("Example:\n");
  printf("              putsms -d/dev/ttyS0 491721234567 \"Hello\"\n");
  printf("Return codes:\n");
  printf("              0   success\n");
  printf("              1   cannot open device or file\n");
  printf("              2   cannot verify PIN or modem not ready\n");
  printf("              3   modem not registered to the network or did not accept PDU mode.\n");
  printf("              4   SMS could not be sent\n");
  printf("              5   error in arguments\n\n");
  printf("Format of the message file: \n");
  printf("To: xxxxxxxx<NL>other headers<NL><NL>message\n");
  printf("putsms ignores the other headers. The message begins after an empty\n");
  printf("line. You may specify a message file that contains only the message\n");
  printf("without header beginning at the first line.\n\n");
  exit(0);
}

void cut_ctrl(char* message) /* removes all ctrl chars */
{
  char tmp[500];
  int posdest=0;
  int possource;
  int count;
  count=strlen(message);
  for (possource=0; possource<=count; possource++)
  {
    if ((message[possource]>=' ') || (message[possource]==0))
      tmp[posdest++]=message[possource];
  }
  strcpy(message,tmp);
}

void loadmessagefile()
{
  int File;
  int readcount;
  char* position;
  char* endpos;
  int Length;
  char tmp[500];

  /* load Message-File (if set) */
  if (filename[0])
  {
    /* load the whole file */
    File = open(filename, O_RDONLY);
    if (File<0)
    {
      perror(device);
      exit(1);
    }
    else
    {
      readcount=read(File,message,sizeof(message)-1);
      message[readcount]=0;
      messagelen=readcount;
      /* Search for To: */
      position=strstr(message,"To: ");
      if (position!=message)
      {
        position=strstr(message,"\nTo: ");
      if (position)
        position++;
      }
      if (position)
      {
        /* found, get the line */
        endpos=strchr(position+4,'\r');
      if (!endpos)
        endpos=strchr(position+4,'\n');
      if (endpos)
      {
        Length=endpos-position-4;
        strncpy(to,position+4,Length);
        to[Length]=0;
      }

      /* Get the rest of the message, skip newline-characters */
      position=strstr(message,"\n\n");
      if (position)
        position+=2;
      else
      {
        position=strstr(message,"\r\n\r\n"); /* for windows compatibility */
        if (position)
          position+=4;
      }

      if (position) /* if the double newline was found, cut the whole header out */
      {
        messagelen=messagelen-(position-message);
        memmove(message,position,messagelen);
        message[messagelen]=0;
      }
      }
      close(File);
    }
  }
  else
    messagelen=strlen(message);
}

void parsearguments(int argc,char** argv)
{
  int result;
  char tmp[500];

  /* set default values */
  strcpy(device,"/dev/ttyS0");
  strcpy(mode,"new");
  pin[0]=0;
  filename[0]=0;
  smsc[0]=0;
  baudrate=19200;
  is_binary=0;
  initstring[0]=0;
  report=0;
  errorsleeptime=10;
  modemname[0]=0;
  smsc[0]=0;
  rtscts=1;
  quickinit=0;
  flash_sms=0;
  idfile[0]=0;
  /* parse arguments */
  do
  {
    result=getopt(argc,argv,"a:A:n:b:l:L:ce:rR:qhHIi:d:p:m:s:f:F:Vu");
    switch (result)
    {
      case 'h': help();
                break;
      case 'a': strcpy(alarmhandler,optarg);
                  break;
      case 'A': alarmlevel=atoi(optarg);
                  break;
      case 'b': baudrate=atoi(optarg);
                break;
      case 'c': cs_convert=1;
                break;
      case 'I': flash_sms=1;
                break;
      case 'e': errorsleeptime=atoi(optarg);
                  break;
      case 'r': report=1;
            break;
      case 'R': strcpy(idfile,optarg);
                break;
      case 'q': quickinit=1;
                break;
      case 'H': rtscts=0;
            break;
      case 'u': udh=0;
            break;
      case 'd': strcpy(device,optarg);
                break;
      case 'p': strcpy(pin,optarg);
                break;
      case 'l': strcpy(logfile,optarg);
                break;
      case 'L': loglevel=atoi(optarg);
                break;
      case 'm': strcpy(mode,optarg);
                break;
      case 'n': strcpy(modemname,optarg);
                break;
      case 's': strcpy(smsc,optarg);
                break;
      case 'f': strcpy(filename,optarg);
            is_binary=0;
                break;
      case 'i': strcpy(initstring,optarg);
                    strcat(initstring,"\r");
            break;
      case 'F': strcpy(filename,optarg);
            is_binary=1;
            break;
      case 'V': printf("Version %s, Copyright (c) by Stefan Frings, smstools@meinemullemaus.de\n",putsms_version);
                exit(0);
    }
  }
  while (result>0);
  if (modemname[0]==0)
    strcpy(modemname,device);

}

void check_arguments(int argc,char** argv)
{
  switch (baudrate)
  {
    case 300:    baudrate=B300; break;
    case 1200:   baudrate=B1200; break;
    case 2400:   baudrate=B2400; break;
    case 9600:   baudrate=B9600; break;
    case 19200:  baudrate=B19200; break;
    case 38400:  baudrate=B38400; break;
#ifdef B57600
    case 57600:  baudrate=B57600; break;
#endif
#ifdef B115200
    case 115200: baudrate=B115200; break;
#endif
#ifdef B230400
    case 230400: baudrate=B230400; break;
#endif
    default: writelogfile(LOG_ERR,"Baudrate not supported"); exit(1);
  }

  /* parse number and text  */
  if (optind==(argc-2)) /* number and text as arguments defined */
  {
    if (filename[0])
    {
      fprintf(stderr,"Message as file AND as argument specified.\n");
      exit(5);
    }
    strcpy(message,argv[optind+1]);
    strcpy(to,argv[optind]);
  }
  else if (optind==(argc-1)) /* Only number as text defined */
    strcpy(to,argv[optind]);

  loadmessagefile();

  /* Check number and text*/
  if (messagelen==0)
  {
    writelogfile(LOG_ERR,"You did not specify a message or a message file");
    exit(5);
  }
  if (to[0]==0)
  {
    writelogfile(LOG_ERR,"You did not specify a destination or a message file");
    exit(5);
  }
  /* Check if binary file allowed */
  if (is_binary && (strcmp(mode,"ascii")==0))
  {
    writelogfile(LOG_ERR,"Binary files are not allowed in ascii mode");
    exit(5);
  }

}

/* Work with the complex bit building to generate a 7 bit PDU string encapsulated in 8 bit. Returns number of 
7 Bit charcters */
int ascii2pdu(char* ascii,char* pdu)
{
  char tmp[500];
  char octett[10];
  int pdubitposition;
  int pdubyteposition;
  int asciiLength;
  int character;
  int bit;
  int pdubitnr;
  char converted;
  int ext_characters=0;
  int counted_characters=0;
  asciiLength=strlen(ascii);
  for (character=0;character<sizeof(tmp);character++)
    tmp[character]=0;
  for (character=0;((character+ext_characters)<160) && (character<asciiLength);character++)
  {
    if (cs_convert)
    {
      // Is the character an extended character?
      converted=ext_convert(ascii[character],CS_ISO,CS_SMS);
      if (converted!=' ')
      {
        counted_characters++;
         // It is an extended character. Insert ESC first.
         for (bit=0;bit<7;bit++)
         {
           pdubitnr=7*(character+ext_characters)+bit;
           pdubyteposition=pdubitnr/8;
           pdubitposition=pdubitnr%8;
           if (0x1B & (1<<bit))
             tmp[pdubyteposition]=tmp[pdubyteposition] | (1<<pdubitposition);
           else
             tmp[pdubyteposition]=tmp[pdubyteposition] & ~(1<<pdubitposition);
         }
         ext_characters++;
       }
       else
         // Is is a regular character
         converted=convert(ascii[character],CS_ISO,CS_SMS);
    }
    else if (ascii[character]==-73)
      converted=0;
    else
      converted=ascii[character];

    counted_characters++;
    for (bit=0;bit<7;bit++)
    {
      pdubitnr=7*(character+ext_characters)+bit;
      pdubyteposition=pdubitnr/8;
      pdubitposition=pdubitnr%8;
      if (converted & (1<<bit))
        tmp[pdubyteposition]=tmp[pdubyteposition] | (1<<pdubitposition);
      else
        tmp[pdubyteposition]=tmp[pdubyteposition] & ~(1<<pdubitposition);
    }

  }
  tmp[pdubyteposition+1]=0;
  pdu[0]=0;
  for (character=0;character<=pdubyteposition; character++)
  {
    sprintf(octett,"%02X",(unsigned char) tmp[character]);
    strcat(pdu,octett);
  }
  return counted_characters;
}

/* Create a HEX Dump */
void binary2pdu(char* binary, int length, char* pdu)
{
  int character;
  char octett[10];
  if (length>140)
    length=140;
  pdu[0]=0;
  for (character=0;character<length; character++)
  {
    sprintf(octett,"%02X",(unsigned char) binary[character]);
    strcat(pdu,octett);
  }
}

/* make the PDU string. The destination variable pdu has to be big enough. */
void make_pdu(char* nummer, char* message, int messagelen, char* pdu)
{
  int coding;
  int flags;
  char tmp[50];
  char tmp2[500];
  int numberformat;
  int numberlength;

  if (nummer[0]=='s')  // Is number starts with s, then send it without number format indicator
  {
    numberformat=129;
    strcpy(tmp,nummer+1);
  }
  else
  {
    numberformat=145;
    strcpy(tmp,nummer);
  }
  numberlength=strlen(tmp);
  // terminate the number with F if the length is odd
  if (numberlength%2)
    strcat(tmp,"F");
  // Swap every second character
  swapchars(tmp);
  flags=1; // SMS-Sumbit MS to SMSC
  if (flash_sms)
     coding=240+0; /* Dummy + Class 0 */
  else
  {
    coding=240+1; // Dummy + Class 1
    if (is_binary)
    {
      coding+=4; // 8 Bit
      if (udh)
        flags+=64; // User Data Header
    }
  }
  if (strcmp(mode,"old")!=0)
    flags+=16; // Validity field
  if (report)
    flags+=32; /* Request Status Report */
  /* Create the PDU string of the message */
  if (is_binary)
    binary2pdu(message,messagelen,tmp2);
  else
    messagelen=ascii2pdu(message,tmp2);
  /* concatenate the first part of the PDU string */
  if (strcmp(mode,"old")==0)
    sprintf(pdu,"%02X00%02X%02X%s00%02X%02X",flags,numberlength,numberformat,tmp,coding,messagelen);
  else
    sprintf(pdu,"00%02X00%02X%02X%s00%02XA7%02X",flags,numberlength,numberformat,tmp,coding,messagelen);
  /* concatenate the text to the PDU string */
  strcat(pdu,tmp2);
}

/* send sms */
void putsms()
{
  char command[1024];
  char command2[1024];
  char answer[1024];
  char pdu[1024];
  int retries;
  char* posi1;
  char* posi2;
  FILE *fd;
  make_pdu(to,message,messagelen,pdu);
  if (strcmp(mode,"old")==0)
    sprintf(command,"AT+CMGS=%i\r",strlen(pdu)/2);
  else if (strcmp(mode,"ascii")==0)
    sprintf(command,"AT+CMGS=\"+%s\"\r",to);
    // Workaround for a buggy Siemens M20
    // sprintf(command,"AT+CMGS=\"%s\",129,\r",to);
  else
    sprintf(command,"AT+CMGS=%i\r",strlen(pdu)/2-1);
  if (strcmp(mode,"ascii")==0)
    sprintf(command2,"%s\x1A",message);
  else
    sprintf(command2,"%s\x1A",pdu);
  retries=0;
  while (1)
  {
    retries+=1;
    put_command(command,answer,sizeof(answer),50,">");
    if (! strstr(answer,"ERROR"))
      put_command(command2,answer,sizeof(answer),300,0);
    if (strstr(answer,"ERROR"))
    {
      writelogfile(LOG_ERR,"Uups, the modem said ERROR.");
      alarm_handler(LOG_ERR,"","Uups, the modem said ERROR.");
      tcsetattr(modem,TCSANOW,&oldtio);
      if (retries<3)
      {
        writelogfile(LOG_NOTICE,"Waiting %i sec. before retrying",errorsleeptime);
      sleep(errorsleeptime);
      // the next line is a workaround for an unknown buggy gsm modem.
      put_command("\r\x1A\r",answer,sizeof(answer),10,0);
      sleep(1);
      }
      else
        exit(4);
    }
    else if (strstr(answer,"OK"))
    {
      writelogfile(LOG_NOTICE,"SMS sent, To: %s",to);
      alarm_handler(LOG_NOTICE,"","SMS sent, To: %s",to);
      // If the modem answered with an ID number then write into id file.
      posi1=strstr(answer,"CMGS: ");
      if ((posi1) && (idfile[0]))
      {
        posi1+=6;
      posi2=strchr(posi1,'\r');
      if (! posi2) 
        posi2=strchr(posi1,'\n');
      if (posi2)
        posi2[0]=0;
      fd=fopen(idfile,"w");
      fprintf(fd,"%s   \n",posi1);
      fclose(fd);
      }
      return;
    }  
    else
    {
      writelogfile(LOG_WARNING,"Maybe could not send message, modem did not confirm submission.");
      alarm_handler(LOG_WARNING,"","Maybe could not send message, modem did not confirm submission.");
      tcsetattr(modem,TCSANOW,&oldtio);
      exit(4);
    }
  }
}

int main(int argc,char** argv)
{
  char tmp[100];
  parsearguments(argc,argv);
  snprintf(tmp,sizeof(tmp),"putsms (%s)",modemname); tmp[sizeof(tmp)-1]=0;
  openlogfile(tmp,logfile,LOG_DAEMON,loglevel);
  set_alarmhandler(alarmhandler,alarmlevel,modemname);
  check_arguments(argc,argv);
  writelogfile(LOG_INFO,"Sending SMS");
  openmodem();
  setmodemparams();
  initmodem();
  putsms();
  tcsetattr(modem,TCSANOW,&oldtio);
  return 0;
}


Generated by  Doxygen 1.6.0   Back to index