/* SMS Server Tools Copyright (C) 2000 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.isis.de/members/~s.frings mailto:s.frings@mail.isis.de */ #include #include #include #include #include #include #include #include #include #include #include #ifdef __sun #include #endif #include "libsms_modem.h" #include "../../dprint.h" #define MAX_BUF 2048 #define CDS_HDR "\r\n+CDS:" #define CDS_HDR_LEN (strlen(CDS_HDR)) #define optz(_n,_l) (buf+buf_len-(((_n)+(_l)>buf_len)?buf_len:(_n)+(_l))) /* global variables */ int sms_report_type; cds_report cds_report_func; int put_command( struct modem *mdm, char* cmd, int cmd_len, char* answer, int max, int timeout,char* exp_end) { static char buf[MAX_BUF]; static int buf_len = 0; char* pos; char* foo; char* ptr; char* to_move; char* answer_s; char* answer_e; int timeoutcounter; int available; int status; int exp_end_len; int n; /* check if fd is "clean" for reading */ timeoutcounter = 0; ioctl(mdm->fd,TIOCMGET,&status); while (!(status & TIOCM_CTS)) { usleep( READ_SLEEP ); timeoutcounter++; ioctl(mdm->fd,TIOCMGET,&status); if (timeoutcounter>=timeout) { LOG(L_INFO,"INFO:put_command: Modem is not clear to send\n"); return 0; } } #ifdef SHOW_SMS_MODEM_COMMAND DBG("DEBUG: put_command: -<%d>-->[%.*s] \n",cmd_len,cmd_len,cmd); #endif /* send the command to the modem */ write(mdm->fd,cmd,cmd_len); tcdrain(mdm->fd); /* read from the modem */ exp_end_len = exp_end?strlen(exp_end):0; answer_s = buf; answer_e = 0; to_move = 0; do { /* try to read some bytes */ ioctl(mdm->fd,FIONREAD,&available); /* how many bytes are available to read? */ if (available<1) /* if 0 then wait a little bit and retry */ { usleep( READ_SLEEP ); timeoutcounter++; ioctl(mdm->fd,FIONREAD,&available); } if (available>0) { /* How many bytes do I want to read maximum? Not more than buffer size. And how many bytes are available? */ n = (available>MAX_BUF-buf_len-1)?MAX_BUF-buf_len-1:available; /* read data */ n = read( mdm->fd, buf+buf_len, n); if (n<0) { LOG(L_ERR,"ERROR:put_command: error reading from modem: %s\n", strerror(errno)); goto error; } if (n) { buf_len += n; buf[buf_len] = 0; //DBG("DEBUG:put_commnad: read = [%s]\n",buf+buf_len-n); foo = pos = 0; if ( (!exp_end && ((pos=strstr(optz(n,4),"OK\r\n")) || (foo=strstr(optz(n,5),"ERROR")))) || (exp_end && (pos=strstr(optz(n,exp_end_len),exp_end)) )) { /* we found the end */ //DBG("DEBUG:put_commnad: end found = %s\n", // (foo?"ERROR":(exp_end?exp_end:"OK"))); /* for ERROR we still have to read EOL */ if (!foo || (foo=strstr(foo+5,"\r\n"))) { answer_e = foo?foo+2:(pos+(exp_end?exp_end_len:4)); timeoutcounter = timeout; } } } } /* repeat until timout */ }while (timeoutcounterbaudrate | CRTSCTS | CS8 | CLOCAL | CREAD | O_NDELAY; //uncomment next line to disable hardware handshake //newtio.c_cflag &= ~CRTSCTS; newtio.c_iflag = IGNPAR; newtio.c_oflag = 0; newtio.c_lflag = 0; newtio.c_cc[VTIME] = 1; newtio.c_cc[VMIN] = 0; tcflush(mdm->fd, TCIOFLUSH); tcsetattr(mdm->fd,TCSANOW,&newtio); return 0; } int initmodem(struct modem *mdm, cds_report cds_report_f) { char command[100]; char answer[100]; int retries=0; int success=0; int clen=0; int n; LOG(L_INFO,"INFO:initmodem: init modem %s on %s.\n",mdm->name,mdm->device); if (mdm->pin[0]) { /* Checking if modem needs PIN */ put_command(mdm,"AT+CPIN?\r",9,answer,sizeof(answer),50,0); if (strstr(answer,"+CPIN: SIM PIN")) { LOG(L_INFO,"INFO:initmodem: Modem needs PIN, entering PIN...\n"); clen=sprintf(command,"AT+CPIN=\"%s\"\r",mdm->pin); put_command(mdm,command,clen,answer,sizeof(answer),100,0); put_command(mdm,"AT+CPIN?\r",9,answer,sizeof(answer),50,0); if (!strstr(answer,"+CPIN: READY")) { if (strstr(answer,"+CPIN: SIM PIN")) { LOG(L_ERR,"ERROR:initmodem: Modem did not accept" " this PIN\n"); goto error; } else if (strstr(answer,"+CPIN: SIM PUK")) { LOG(L_ERR,"ERROR:initmodem: YourPIN is locked!" " Unlock it manually!\n"); goto error; } else { goto error; } } LOG(L_INFO,"INFO:initmodem: PIN Ready!\n"); sleep(5); } } if (mdm->mode==MODE_DIGICOM) success=1; else { LOG(L_INFO,"INFO:initmodem: Checking if Modem is registered to" " the network\n"); success=0; retries=0; do { retries++; put_command(mdm,"AT+CREG?\r",9,answer,sizeof(answer),100,0); if (strchr(answer,'1') ) { LOG(L_INFO,"INFO:initmodem: Modem is registered to the" " network\n"); success=1; } else if (strchr(answer,'2')) { // added by bogdan LOG(L_WARN,"WARNING:initmodem: Modems seems to try to " "reach the network! Let's wait a little bit\n"); retries--; sleep(2); } else if (strchr(answer,'5')) { // added by Thomas Stoeckel LOG(L_INFO,"INFO:initmodem: Modem is registered to a" " roaming partner network\n"); success=1; } else if (strstr(answer,"ERROR")) { LOG(L_WARN,"WARNING:initmodem: Ignoring that modem does" " not support +CREG command.\n"); success=1; } else { LOG(L_NOTICE,"NOTICE:initmodem: Waiting 2 sec. before" " retrying\n"); sleep(2); } }while ((success==0)&&(retries<20)); } if (success==0) { LOG(L_ERR,"ERROR:initmodem: Modem is not registered to the network\n"); goto error; } for( n=0 ; n<2+2*(sms_report_type==CDS_REPORT) ; n++) { /* build the command */ switch (n) { case 0: strcpy(command,"AT+CMGF=0\r"); command[8]+=(mdm->mode==MODE_ASCII || mdm->mode==MODE_DIGICOM); clen = 10; break; case 1: strcpy(command,"AT S7=45 S0=0 L1 V1 X4 &c1 E1 Q0\r"); clen = 33; break; case 2: strcpy(command,"AT+CSMP=49,167,0,241\r"); clen = 21; break; case 3: strcpy(command,"AT+CNMI=1,1,0,1,0\r"); clen = 18; break; } /* send it to modem */ retries=0; success=0; do { retries++; /*querying the modem*/ put_command(mdm,command,clen,answer,sizeof(answer),100,0); /*dealing with the answer*/ if (strstr(answer,"ERROR")) { LOG(L_NOTICE,"NOTICE:initmodem: Waiting 1 sec. before to" " retrying\n"); sleep(1); } else success=1; }while ((success==0)&&(retries<3)); /* have we succeeded? */ if (success==0) { LOG(L_ERR,"ERROR:initmodem: cmd [%.*s] returned ERROR\n", clen-1,command); goto error; } } /* end for */ if ( sms_report_type==CDS_REPORT && !cds_report_f) { LOG(L_ERR,"ERROR:initmodem:no CDS_REPORT function given\n"); goto error; } cds_report_func = cds_report_f; if (mdm->smsc[0]) { LOG(L_INFO,"INFO:initmodem: Changing SMSC to \"%s\"\n",mdm->smsc); setsmsc(mdm,mdm->smsc); } return 0; error: return -1; } int checkmodem(struct modem *mdm) { char answer[500]; /* Checking if modem needs PIN */ put_command(mdm,"AT+CPIN?\r",9,answer,sizeof(answer),50,0); if (!strstr(answer,"+CPIN: READY")) { LOG(L_WARN,"WARNING:sms_checkmodem: modem wants the PIN again!\n"); goto reinit; } if (mdm->mode!=MODE_DIGICOM) { put_command(mdm,"AT+CREG?\r",9,answer,sizeof(answer),100,0); if (!strchr(answer,'1') ) { LOG(L_WARN,"WARNING:sms_checkmodem: Modem is not registered to the" " network\n"); goto reinit; } } return 1; reinit: LOG(L_WARN,"WARNING:sms_checkmodem: re -init the modem!!\n"); initmodem(mdm,cds_report_func); return -1; } int setsmsc(struct modem *mdm, char *smsc) { char command[100]; char answer[50]; int clen; if (smsc && smsc[0]) { clen=sprintf(command,"AT+CSCA=\"+%s\"\r",smsc); put_command(mdm,command,clen,answer,sizeof(answer),50,0); } return 0; } int openmodem( struct modem *mdm) { mdm->fd = open(mdm->device, O_RDWR | O_NOCTTY ); if (mdm->fd <0) return -1; tcgetattr(mdm->fd,&(mdm->oldtio)); return 0; } int closemodem(struct modem *mdm) { tcsetattr(mdm->fd,TCSANOW,&(mdm->oldtio)); close(mdm->fd); return 0; }