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

modeminit.c

/*
SMS Server Tools 3
Copyright (C) Keijo Kasvi
http://smstools3.kekekasvi.com/

Based on SMS Server Tools 2 from Stefan Frings
http://www.meinemullemaus.de/

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.
*/

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <regex.h>
#include "logging.h"
#include "alarm.h"

#ifdef SOLARIS
#include <sys/filio.h>
#include <strings.h> // for bzero().
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <syslog.h>
#include <sys/ioctl.h>
#include <errno.h>
#include "extras.h"
#include "modeminit.h"
#include "smsd_cfg.h"
#include "version.h"

// Define a dummy if the OS does not support hardware handshake
#ifndef CRTSCTS
#define CRTSCTS 0
#endif

00045 typedef struct {
  int code;
  char *text;
} _gsm_general_error; 

_gsm_general_error gsm_cme_errors[] =
{
  // 3GPP TS 07.07 version 7.8.0 Release 1998 (page 90) ETSI TS 100 916 V7.8.0 (2003-03)
  {0, "phone failure"},
  {1, "no connection to phone"},
  {2, "phone-adaptor link reserved"},
  {3, "operation not allowed"},
  {4, "operation not supported"},
  {5, "PH-SIM PIN required"},
  {6, "PH-FSIM PIN required"},
  {7, "PH-FSIM PUK required"},
  {10,      "SIM not inserted"},
  {11,      "SIM PIN required"},
  {12,      "SIM PUK required"},
  {13,      "SIM failure"},
  {14,      "SIM busy"},
  {15,      "SIM wrong"},
  {16,      "incorrect password"},
  {17,      "SIM PIN2 required"},
  {18,      "SIM PUK2 required"},
  {20,      "memory full"},
  {21,      "invalid index"},
  {22,      "not found"},
  {23,      "memory failure"},
  {24,      "text string too long"},
  {25,      "invalid characters in text string"},
  {26,      "dial string too long"},
  {27,      "invalid characters in dial string"},
  {30,      "no network service"},
  {31,      "network timeout"},
  {32,      "network not allowed - emergency calls only"},
  {40,      "network personalisation PIN required"},
  {41,      "network personalisation PUK required"},
  {42,      "network subset personalisation PIN required"},
  {43,      "network subset personalisation PUK required"},
  {44,      "service provider personalisation PIN required"},
  {45,      "service provider personalisation PUK required"},
  {46,      "corporate personalisation PIN required"},
  {47,      "corporate personalisation PUK required"},
  {100,     "unknown"}

// Some other possible errors (source document?):
//CME ERROR: 48  PH-SIM PUK required
//CME ERROR: 256 Operation temporarily not allowed
//CME ERROR: 257 Call barred
//CME ERROR: 258 Phone is busy
//CME ERROR: 259 User abort
//CME ERROR: 260 Invalid dial string
//CME ERROR: 261 SS not executed
//CME ERROR: 262 SIM Blocked

};

_gsm_general_error gsm_cms_errors[] =
{
  // Table 8.4/GSM 04.11 (part 1):
  {1, "Unassigned (unallocated) number"},
  {8, "Operator determined barring"},
  {10,      "Call barred"},
  {21,      "Short message transfer rejected"},
  {27,      "Destination out of order"},
  {28,      "Unindentified subscriber"},
  {29,      "Facility rejected"},
  {30,      "Unknown subscriber"},
  {38,      "Network out of order"},
  {41,      "Temporary failure"},
  {42,      "Congestion"},
  {47,      "Recources unavailable, unspecified"},
  {50,      "Requested facility not subscribed"},
  {69,      "Requested facility not implemented"},
  {81,      "Invalid short message transfer reference value"},
  {95,      "Semantically incorrect message"},
  {96,      "Invalid mandatory information"},
  {97,      "Message type non-existent or not implemented"},
  {98,      "Message not compatible with short message protocol state"},
  {99,      "Information element non-existent or not implemented"},
  {111,     "Protocol error, unspecified"},
  {127,     "Internetworking , unspecified"},
  // Table 8.4/GSM 04.11 (part 2):
  {22,      "Memory capacity exceeded"},
  // GSM 03.40 subclause 9.2.3.22 values.
  {128,     "Telematic internetworking not supported"},
  {129,     "Short message type 0 not supported"},
  {130,     "Cannot replace short message"},
  {143,     "Unspecified TP-PID error"},
  {144,     "Data code scheme (alphabet) not supported"},
  {145,     "Message class not supported"},
  {159,     "Unspecified TP-DCS error"},
  {160,     "Command cannot be actioned"},
  {161,     "Command unsupported"},
  {175,     "Unspecified TP-Command error"},
  {176,     "Transfer Protocol Data Unit (TPDU) not supported"},
  {192,     "Service Center (SC) busy"},
  {193,     "No SC subscription"},
  {194,     "SC System failure"},
  {195,     "Invalid Short Message Entity (SME) address"},
  {196,     "Destination SME barred"},
  {197,     "SM Rejected-Duplicate SM"},
  {198,     "Validity Period Format (TP-VPF) not supported"},
  {199,     "Validity Period) TP-VP not supported"},
  {208,     "SIM SMS Storage full"},
  {209,     "No SMS Storage capability in SIM"},
  {210,     "Error in MS"},
  {211,     "Memory capacity exceeded"},
  {212,     "Sim Application Toolkit busy"},
  {213,     "SIM data download error"},
  {255,     "Unspecified error cause"},
  // 3GPP TS 27.005 subclause 3.2.5 values /3/.
  {300,     "ME Failure"},
  {301,     "SMS service of ME reserved"},
  {302,     "Operation not allowed"},
  {303,     "Operation not supported"},
  {304,     "Invalid PDU mode parameter"},
  {305,     "Invalid Text mode parameter"},
  {310,     "(U)SIM not inserted"},
  {311,     "(U)SIM PIN required"},
  {312,     "PH-(U)SIM PIN required"},
  {313,     "(U)SIM failure"},
  {314,     "(U)SIM busy"},
  {315,     "(U)SIM wrong"},
  {316,     "(U)SIM PUK required"},
  {317,     "(U)SIM PIN2 required"},
  {318,     "(U)SIM PUK2 required"},
  {320,     "Memory failure"},
  {321,     "Invalid memory index"},
  {322,     "Memory full"},
  {330,     "SMSC address unknown"},
  {331,     "No network service"},
  {332,     "Network timeout"},
  {340,     "No +CNMA acknowledgement expected"},
  {500,     "Unknown error"}
};

char *get_gsm_cme_error(int code)
{
  int i;
  int m = sizeof gsm_cme_errors / sizeof *gsm_cme_errors;

  for (i = 0; i < m; i++)
    if (code == gsm_cme_errors[i].code)
      return gsm_cme_errors[i].text;

  return "";
}

char *get_gsm_cms_error(int code)
{
  int i;
  int m = sizeof gsm_cms_errors / sizeof *gsm_cms_errors;

  for (i = 0; i < m; i++)
    if (code == gsm_cms_errors[i].code)
      return gsm_cms_errors[i].text;

  return "";
}

char *get_gsm_error(char *answer)
{
  char *p;

  if (answer && *answer)
  {
    if ((p = strstr(answer, "+CME ERROR: ")) != NULL)
      return get_gsm_cme_error(atoi(p +12));
    if ((p = strstr(answer, "+CMS ERROR: ")) != NULL)
      return get_gsm_cms_error(atoi(p +12));
  }

  return "";
}

// The following functions are for internal use of put_command and therefore not in the modeminit.h.

int write_to_modem(int modem,char* modemname,int send_delay,char* command,int timeout, int log_command, int print_error)
{
  int status=0;
  int timeoutcounter=0;
  int x=0;
  struct termios tio;

  tcgetattr(modem,&tio);

  if (command && command[0])
  {
    if (tio.c_cflag & CRTSCTS)
    {
      ioctl(modem,TIOCMGET,&status);
      while (!(status & TIOCM_CTS))
      {
        usleep(100000);
        timeoutcounter++;
        ioctl(modem,TIOCMGET,&status);
        if (timeoutcounter>timeout)
        {
          if (print_error)
            printf("\nModem is not clear to send.\n");
          else
          {
            writelogfile0(LOG_ERR,modemname, tb_sprintf("Modem is not clear to send"));
            alarm_handler0(LOG_ERR,modemname, tb);
          }
          return 0;
        }
      }
    }
    if (log_command)
      writelogfile(LOG_DEBUG,modemname,"-> %s",command);
    for(x=0;x<strlen(command);x++)
    {
      if (write(modem,command+x,1)<1)
      {
        if (print_error)
          printf("\nCould not send character %c, cause: %s\n",command[x],strerror(errno));
        else
        {
          writelogfile0(LOG_ERR,modemname, tb_sprintf("Could not send character %c, cause: %s", command[x], strerror(errno)));
          alarm_handler0(LOG_ERR,modemname, tb);
        }
        return 0;
      }
      if (send_delay)
        usleep(send_delay*1000);
      tcdrain(modem);
    }
  }
  return 1;
}

// Read max characters from modem. The function returns when it received at 
// least 1 character and then the modem is quiet for timeout*0.1s.
// The answer might contain already a string. In this case, the answer 
// gets appended to this string.
int read_from_modem(int modem, char* modemname, int send_delay, char* answer,int max,int timeout)
{
  int count=0;
  int got=0;
  int timeoutcounter=0;
  int success=0;
  int toread=0;
  
  // Cygwin does not support TIOC functions, so we cannot use it.
  // ioctl(modem,FIONREAD,&available);    // how many bytes are available to read?

  do 
  {
    // How many bytes do I want to read maximum? Not more than buffer size -1 for termination character.
    count=strlen(answer);
    toread=max-count-1;
    if (toread<=0)
      break;
    // read data
    got=read(modem,answer+count,toread);
    // if nothing received ...
    if (got<=0)
    {
      // wait a litte bit and then repeat this loop
      got=0;
      usleep(100000);
      timeoutcounter++;
    }
    else  
    {
      // restart timout counter
      timeoutcounter=0;
      // append a string termination character
      answer[count+got]=0;
      success=1;      
    }
  }
  while (timeoutcounter < timeout);
  return success;
}


// Exported functions:


int put_command(int modem, char* modemname, int send_delay,char* command,char* answer,int max,int timeout,char* expect)
{
  char loganswer[2048];
  int timeoutcounter=0;
  regex_t re;
  int got_timeout=1;

  // compile regular expressions
  if (expect && expect[0] && (regcomp(&re,expect, REG_EXTENDED|REG_NOSUB) != 0)) 
  {     
    fprintf(stderr,"Programming error: Modem answer %s is not a valid regepr\n",expect);
    exit(1);
  }  

  // clean input buffer
  // It seems that this command does not do anything because actually it 
  // does not clear the input buffer. However I do not remove it until I 
  // know why it does not work.
  tcflush(modem,TCIFLUSH);
  
  // send command
  if (write_to_modem(modem,modemname,send_delay,command,30, 1, 0)==0)
  {
    t_sleep(errorsleeptime);
    // Free memory used by regexp
    regfree(&re);
    return 0;
  }
  writelogfile(LOG_DEBUG,modemname,"Command is sent, waiting for the answer");

  // wait for the modem-answer 
  answer[0]=0;
  timeoutcounter=0;
  do
  {
    read_from_modem(modem,modemname,send_delay,answer,max,2);  // One read attempt is 200ms

    // check if it's the expected answer
    if (expect && expect[0] && (regexec(&re, answer, (size_t) 0, NULL, 0)==0))
    {
      got_timeout = 0;
      put_command_timeouts = 0;
      break;
    }

    timeoutcounter+=2;
  }
  // repeat until timout
  while (timeoutcounter<timeout);

  if (got_timeout)
  {    
    put_command_timeouts++;
    if (expect && expect[0])
      writelogfile(LOG_DEBUG,modemname,"put_command expected %s, timeout occurred.", expect);
  }

  strncpy(loganswer,answer,sizeof(loganswer)-1);
  loganswer[sizeof(loganswer)-1]=0;
  cutspaces(loganswer);
  cut_emptylines(loganswer);
  writelogfile(LOG_DEBUG,modemname,"<- %s",loganswer);

  // Free memory used by regexp
  regfree(&re);

  return strlen(answer);
}

void setmodemparams(int modem, char* modemname, int rtscts,int baudrate) /* setup serial port */
{
  struct termios newtio;

  bzero(&newtio, sizeof(newtio));
  newtio.c_cflag = CS8 | CLOCAL | CREAD | O_NDELAY | O_NONBLOCK;
  if (rtscts)
    newtio.c_cflag |= CRTSCTS;
  newtio.c_iflag = IGNPAR;
  newtio.c_oflag = 0;
  newtio.c_lflag = 0;
  newtio.c_cc[VTIME]    = 0;
  newtio.c_cc[VMIN]     = 0;
  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,modemname,"Baudrate not supported, using 9600"); baudrate=B9600;    
  }
  cfsetispeed(&newtio,baudrate);
  cfsetospeed(&newtio,baudrate);
  tcsetattr(modem,TCSANOW,&newtio);
}

int initmodem(int device, int modem, char* modemname, int send_delay, int error_sleeptime, char* pin, char* initstring1, char* initstring2,
              char* mode, char* smsc, int *check_network, int pinsleeptime, int pre_init)
{
  char command[100];
  char answer[500];
  int retries=0;
  int success=0;
  char *p;
  char *pre_initstring = "ATE0+CMEE=1\r";

  writelogfile(LOG_INFO,modemname,"Checking if modem is ready");
  retries=0;
  do
  {
    retries++;
    put_command(modem,modemname,send_delay,"AT\r",answer,sizeof(answer),50,"(OK)|(ERROR)");
    if ( strstr(answer,"OK")==NULL && strstr(answer,"ERROR")==NULL)
    {
      if (terminate)
        return 7;
      // if Modem does not answer, try to send a PDU termination character
      put_command(modem,modemname,send_delay,"\x1A\r",answer,sizeof(answer),50,"(OK)|(ERROR)");
    }
    if (terminate)
      return 7;
  }
  while ((retries<=10) && (! strstr(answer,"OK")));
  if (! strstr(answer,"OK"))
  {
    writelogfile0(LOG_ERR,modemname, tb_sprintf("Modem is not ready to answer commands"));
    alarm_handler0(LOG_ERR,modemname, tb);
    return 1;
  }

  if (pre_init > 0)
  {
    writelogfile(LOG_INFO,modemname,"Pre-initializing modem");
    put_command(modem,modemname,send_delay,pre_initstring,answer,sizeof(answer),100,"(OK)|(ERROR)");
    if (strstr(answer,"OK")==0)
    {
      writelogfile(LOG_ERR,modemname,"Modem did not accept the pre-init string");
      //alarm_handler(LOG_ERR,modemname,"Modem did not accept the init string");
      //return 3;
    }
  }

  if (pin[0])
  {
    char *cpin_expect = "(READY)|( PIN)|( PUK)|(ERROR)"; // Previously: "(\\+CPIN:.*OK)|(ERROR)"

    writelogfile(LOG_INFO,modemname,"Checking if modem needs PIN");
    put_command(modem,modemname,send_delay,"AT+CPIN?\r",answer,sizeof(answer),50, cpin_expect);
    if (strstr(answer,"+CPIN: SIM PIN") && !strstr(answer, "PIN2"))
    {
      writelogfile(LOG_NOTICE,modemname,"Modem needs PIN, entering PIN...");
      sprintf(command,"AT+CPIN=\"%s\"\r",pin);
      put_command(modem,modemname,send_delay,command,answer,sizeof(answer),300,"(OK)|(ERROR)");
      if (strstr(answer, "ERROR"))
      {
        p = get_gsm_error(answer);
        writelogfile(LOG_NOTICE,modemname, "PIN entering: modem answered %s%s%s", cut_ctrl(answer), (*p)? ", " : "", p);
      }

      // After a PIN is entered, some modems need some time before next commands are processed.
      if (pinsleeptime > 0)
        if (t_sleep(pinsleeptime))
          return 7;

      put_command(modem,modemname,send_delay,"AT+CPIN?\r",answer,sizeof(answer),50, cpin_expect);
      if (strstr(answer,"+CPIN: SIM PIN") && !strstr(answer, "PIN2"))
      {
        writelogfile0(LOG_ERR,modemname, tb_sprintf("Modem did not accept this PIN"));
        alarm_handler0(LOG_ERR,modemname, tb);
        abnormal_termination(0); //return 2;
      }
      if (strstr(answer,"+CPIN: READY"))
        writelogfile(LOG_INFO,modemname,"PIN Ready");
    }

    if (strstr(answer,"+CPIN: SIM PUK"))
    {
      writelogfile0(LOG_CRIT,modemname, tb_sprintf("Your SIM is locked. Unlock it manually"));
      alarm_handler0(LOG_CRIT,modemname, tb);
      abnormal_termination(0); //return 2;
    }

    if (!strstr(answer, "+CPIN: READY"))
    {
      p = get_gsm_error(answer);
      writelogfile0(LOG_CRIT,modemname, tb_sprintf("PIN handling: expected READY, modem answered %s%s%s", cut_ctrl(answer), (*p)? ", " : "", p));
      alarm_handler0(LOG_CRIT,modemname, tb);
      abnormal_termination(0); //return 2;
    }
  }

  if (*initstring1 || *initstring2)
    writelogfile(LOG_INFO,modemname,"Initializing modem");

  if (initstring1[0])
  {
    retries=0;
    do
    {
      retries++;
      put_command(modem,modemname,send_delay,initstring1,answer,sizeof(answer),100,"(OK)|(ERROR)");
      if (strstr(answer, "ERROR"))
        if (retries < 2)
          if (t_sleep(error_sleeptime))
            return 7;
    }
    while (retries < 2 && !strstr(answer,"OK"));
    if (strstr(answer,"OK")==0)
    {
      writelogfile0(LOG_ERR,modemname, tb_sprintf("Modem did not accept the init string"));
      alarm_handler0(LOG_ERR,modemname, tb);
      return 3;
    }
  }

  if (initstring2[0])
  {
    retries=0;
    do
    {
      retries++;
      put_command(modem,modemname,send_delay,initstring2,answer,sizeof(answer),100,"(OK)|(ERROR)");
      if (strstr(answer, "ERROR"))
        if (retries < 2)
          if (t_sleep(error_sleeptime))
            return 7;
    }
    while (retries < 2 && !strstr(answer,"OK"));
    if (strstr(answer,"OK")==0)
    {
      writelogfile0(LOG_ERR,modemname, tb_sprintf("Modem did not accept the second init string"));
      alarm_handler0(LOG_ERR,modemname, tb);
      return 3;
    }
  }

  if (*check_network)
  {
    writelogfile(LOG_INFO,modemname,"Checking if Modem is registered to the network");
    success=0;
    retries=0;
    do
    {
      retries++;
      put_command(modem,modemname,send_delay,"AT+CREG?\r",answer,sizeof(answer),100,"(\\+CREG:.*OK)|(ERROR)");
      if (strstr(answer,"1"))
      {
        writelogfile(LOG_INFO,modemname,"Modem is registered to the network");
        success=1;
      }
      else if (strstr(answer,"5"))
      {
            // added by Thomas Stoeckel
            writelogfile(LOG_INFO,modemname,"Modem is registered to a roaming partner network");
      success=1;
      }
      else if (strstr(answer,"ERROR"))
      {
        writelogfile(LOG_INFO,modemname,"Ignoring that modem does not support +CREG command.");
      success=1;
        *check_network = 0;
      }
      else if (strstr(answer,"+CREG:"))
      {
        writelogfile(LOG_NOTICE,modemname,"Modem is not registered, waiting %i sec. before retrying",error_sleeptime);
        if (t_sleep(error_sleeptime))
          return 7;
      success=0;
      }
      else
      {
        writelogfile0(LOG_ERR,modemname, tb_sprintf("Error: Unexpected answer from Modem after +CREG?, waiting %i sec. before retrying", error_sleeptime));
      alarm_handler0(LOG_ERR,modemname, tb);
      if (t_sleep(error_sleeptime))
          return 7;
      success=0;
      }
      if (terminate)
        return 7;
    }
    while ((success==0)&&(retries<10));

    if (success==0)
    {
      writelogfile0(LOG_ERR,modemname, tb_sprintf("Error: Modem is not registered to the network"));
      alarm_handler0(LOG_ERR,modemname, tb);
      return 4;
    }
  }

  if (mode[0])
  {
    if ((strcmp(mode,"ascii")==0))
    {
      writelogfile(LOG_INFO,modemname,"Selecting ASCII mode");
      strcpy(command,"AT+CMGF=1\r");
    }
    else
    {
      writelogfile(LOG_INFO,modemname,"Selecting PDU mode");
      strcpy(command,"AT+CMGF=0\r");
    }
    retries=0;
    do
    {
      retries++;
      put_command(modem,modemname,send_delay,command,answer,sizeof(answer),50,"(OK)|(ERROR)");
      if (strstr(answer, "ERROR"))
        if (retries < 2)
          if (t_sleep(error_sleeptime))
            return 7;
    }
    while (retries < 2 && !strstr(answer,"OK"));
    if (strstr(answer,"ERROR"))
    {
      writelogfile0(LOG_ERR,modemname, tb_sprintf("Error: Modem did not accept mode selection"));
      alarm_handler0(LOG_ERR,modemname, tb);
      return 5;
    }
  }

  if (smsc[0])
  {
    writelogfile(LOG_INFO,modemname,"Changing SMSC");
    sprintf(command,"AT+CSCA=\"+%s\"\r",smsc);
    retries=0;
    do
    {
      retries++;
      put_command(modem,modemname,send_delay,command,answer,sizeof(answer),50,"(OK)|(ERROR)");
      if (strstr(answer, "ERROR"))
        if (retries < 2)
          if (t_sleep(error_sleeptime))
            return 7;
    }
    while (retries < 2 && !strstr(answer,"OK"));
    if (strstr(answer,"ERROR"))
    {
      writelogfile0(LOG_ERR,modemname, tb_sprintf("Error: Modem did not accept SMSC"));
      alarm_handler0(LOG_ERR,modemname, tb);
      return 6;
    }
  }

  // 3.1beta7, 3.0.9: International Mobile Subscriber Identity is asked once.
  if (devices[device].identity[0] == 0)
  {
    writelogfile(LOG_INFO,modemname,"Querying IMSI");
    sprintf(command,"AT+CIMI\r");
    put_command(modem,modemname,send_delay,command, devices[device].identity, sizeof(devices[device].identity), 50,"(OK)|(ERROR)");
    if (!strstr(devices[device].identity, "ERROR"))
    {
      if ((p = strstr(devices[device].identity, "OK")))
        *p = 0;
      cut_ctrl(devices[device].identity);
      cutspaces(devices[device].identity);
      strcpy(devices[device].identity_header, "IMSI");
      writelogfile(LOG_INFO,modemname,"%s: %s", devices[device].identity_header, devices[device].identity);
    }
  }

  return 0;
}

int openmodem(char* device,char* modemname)
{
  int modem;

  modem = open(device, O_RDWR | O_NOCTTY | O_NONBLOCK);
  if (modem <0)
  {
    writelogfile0(LOG_ERR,modemname, tb_sprintf("Cannot open serial port %s, error: %s", device, strerror(errno)));
    alarm_handler0(LOG_ERR,modemname, tb);
    return -1;
  }
  if (strstr(smsd_version, "beta"))
    writelogfile(LOG_INFO, modemname, "Serial port %s opened as %i", device, modem);
  return modem;
}

int t_sleep(int seconds)
{
  int i;

  for (i = 0; i < seconds; i++)
  {
    if (terminate == 1)
      return 1;
    sleep(1);
  }
  return 0;
}

int talk_with_modem(int device)
{
  int result = 0;
  int modem = -1;
  int n;
  char tmp[256];
  struct termios newtset, oldtset;
  char newdevice[PATH_MAX];
  int stdinflags;
  int set_nonblock = 0;
  int idle;

  stdinflags = fcntl(STDIN_FILENO, F_GETFL); 
  if (!(stdinflags & O_NONBLOCK)) 
  {
    if (fcntl(STDIN_FILENO, F_SETFL, stdinflags | O_NONBLOCK) == -1) 
      printf("Failed to set STDIN nonblock.\n");
    else
      set_nonblock = 1;
  }

  tcgetattr(STDIN_FILENO, &oldtset);
  newtset = oldtset;
  newtset.c_lflag &= ~(ECHO | ICANON);
  newtset.c_iflag &= ~ICRNL;
  newtset.c_cc[VMIN] = 1;
  newtset.c_cc[VTIME] = 0;
  tcsetattr(STDIN_FILENO, TCSAFLUSH, &newtset);

  printf("Communicating with %s. (Press Ctrl-C to abort.)\n", process_title);
  writelogfile(LOG_CRIT, process_title, "Communicating with terminal.");

  printf("Default device is %s\n", devices[device].device);
  printf("Press Enter to start or type an another device name.\n");
  *newdevice = 0;

  while (!terminate)
  {
    idle = 0;

    if ((n = read(STDIN_FILENO, tmp, (modem != -1)? sizeof(tmp) -1 : 1)) > 0)
    {
      if (modem != -1)
      {
        tmp[n] = 0;
        write_to_modem(modem, devices[device].name, devices[device].send_delay, tmp, 5, 0, 1);
      }
      else
      {
        if (*tmp == 13)
        {
          printf("\n");
          fflush(stdout);
          if (*newdevice)
            strcpy(devices[device].device, newdevice);
          printf("Opening device %s\n", devices[device].device);
          modem = openmodem(devices[device].device, devices[device].name);
          if (modem == -1)
          {
            printf("Cannot open device %s, cause: %s.\n", devices[device].device, strerror(errno));
            *newdevice = 0;
            continue;
          }
          setmodemparams(modem, devices[device].name, devices[device].rtscts, devices[device].baudrate);
          printf("Ready.\n");
          result = 1;
        }
        else if (*tmp)
        {
          printf("%c", *tmp);
          fflush(stdout);
          if (*tmp == 127 || *tmp == 8)
          {
            if (*newdevice)
              newdevice[strlen(newdevice) -1] = 0;
          }
          else
          {
            if (strlen(newdevice) < sizeof(newdevice) -1)
              sprintf(strchr(newdevice, 0), "%c", *tmp);
            else
            {
              printf("\nDevice name too long.\n");
              *newdevice = 0;
              continue;
            }
          }
        }
      }
    }
    else
      idle = 1;

    if (modem != -1)
    {
      if ((n = read(modem, tmp, sizeof(tmp) -1)) > 0)
      {
        write(STDOUT_FILENO, tmp, n);
        idle = 0;
      }
    }

    if (idle)
      usleep(100000);
  }

  if (modem >= 0)
    close(modem);

  if (set_nonblock)
    fcntl(STDIN_FILENO, F_SETFL, stdinflags & ~O_NONBLOCK); 
  tcsetattr(STDIN_FILENO, TCSANOW, &oldtset);

  return result;
}

Generated by  Doxygen 1.6.0   Back to index