Logo Search packages:      
Sourcecode: smstools version File versions  Download package

smsd.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 <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <signal.h>
#include <time.h>
#ifndef NOSTATS
#include <mm.h>
#endif
#include <fcntl.h>
#include <unistd.h>
#include "extras.h"
#include "locking.h"
#include "smsd_cfg.h"
#include "stats.h"
#include "version.h"
#include "blacklist.h"
#include "whitelist.h"
#include "logging.h"
#include "alarm.h"
#include "charset.h"
#include "cfgfile.h"

int logfilehandle;  // handle of log file.
int thread_id; // -1 for main task, all other have numbers starting with 0.


/* =======================================================================
   Runs checkhandler and returns return code
   ======================================================================= */
   
int run_checkhandler(char* filename)
{
  char cmdline[PATH_MAX+PATH_MAX+32];
  if (checkhandler[0])
  {
    sprintf(cmdline,"%s %s",checkhandler,filename);
    return my_system(cmdline);
  }
  else
  {
    return 0;
  }
}

/* =======================================================================
   Stops the program if the given file exists
   ======================================================================= */

/* filename1 is checked. The others arguments are used to compose an error message. */

void stop_if_file_exists(char* infotext1, char* filename1, char* infotext2, char* filename2)
{
  int datei;
  datei=open(filename1,O_RDONLY);
  if (datei>=0)
  {
    close(datei);
    writelogfile(LOG_CRIT,"Fatal error: %s %s %s %s. %s. Check file and dir permissions.",infotext1,filename1,infotext2,filename2,strerror(errno));
    alarm_handler(LOG_CRIT,"SMSD","Fatal error: %s %s %s %s. %s. Check file and dir permissions.",infotext1,filename1,infotext2,filename2,strerror(errno));
    kill(0,SIGTERM);
  }
}

/* =======================================================================
   Read the header of an SMS file
   ======================================================================= */

void readSMSheader(char* filename, /* Filename */
// output variables are:
                   char* to, /* destination number */
                 char* from, /* sender name or number */
                 int*  alphabet, /* -1=GSM 0=ISO 1=binary 2=UCS2 3=unknown */
                 int*  udh, /* UDH flag */
                 char* queue, /* Name of Queue */
                 int*  flash, /* 1 if send as Flash SMS */
                 char* smsc, /* SMSC Number */
                   int*  report,  /* 1 if request status report */
               int*  split)  /* 1 if request splitting */
{
  FILE* File;
  char line[256];
  to[0]=0;
  from[0]=0;
  *alphabet=0; 
  *udh=1; 
  queue[0]=0;
  *flash=0;
  smsc[0]=0;
  *report=-1; 
  *split=-1;
  
  File=fopen(filename,"r");  
  // read the header line by line 
  if (File)
  {
    // read until end of file or until an empty line was found
    while (fgets(line,sizeof(line)-1,File))
    {
      if ((line[0]==0) || (line[0]=='\n') || (line[0]=='\r'))
        break;
      if (strstr(line,"To:")==line)
      {
        // remove the To: and spaces
        memmove(line,line+3,strlen(line)-2);
        cutspaces(line);
        // correct phone number if it has wrong syntax
        if (strstr(line,"00")==line)
          strcpy(to,line+2);
        else if (strchr(line,'+')==line)
          strcpy(to,line+1);
        else
          strcpy(to,line);
      }
      else if (strstr(line,"From:")==line)
      {
        strcpy(from,line+5);
        cutspaces(from);
      }
      else if (strstr(line,"SMSC:")==line)
      {
        // remove the SMSC: and spaces
        memmove(line,line+5,strlen(line)-4);
        cutspaces(line);
        // correct phone number if it has wrong syntax
        if (strstr(line,"00")==line)
          strcpy(smsc,line+2);
        else if (strchr(line,'+')==line)
          strcpy(smsc,line+1);
        else
          strcpy(smsc,line);
      }
      else if (strstr(line,"Flash:")==line)
      {
        memmove(line,line+6,strlen(line)-5);
        cutspaces(line);
        *flash=yesno(line);
      }  
      else if (strstr(line,"Provider:")==line)
      {
        strcpy(queue,line+9);
        cutspaces(queue);
      }
      else if (strstr(line,"Queue:")==line)
      {
        strcpy(queue,line+6);
        cutspaces(queue);
      }
      else if (strstr(line,"Binary:")==line)
      {
        memmove(line,line+7,strlen(line)-6);
        cutspaces(line);
        *alphabet=yesno(line);
      }
      else if (strstr(line,"Report:")==line)
      {
        memmove(line,line+7,strlen(line)-6);
        cutspaces(line);
        *report=yesno(line);
      }
      else if (strstr(line,"Autosplit:")==line)
      {
      memmove(line,line+10,strlen(line)-9);
        cutspaces(line);
      *split=yesno(line);
      }
      else if (strstr(line,"Alphabet:")==line)
      {
        memmove(line,line+9,strlen(line)-8);
        cutspaces(line);
        if (strcasecmp(line,"GSM")==0)
          *alphabet=-1;
        else if (strncasecmp(line,"iso",3)==0)
          *alphabet=0;
        else if (strncasecmp(line,"lat",3)==0)
          *alphabet=0;
        else if (strncasecmp(line,"ans",3)==0)
          *alphabet=0;
        else if (strncasecmp(line,"bin",3)==0)
          *alphabet=1;
        else if (strncasecmp(line,"chi",3)==0)
          *alphabet=2;
        else if (strncasecmp(line,"ucs",3)==0)
          *alphabet=2;
        else if (strncasecmp(line,"uni",3)==0)
          *alphabet=2;
        else
          *alphabet=3;
      } 
      else if (strstr(line,"UDH:")==line)
      {
        memmove(line,line+4,strlen(line)-3);
        cutspaces(line);
        *udh=yesno(line);
      }
      // if the header is unknown, then do nothing more here
      else
      {
        ;;
      }
    }
    // End of header reached
    fclose(File);
  }
  else
  {
     writelogfile(LOG_ERR,"Cannot read sms file %s.",filename);
     alarm_handler(LOG_ERR,"SMSD","Cannot read sms file %s.",filename);          
  }
}



/* =======================================================================
   Read the message text of an SMS file
   ======================================================================= */

void readSMStext(char* filename, /* Filename */
                 int do_convert, /* shall I convert from ISO to GSM? */
// output variables are:
                 char* text)     /* destination number */
{
  FILE* File;
  char line[maxtext+1]; 
  text[0]=0;
  
  File=fopen(filename,"r");  
  // read the header line by line 
  if (File)
  {
    // read until until an empty line was found
    while (fgets(line,sizeof(line)-1,File))
    {
      if ((line[0]=='\n') || (line[0]=='\r'))
        break;
    }
    // read each line of the message text
    while (fgets(line,sizeof(line)-1,File))
    {
      if (do_convert==1)
        iso2gsm(line,text+strlen(text),maxtext-strlen(text));
      else
        strncat(text,line,maxtext-strlen(text));
    }
    // End of file
    fclose(File);
  }
  else
  {
     writelogfile(LOG_ERR,"Cannot read sms file %s.",filename);
     alarm_handler(LOG_ERR,"SMSD","Cannot read sms file %s.",filename);          
  }
}

/* =======================================================================
   Mainspooler (sorts SMS into queues)
   ======================================================================= */

void mainspooler()
{
  char filename[PATH_MAX];
  char to[100];
  char from[100];
  char smsc[100];
  char queuename[100];
  char directory[PATH_MAX];
  char cmdline[PATH_MAX+PATH_MAX+32];
  int queue;
  int alphabet;
  int udh;
  int i;
  int flash;
  int success;
  int report;
  int split;
  writelogfile(LOG_INFO,"Smsd outgoing file checker has started.");
  while (1)
  {
    success=0;
    if (getfile(d_spool,filename))
    {
      readSMSheader(filename,to,from,&alphabet,&udh,queuename,&flash,smsc,&report,&split);
      // Is the destination set?
      if (to[0]==0)
      {
        writelogfile(LOG_NOTICE,"No destination in file %s",filename);
        alarm_handler(LOG_NOTICE,"SMSD","No destination in file %s",filename);
      }
      // Does the checkhandler accept the message?
      else if (run_checkhandler(filename))
      {   
        writelogfile(LOG_NOTICE,"SMS file %s rejected by checkhandler",filename);
        alarm_handler(LOG_NOTICE,"SMSD","SMS file %s rejected by checkhandler",filename);    
      }
      // is To: in the blacklist?
      else if (inblacklist(to))
      {
        writelogfile(LOG_NOTICE,"Destination %s in file %s is blacklisted",to,filename);
         alarm_handler(LOG_NOTICE,"SMSD","Destination %s in file %s is blacklisted",to,filename);
      }
      // is To: in the whitelist?
      else if (! inwhitelist(to))
      {
        writelogfile(LOG_NOTICE,"Destination %s in file %s is not whitelisted",to,filename);
        alarm_handler(LOG_NOTICE,"SMSD","Destination %s in file %s is not whitelisted",to,filename);
      }
      // Is the alphabet setting valid?
      else if (alphabet>2)
      {
        writelogfile(LOG_NOTICE,"Invalid alphabet in file %s",filename);
        alarm_handler(LOG_NOTICE,"SMSD","Invalid alphabet in file %s",filename);
      }
      // is there is a queue name, then set the queue by this name
      else if ((queuename[0]) && ((queue=getqueue(queuename,directory))==-1))
      {
        writelogfile(LOG_NOTICE,"Wrong provider queue %s in file %s",queuename,filename);
        alarm_handler(LOG_NOTICE,"SMSD","Wrong provider queue %s in file %s",queuename,filename);
      }
      // if there is no queue name, set it by the destination phone number
      else if ((queuename[0]==0) && ((queue=getqueue(to,directory))==-1))
      {
        writelogfile(LOG_NOTICE,"Destination number %s in file %s does not match any provider",to,filename);
        alarm_handler(LOG_NOTICE,"SMSD","Destination number %s in file %s does not match any provider",to,filename);
      }
      // everything is ok, move the file into the queue
      else
      {
        movefilewithdestlock(filename,directory);
        stop_if_file_exists("Cannot move",filename,"to",directory);
        writelogfile(LOG_INFO,"Moved file %s to %s",filename,directory);
        success=1;
      }
      if (! success)
      {
        rejected_counter++;
        if (eventhandler[0])
        {
          sprintf(cmdline,"%s %s %s",eventhandler,"FAILED",filename);
          my_system(cmdline);
        }
        movefilewithdestlock(filename,d_failed);
        stop_if_file_exists("Cannot move",filename,"to",d_failed);
      }
    }
    else
    {
      // Sleep a while and output status monitor
      for (i=0; i<delaytime; i++)
      {
        print_status();
      checkwritestats();
        sleep(1);
      }
    }
  }
}

/* =======================================================================
   Receive one SMS
   ======================================================================= */

int receive1sms(int device,int* quick)   // receive one SM. quick may beo 0, 1 or 2 for very quick
                              // Returns 1 if successful
                              // Return 0 if no SM available
                              // Returns -1 on error
{
  char cmdline[PATH_MAX+PATH_MAX+1024];
  char filename[100];
  int result;
  char newname[PATH_MAX];
  char tmp[32];
  char* cp;
  int start_time=time(0);

  statistics[device]->status='r';
  writelogfile(LOG_INFO,"Checking device %s for incoming SMS",devices[device].name);
  //Create a temp file for received message
  sprintf(filename,"/tmp/%s.XXXXXX",devices[device].name);
  close(mkstemp(filename));
  sprintf(cmdline,"%s/getsms -L%i -n%s -b%i -D%i -e%i -d%s -s%s -o%s",mypath,loglevel,devices[device].name,devices[device].baudrate,devices[device].send_delay,errorsleeptime,devices[device].device,devices[device].name, filename);
#ifdef WINDOWS
  sprintf(cmdline,"%s/getsms.exe -L%i -n%s -b%i -D%i -e%i -d%s -s%s -o%s",mypath,loglevel,devices[device].name,devices[device].baudrate,devices[device].send_delay,errorsleeptime,devices[device].device,devices[device].name, filename);
#endif
  if (logfile[0])
  {
    strcat(cmdline," -l");
    sprintf(tmp,"%i",logfilehandle);
    strcat(cmdline,tmp);
  }
  if (alarmhandler[0])
  {
    strcat(cmdline," -a");
    strcat(cmdline,alarmhandler);
    strcat(cmdline," -A");
    sprintf(tmp,"%i",alarmlevel);
    strcat(cmdline,tmp);
  }
  if (devices[device].mode[0])
  {
    strcat(cmdline," -m");
    strcat(cmdline,devices[device].mode);
  }
  if (devices[device].pin[0])
  {
    strcat(cmdline," -p");
    strcat(cmdline,devices[device].pin);
  }
  if (devices[device].cs_convert)
    strcat(cmdline," -c");
  if (! devices[device].rtscts)
    strcat(cmdline," -H");
  if (*quick)
    strcat(cmdline," -q");
  if (*quick==2)
    strcat(cmdline," -Q");
  if (devices[device].initstring[0])
  {
    strcat(cmdline," -i'");
    strcat(cmdline,devices[device].initstring);
    strcat(cmdline,"'");
  }
  if (devices[device].initstring2[0])
  {
    strcat(cmdline," -j'");
    strcat(cmdline,devices[device].initstring2);
    strcat(cmdline,"'");
  }
  if (debug)
    strcat(cmdline," -k");
  writelogfile(LOG_DEBUG,"Calling: %s",cmdline);

  result=my_system(cmdline);
  statistics[device]->usage_r+=time(0)-start_time;
  if ((result!=0) && (result!=5))
  {
    unlink(filename);
    if (result==1 || result==2 || result==3)
    {
      *quick=0;
      return -1;
    }
    else
    {
      *quick=1;
      return 0;
    }
  }
  else
  {
    movefilewithdestlock(filename,d_incoming);
    stop_if_file_exists("Cannot move file",filename,"to",d_incoming);
    statistics[device]->received_counter++;
    if (eventhandler[0] || devices[device].eventhandler[0])
    {
      cp=strrchr(filename,'/');
      if (cp)
      sprintf(newname,"%s%s",d_incoming,cp);
      else
        sprintf(newname,"%s/%s",d_incoming,filename);
      if (result==5) //Status Report
      {
        if (devices[device].eventhandler[0])
          sprintf(cmdline,"%s %s %s",devices[device].eventhandler,"REPORT",newname);
        else
          sprintf(cmdline,"%s %s %s",eventhandler,"REPORT",newname);
      }
      else // SMS Received
      {
        if (devices[device].eventhandler[0])
          sprintf(cmdline,"%s %s %s",devices[device].eventhandler,"RECEIVED",newname);
        else
          sprintf(cmdline,"%s %s %s",eventhandler,"RECEIVED",newname);
      }
      my_system(cmdline);
    }
    *quick=1;
    return 1;
  }
}

/* =======================================================================
   Send a part of a message, this is physically one sms
   ======================================================================= */

int send_part(int device, char* from, char* to, char* text, int alphabet, char* filename, int udh, int quick, int flash, char* messageid,char* smsc,int report)
// alphabet can be -1=GSM 0=ISO 1=binary 2=UCS2
// udh can be 0=off or 1=on
// filename is only used in binary and UCS2 mode
// smsc is optional. Can be used to override config file setting.
{
  int result;
  char cmdline[PATH_MAX+PATH_MAX+PATH_MAX+1024];
  char tmpfilename[100];
  FILE* fd;
  int posi;
  char tmp[32];
  time_t start_time=time(0);
  statistics[device]->status='s';
  writelogfile(LOG_INFO,"Sending SMS from %s to %s on device %s",from,to,devices[device].name);
  if ((report==1) && (devices[device].incoming==0))
    writelogfile(LOG_NOTICE,"Cannot receive status report because receiving is disabled on device %s",devices[device].name);

    if (debug)
    {
      printf("----------\n%s\n----------\n",text);
      result=0;
    }
    else
    {
      sprintf(cmdline,"%s/putsms -A%i -L%i -n%s -b%i -e%i -d%s",mypath,alarmlevel,loglevel,devices[device].name,devices[device].baudrate,errorsleeptime,devices[device].device);
#ifdef WINDOWS
      sprintf(cmdline,"%s/putsms.exe -A%i -L%i -n%s -b%i -e%i -d%s",mypath,alarmlevel,loglevel,devices[device].name,devices[device].baudrate,errorsleeptime,devices[device].device);
#endif
      if (logfile[0])
      {
        strcat(cmdline," -l");
        sprintf(tmp,"%i",logfilehandle);
        strcat(cmdline,tmp);
      }
      if (alarmhandler[0])
      {
        strcat(cmdline," -a'");
        strcat(cmdline,alarmhandler);
        strcat(cmdline,"'");
      }
      // Use the smsc setting from the sms file, or the modems default if unset
      if (smsc[0])
      {
        strcat(cmdline," -s");
        strcat(cmdline,smsc);
      }
      else if (devices[device].smsc[0])
      {
        strcat(cmdline," -s");
        strcat(cmdline,devices[device].smsc);
      }
      if (devices[device].mode[0])
      {
        strcat(cmdline," -m");
        strcat(cmdline,devices[device].mode);
      }
      if (devices[device].pin[0])
      {
        strcat(cmdline," -p");
        strcat(cmdline,devices[device].pin);
      }
      // Use the modems default if report is unset (-1)
      if (report==-1)
        report=devices[device].report;
      if (report)
      {
        // Create a temp file for message ID
        sprintf(tmpfilename,"/tmp/%s.XXXXXX",devices[device].name);
        close(mkstemp(tmpfilename));
        strcat(cmdline," -r -R'");
        strcat(cmdline,tmpfilename);
        strcat(cmdline,"'");
      }
      if (! devices[device].rtscts)
        strcat(cmdline," -H");
      if (quick)
        strcat(cmdline," -q");
      if (devices[device].initstring[0])
      {
        strcat(cmdline," -i'");
        strcat(cmdline,devices[device].initstring);
        strcat(cmdline,"'");
      }
      if (devices[device].initstring2[0])
      {
        strcat(cmdline," -j'");
        strcat(cmdline,devices[device].initstring2);
        strcat(cmdline,"'");
      }
      if (alphabet<=0)
      {
        if (flash)
          strcat(cmdline," -I");
        strcat(cmdline," -- ");
        strcat(cmdline,to);
        // write a double quote before the text 
        strcat(cmdline," \"");
        // add the text but escape special characters 
        posi=0;
        while (text[posi])
        {
          if (text[posi]=='$')          // replace $ by \$
            strcat(cmdline,"\\$");
        else if (text[posi]=='\"')    // replace " by \"
          strcat(cmdline,"\\\""); 
          else if (text[posi]=='`')     // replace ` by \`
            strcat(cmdline,"\\`"); 
          else if (text[posi]=='\\')    // replace \ by \\ .
            strcat(cmdline,"\\\\");
          else 
            strncat(cmdline,&text[posi],1);
          posi++;
        }
        // write a double quote after the text
        strcat(cmdline,"\"");
      }
      else if (alphabet==1)
      {
        if (udh==0)
          strcat(cmdline," -u");
        strcat(cmdline," -F");
        strcat(cmdline,filename);
        strcat(cmdline," -- ");
        strcat(cmdline,to);
      }
      else if (alphabet==2)
      {
        if (flash)
          strcat(cmdline," -I");
        strcat(cmdline," -g");
        strcat(cmdline,filename);
        strcat(cmdline," -- ");
        strcat(cmdline,to);
      }
      writelogfile(LOG_DEBUG,"Calling: %s",cmdline);
      result=my_system(cmdline);
    }

  statistics[device]->usage_s+=time(0)-start_time;
  if (result==0)
  {
    writelogfile(LOG_INFO,"Sending SMS to %s on %s was successful.",to,devices[device].name);
    statistics[device]->succeeded_counter++;
    messageid[0]=0;
    if (report)
    {
      fd=fopen(tmpfilename,"r");
      if (fd)
      {
        fread(messageid,3,1,fd);
        messageid[3]=0;
        fclose(fd);
        unlink(tmpfilename);
      } 
    }
    return 1;
  }
  else
  {
    writelogfile(LOG_WARNING,"Sending SMS to %s on %s failed",to,devices[device].name);
    alarm_handler(LOG_WARNING,devices[device].name,"Sending SMS to %s failed",to);
    statistics[device]->failed_counter++;
    return 0;
  }
}

/* =======================================================================
   Send a whole message, this can have many parts
   ======================================================================= */

int send1sms(int device,int* quick,int* errorcounter)    
// Search the queues for SMS to send and send one of them.
// Returns 0 if queues are empty
// Returns -1 if sending failed
// Returns 1 if successful
{
  char filename[PATH_MAX];
  char to[100];
  char from[100];
  char smsc[100];
  char provider[100];
  char text[maxtext];
  char part_text[maxsms_pdu+1];
  char directory[PATH_MAX];
  char cmdline[PATH_MAX+PATH_MAX+32];
  int q,queue;
  int part;
  int parts;
  int maxpartlen;
  int alphabet;
  int udh;
  int success=0;
  int flash;
  int report;
  int split;
  char messageid[10]={0};
  int found_a_file=0;

  // How long is the maximum allowed message size
  if (strcmp(devices[device].mode,"ascii")==0)
    maxpartlen=maxsms_ascii;
  else
    maxpartlen=maxsms_pdu;
  
  // Search for one single sms file  
  for (q=0; q<PROVIDER; q++)
  {
    if ((devices[device].queues[q][0]) &&
       ((queue=getqueue(devices[device].queues[q],directory))!=-1) &&
       (getfile(directory,filename)) &&
       (lockfile(filename)))
    {
      found_a_file=1;
      break;
    }
  }
 
  // If there is no file waiting to send, then do nothing
  if (found_a_file==0)
  { 
    return 0;
  }
  else
  {
  
    // Some modem cannot send if the memory is full. In this case
    // Try a quick receive to ensure that at least 1 memory space is free
    if ((receive_before_send) && (devices[device].incoming))
    {
      *quick=2;
      receive1sms(device,quick);
      if (*quick>1)
      *quick=1;
    }
    
    readSMSheader(filename,to,from,&alphabet,&udh,provider,&flash,smsc,&report,&split);
    // If this is a text message, then read also the text
    if (alphabet<1)
    {
      readSMStext(filename,devices[device].cs_convert && (alphabet==0),text);
      // Is the messag empty?
      if (strlen(text)==0)
      {
        writelogfile(LOG_NOTICE,"The file %s has no text",filename);
        alarm_handler(LOG_NOTICE,"SMSD","The file %s has no text",filename);
        parts=0;
        success=-1;
      }
      // The message is not empty
      else
      {
        // Split is unset, use the default value from config file
        if (split==-1) 
          split=autosplit;
        // In how many parts do we need to split the text?
        if (split)
        {
          // if it fits into 1 SM, then we need 1 part
          if (strlen(text)<=maxpartlen)
            parts=1;
        // else if numbering is enabled then reserve 4 char. for the numbers
          else if (number_parts)
        {
            parts=(strlen(text)+maxpartlen-5)/(maxpartlen-4);
          // If we have more than 9 parts, we need to reserve 6 char. for the numbers
          if (parts>9)
            parts=(strlen(text)+maxpartlen-7)/(maxpartlen-6);
        }
        // Else simply calculate the number of parts
          else
            parts=(strlen(text)+maxpartlen-1)/maxpartlen;
        }
        else
          parts=1; 
      if (parts>1)
        writelogfile(LOG_INFO,"Splitting this message into %i parts.",parts);
      }
    }
    // This is a binary or ucs2 message
    else
    {
      parts=1;
    }
    
    
    // Try to send each part  
    writelogfile(LOG_INFO,"I have to send %i messages for %s",parts,filename); 
    for (part=0; part<parts; part++)
    {
      // If this is a text message, then copy the needed part from the text. Otherwise make it empty.
      if (alphabet<1)
      {
      if (number_parts && parts>1)
        {
          sprintf(part_text,"%i/%i ",part+1,parts);
        if (parts<10)
          strncat(part_text,text+(maxpartlen-4)*part,maxpartlen-4);
        else
            strncat(part_text,text+(maxpartlen-6)*part,maxpartlen-6);
      }
      else
          strncpy(part_text,text+maxpartlen*part,maxpartlen);
      }
      else
        part_text[0]=0;
      // Try to send the sms
      if (send_part(device,from,to,part_text,alphabet,filename,udh,*quick,flash,messageid,smsc,report))
      {
        // Sending was successful
        *quick=1;
        success=1;
      }
      else
      {
        // Sending failed
        *quick=0;
        success=-1;
        (*errorcounter)++;
        if (*errorcounter>=blockafter)
        {
          writelogfile(LOG_CRIT,"Fatal error: sending on %s failed 3 times. Blocking %i sec.",devices[device].name,blocktime);
          alarm_handler(LOG_CRIT,devices[device].name,"Fatal error: sending failed 3 times. Blocking %i sec.",blocktime);
          statistics[device]->multiple_failed_counter++;
          statistics[device]->status='b';
          sleep(blocktime);
          *errorcounter=0;
        }
        // Do not send the next part if sending failed
        break;
      }
    }
    
    // Mark modem status as idle
    statistics[device]->status='i';
    // Run eventhandler is configured
    if (eventhandler[0] || devices[device].eventhandler[0])
    {
      if (success<1)
        strcpy(text,"FAILED");
      else
        strcpy(text,"SENT");
      if (devices[device].eventhandler[0])
        sprintf(cmdline,"%s %s %s %s",devices[device].eventhandler,text,filename,messageid);
      else
        sprintf(cmdline,"%s %s %s %s",eventhandler,text,filename,messageid);
        my_system(cmdline);
    }
    
    // If sending failed
    if (success==-1)
    {
      // Move file into failed queue or delete
      if (d_failed[0])
      {
        movefilewithdestlock(filename,d_failed);
        stop_if_file_exists("Cannot move",filename,"to",d_failed);
      writelogfile(LOG_INFO,"Moved file %s to %s",filename,d_failed);
      }
      else
      {
        unlink(filename);
        stop_if_file_exists("Cannot delete",filename,"","");
      writelogfile(LOG_INFO,"Deleted file %s",filename);
      }
    }
    
    // Sending was successful
    else
    {
      // Move file into failed queue or delete
      if (d_sent[0])
      {
        movefilewithdestlock(filename,d_sent);
        stop_if_file_exists("Cannot move",filename,"to",d_sent);
      writelogfile(LOG_INFO,"Moved file %s to %s",filename,d_sent);
      }
      else
      {
        unlink(filename);
        stop_if_file_exists("Cannot delete",filename,"","");
      writelogfile(LOG_INFO,"Deleted file %s",filename);
      }
    }
    
    unlock(filename);
    return success;
  }
}


/* =======================================================================
   Device-Spooler (one for each modem)
   ======================================================================= */


void devicespooler(int device)
{
  int workless;
  int quick=0;
  int errorcounter;
  int have_set_smsc=0;
  
  writelogfile(LOG_INFO,"Modem handler %i for %s has started.",device,devices[device].name);
  errorcounter=0;

  while (1) /* endless loop */
  {
    workless=1;
    // If the SMSC number was not set, then set it now, do not quick init
    if (have_set_smsc==0)
      quick=0;

    // Send SM
    while (send1sms(device,&quick,&errorcounter))
    {
      have_set_smsc=1;
      workless=0;
      if (devices[device].incoming==2) // repeat only if receiving has low priority
        break;
    }

    // Receive SM
    if (devices[device].incoming)
      while (receive1sms(device,&quick)==1)
      {
        workless=0;
        if (devices[device].incoming==1) // repeat only if receiving has high priority
          break;
      }

    if (workless==1) // wait a little bit if there was no SM to send or receive to save CPU usage
    {
      // Disable quick init again before next loop
      quick=0;
      statistics[device]->status='i';
      sleep(delaytime);
    }
  }
}


/* =======================================================================
   Task-Maker (creates threads for the modems and the main queue)
   ======================================================================= */

void taskmaker()
{
  int i;
  // start device spoolers
  for (i=0; i<DEVICES; i++)
  {
    if (devices[i].name[0])
      if (fork()==0)
      {
      thread_id=i;
      write_pid("/var/run/smsd.pid");
      devicespooler(i);
      remove_pid("/var/run/smsd.pid");
      }
  } 
  // Start main program
  thread_id=-1;
  write_pid("/var/run/smsd.pid");
  mainspooler();
  remove_pid("/var/run/smsd.pid");
}

void termination_handler (int signum)
{
  if (thread_id==-1)
  {
    savestats();
#ifndef NOSTATS
    MM_destroy();
#endif
    writelogfile(LOG_CRIT,"Smsd main program has stopped.");
    thread_id=-2;
    kill(0,SIGTERM);
  }
  else if (thread_id>=0)
    writelogfile(LOG_CRIT,"Modem handler %i for %s has stopped.",thread_id,devices[thread_id].name);
  remove_pid("/var/run/smsd.pid");
  exit(0);
}

/* =======================================================================
   Main
   ======================================================================= */

int main(int argc,char** argv)
{
  if (signal(SIGINT,termination_handler)==SIG_IGN)
    signal(SIGINT,SIG_IGN);
  if (signal(SIGTERM,termination_handler)==SIG_IGN)
    signal(SIGTERM,SIG_IGN);
    
  parsearguments(argc,argv);
  initcfg();
  readcfg();
  logfilehandle=openlogfile("smsd",logfile,LOG_DAEMON,loglevel);  
  initstats();
  loadstats();
  writelogfile(LOG_CRIT,"Smsd v%s started. Made for getsms v%s and putsms v%s.",smsd_version,getsms_version,putsms_version);  
  taskmaker();
  return 0;
}

Generated by  Doxygen 1.6.0   Back to index