/* * gcom version 0.3 - 3G/GPRS datacard management utility * * Copyright (C) 2003 Paul Hardwick * * This program is free software; 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * See gcom.doc for more configuration and usage information. * */ /*************************************************************************** * $Id: gcom.c 10 2006-01-04 12:40:44Z paul $ * $HeadURL: http://10.0.0.4/svn/gcom/gcom.c $ ****************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "gcom.h" #define MAXLABELS 3000 /* Maximum number of labels */ #define MAXGOSUBS 128 /* Max depth */ #define STRINGL 1024 /* String lengths. Also, max script line length */ #define MAXPATH 1024 /* Max filename length (less or equal to STRINGL) */ #define MAXTOKEN 20 /* Maximum token or label length */ #define GTDEVICE "/dev/modem" #define BOOL unsigned char #define NVARS 286 /* a-z, a0-z9 == 26*11 */ extern char *optarg; extern int optind, opterr; FILE *filep; char *script; int scriptspace; BOOL ifres; int lastpc,pc; /* program "counters" */ long resultcode=0; /* result code */ int ignorecase=1; /* no case sensitivity */ BOOL comecho=0; /* echo what's comin' in */ BOOL high_speed=0; long senddelay=0; /* 0/100th second character delay for sending */ long number; /* For getonearg() returning an long */ char **label; /* Index of labels for goto and gosub */ int *labelpc; /* Positions of said labels in script */ int labels; /* Number of labels found in script */ long intvars[NVARS]; /* [a-z][0-9] integer variables */ char string[STRINGL]; /* For getstring() returns and misc. use (misuse) */ char *stringvars[NVARS]; /* $[a-z][0-9] string variables */ char cspeed[10]; /* Ascii representation of baudrate */ int speed=B0; /* Set to B110, B150, B300,..., B38400 */ char device[MAXPATH]; /* Comm device. May be "-" */ char token[MAXTOKEN]; /* For gettoken() returns */ char scriptfile[MAXPATH]; /* Script file name */ BOOL verbose=0; /* Log actions */ struct termio cons, stbuf, svbuf; /* termios: svbuf=before, stbuf=while */ int comfd=0; /* Communication file descriptor. Defaults to stdin. */ char msg[STRINGL]; /* Massage messages here */ int preturn,returns[MAXGOSUBS]; int clocal=0; int parity=0, bits=CS8, stopbits=0; unsigned long hstart,hset; char NullString[]={ "" }; BOOL lastcharnl=1; /* Indicate that last char printed from getonebyte was a nl, so no new one is needed */ //"open com \"/dev/modem\"\nset com 38400n81\nset senddelay 0.05\nsend \"ATi^m\"\nget 2 \" ^m\" $s\nprint \"Response : \",$s,\"\\n\"\nget 2 \" ^m\" $s\nprint \"Response :\",$s,\"\\n\"\nget 2 \" ^m\" $s\nprint \"Response : \",$s,\"\\n\"\n\n"; /* Prototypes. */ unsigned long htime(void); void dormir(unsigned long microsecs); void dotestkey(void); void ext(long xtc); void vmsg(char *text); void skipline(void); void printwhere(void); void writecom(char *text); int getonebyte(void); void dodump(void); void serror(char *text, int exitcode); void skipspaces(void); void getopen(void); void getclose(void); int gettoken(void); void skiptoken(void); long getvalue(void); void getcomma(void); void gethardstring(void); void getstring(void); unsigned long getdvalue(void); void dolet(void); int dowaitquiet(void); int dowaitfor(void); BOOL getonoroff(void); void setcom(void); void doset(void); void dogoto(void); void dogosub(void); unsigned char getonearg(void); void doif(void); int getindex(void); int getintindex(void); int getstringindex(void); void doget(void); void doprint(int channel); void doclose(void); void opendevice(void); void doopen(void); int doscript(void); /* Returns hundreds of seconds */ unsigned long htime(void) { struct timeval timenow; gettimeofday(&timenow,NULL); return(100L*(timenow.tv_sec-hstart)+(timenow.tv_usec)/10000L-hset); } /* I use select() 'cause CX/UX 6.2 doesn't have usleep(). On Linux, usleep() uses select() anyway. */ void dormir(unsigned long microsecs) { struct timeval timeout; timeout.tv_sec=microsecs/1000000L; timeout.tv_usec=microsecs-(timeout.tv_sec*1000000L); select(1,0,0,0,&timeout); } /* Tests for ENTER key */ void dotestkey(void) { fd_set fds; struct timeval timeout; timeout.tv_sec=0L; timeout.tv_usec=10000L; FD_ZERO(&fds); FD_SET(0,&fds); /* Prepare to select() from stdin */ resultcode=select(1,&fds,0,0,&timeout); if(resultcode) getchar(); } /* Exit after resetting terminal settings */ void ext(long xtc) { ioctl(1, TCSETA, &cons); exit(xtc); } /* Log message if verbose is on */ void vmsg(char *text) { time_t t; char *ct; if(verbose) { if(lastcharnl==0) { fprintf(stderr,"\n"); lastcharnl=1; } t=time(0); ct=ctime(&t); fprintf(stderr,"gcom %c%c:%c%c:%c%c -> %s\n", ct[11],ct[12],ct[14],ct[15],ct[17],ct[18], text); } } /* Skip to next statement */ void skipline(void) { while(script[pc]!='\n' && script[pc]!=0) pc++; if(script[pc]) pc++; } void printwhere(void) { int a,b,c; sprintf(msg,"@%04d ",pc); a=pc; skipline(); b=pc-1; pc=a; c=strlen(msg); for(;a "); for(a=6;a' || script[pc]=='!') { token[0]=0; while(script[pc]=='=' || script[pc]=='<' || script[pc]=='>' || script[pc]=='!') { token[tokenp++]=script[pc++]; } token[tokenp]=0; return(0); } if(script[pc]=='#') { strcpy(token,"rem"); pc++; return(0); } if(script[pc]=='/' && script[pc+1]=='/') { strcpy(token,"rem"); pc+=2; return(0); } if(script[pc]==':') { strcpy(token,"label"); pc++; return(0); } while(script[pc]!=' ' && script[pc]!='\n' && script[pc]!='\t' && script[pc]!='(') { token[tokenp]=script[pc++]; if(token[tokenp]>='A' && token[tokenp]<='Z') { token[tokenp]=token[tokenp]-'A'+'a'; } if(tokenp++==MAXTOKEN-1) serror("Token too long",5); } token[tokenp]=0; if(strcmp(token,"then")==0) return(gettoken()); /* Ignore then for if */ return(0); } /* shitfaced recursive value parser. must write better one */ long getvalue(void) { unsigned long p=0; int goone=1; unsigned int a; int base,amode; skipspaces(); if(script[pc]=='(') { pc++; p=getvalue(); getclose(); } else if(script[pc]==')') { return(p); } else if(script[pc]=='"' || script[pc]=='\'' || script[pc]=='$' ) { serror("Did not expect a string",7); } else if( (script[pc]>='a' && script[pc]<='z' && script[pc+1]>='a' && script[pc+1]<='z') || (script[pc]>='A' && script[pc]<='Z' && script[pc+1]>='A' && script[pc+1]<='Z') ) { gettoken(); getopen(); if(strcmp(token,"len")==0) { char toto[STRINGL]; strcpy(toto,string); getstring(); p=strlen(string); strcpy(string,toto); } else if(strcmp(token,"htime")==0) { p=htime(); } else if(strcmp(token,"time")==0) { p=time(0); } else if(strcmp(token,"pid")==0) { p=getpid(); } else if(strcmp(token,"ppid")==0) { p=getppid(); } else if(strcmp(token,"verbose")==0) { p=verbose; } else if(strcmp(token,"isatty")==0) { p=isatty(getvalue()); } else if(strcmp(token,"baud")==0) { p=atol(cspeed); } else if(strcmp(token,"access")==0) { char toto[STRINGL]; char afile[STRINGL]; strcpy(toto,string); getstring(); strcpy(afile,string); getcomma(); getstring(); if(string[0]==0) serror("Missing access mode[s]",5); amode=0; for(a=0;a='a' && script[pc]<='z') || (script[pc]>='A' && script[pc]<='Z') ) { p=intvars[getintindex()]; } else if(script[pc]>='0' && script[pc]<='9') { base=10; if(script[pc]=='0') { base=8; pc++; if(script[pc]=='x' || script[pc]=='X') { base=16; pc++; } if(script[pc]=='%') { base=2; pc++; } } while((script[pc]>='0' && script[pc]<='9') || (script[pc]>='a' && script[pc]<='f') || (script[pc]>='A' && script[pc]<='F')) { if(script[pc]>='a' && script[pc]<='f') { p=p*base+script[pc++]-'a'+10; } else if(script[pc]>='A' && script[pc]<='F') { p=p*base+script[pc++]-'A'+10; } else { p=p*base+script[pc++]-'0'; } } } else { goone=0; } } return(p); } void getcomma(void) { skipspaces(); if(script[pc++]!=',') serror("Comma expected",5); } void gethardstring(void) { int a=0; skipspaces(); while(script[pc]!=0 && script[pc]!=' ' && script[pc]!='\t' && script[pc]!='\n') { string[a++]=script[pc++]; } string[a]=0; } /* Parse a string from script[pc] */ void getstring(void) { FILE *fp; time_t t; unsigned int a,b; int c,p=0; unsigned char ch,match; string[0]=0; skipspaces(); if(script[pc]!='"' && script[pc]!='\'' && script[pc]!='$' ) { serror("Expected a string",7); } while(script[pc]!=' ' && script[pc]!='\t' && script[pc]!='\n' && script[pc]!=',' && script[pc]!=')' && script[pc]!='=' && script[pc]!='<' && script[pc]!='>' && script[pc]!='!' ) { if(script[pc]=='+') pc++; skipspaces(); if( (script[pc]=='$' && script[pc+1]>='a' && script[pc+1]<='z' && script[pc+2]>='a' && script[pc+2]<='z') || (script[pc]=='$' && script[pc+1]>='A' && script[pc+1]<='Z' && script[pc+2]>='A' && script[pc+2]<='Z') ) { pc++; gettoken(); getopen(); if(strcmp(token,"time")==0) { t=time(0); strcat(string,ctime(&t)); string[strlen(string)-1]=0; } else if(strcmp(token,"rpipe")==0) { char toto[STRINGL]; strcpy(toto,string); getstring(); if((fp=popen(string,"r"))==NULL) serror("Could not popen!",4); fgets(string,STRINGL-1,fp); string[strlen(string)-1]=0; pclose(fp); strcat(toto,string); strcpy(string,toto); } else if(strcmp(token,"env")==0) { char toto[STRINGL]; strcpy(toto,string); getstring(); if(getenv(string)) strcat(toto,(char *)getenv(string)); strcpy(string,toto); } else if(strcmp(token,"hms")==0) { long sec,min,hour; sec=getvalue(); min=sec/60L; sec-=min*60L; hour=min/60L; min-=hour*60L; sprintf(string,"%s%02ld:%02ld:%02ld",string,hour,min,sec); } else if(strcmp(token,"dev")==0) { strcat(string,device); } else if(strcmp(token,"cwd")==0) { getcwd(string,STRINGL); } else if(strcmp(token,"baud")==0) { strcat(string,cspeed); } else if(strcmp(token,"str")==0 || strcmp(token,"ltoa")==0) { sprintf(string,"%s%ld",string,getvalue()); } else if(strcmp(token,"hexu")==0) { sprintf(string,"%s%lX",string,getvalue()); } else if(strcmp(token,"hex")==0) { sprintf(string,"%s%lx",string,getvalue()); } else if(strcmp(token,"oct")==0) { sprintf(string,"%s%lo",string,getvalue()); } else if(strcmp(token,"dirname")==0) { char toto[STRINGL]; strcpy(toto,string); getstring(); b=0; for(a=0;a='A' && string[a]<='Z' ) string[a]=string[a]-'A'+'a'; } strcat(toto,string); strcpy(string,toto); } else if(strcmp(token,"toupper")==0) { char toto[STRINGL]; strcpy(toto,string); getstring(); for(a=0;a='a' && string[a]<='z' ) string[a]=string[a]-'a'+'A'; } strcat(toto,string); strcpy(string,toto); } else if(strcmp(token,"basename")==0) { char toto[STRINGL]; strcpy(toto,string); getstring(); b=0; for(a=0;astrlen(string)) serror("String is shorter than second argument",7); c=strlen(toto); a=strlen(string)-b; while(b!=0 && string[a]!=0) { toto[c++]=string[a++]; b--; } toto[c]=0; strcpy(string,toto); } else if(strcmp(token,"left")==0) { char toto[STRINGL]; strcpy(toto,string); getstring(); getcomma(); b=getvalue(); if(b>strlen(string)) serror("String is shorter than second argument",7); c=strlen(toto); a=0; while(b!=0 && string[a]!=0) { toto[c++]=string[a++]; b--; } toto[c]=0; strcpy(string,toto); } else if(strcmp(token,"mid")==0) { char toto[STRINGL]; strcpy(toto,string); getstring(); getcomma(); a=getvalue(); getcomma(); b=getvalue(); if(a>strlen(string)) serror("String is shorter than second argument",7); c=strlen(toto); while(b!=0 && string[a]!=0) { toto[c++]=string[a++]; b--; } toto[c]=0; strcpy(string,toto); } else if(strcmp(token,"sex")==0) { strcat(string,"You're a naughty boy, you!"); } else serror("Invalid string funtion",5); getclose(); } else if(script[pc]=='$') { strcat(string,stringvars[getstringindex()]); } else if(script[pc]=='"' || script[pc]=='\'') { match=script[pc++]; while(script[pc]!=match) { ch=script[pc++]; if(ch==0) serror("Umatched quote.",5); if(ch=='\\') { if(script[pc]<='7' && script[pc]>='0' && script[pc+1]<='7' && script[pc+1]>='0' ) { ch=0; while(script[pc]>='0' && script[pc]<='7') { ch=8*ch+script[pc++]-'0'; } } else { switch(script[pc]) { case 'T' : case 't' : ch=9; break; case 'R' : case 'r' : ch=13; break; case 'N' : case 'n' : ch=10; break; case 'B' : case 'b' : ch=8; break; case 'F' : case 'f' : ch=12; break; case '"' : case '^' : case '\'' : case '\\' : ch=script[pc]; break; default : serror("Malformed escaped character",5); } pc++; } } else if(ch=='^') { ch=script[pc]; if(ch!='^' && ch!='"' && ch!='\'' && ch!='\\' ) { ch=ch&31; /* Control char */ } pc++; } p=strlen(string); string[p++]=ch; string[p]=0; } pc++; /* Space over quote */ } else { p=strlen(string); string[p++]=script[pc++]; string[p]=0; } } } /* Get a value, multiply by a hundred (for time values) */ unsigned long getdvalue(void) { float f; gettoken(); skipspaces(); sscanf(token,"%f",&f); f+=0.00001; /* Rounding errors */ return(100.0*f); } void dolet(void) { int index; BOOL svar=0; skipspaces(); if(script[pc]=='$') { svar=1; index=getstringindex(); } else index=getintindex(); skipspaces(); gettoken(); if(strcmp(token,"=")!=0) serror("Bad LET assignment, '=' missing",5); skipspaces(); if(svar) { getstring(); strcpy(stringvars[index],string); } else { intvars[index]=getvalue(); } } /* See documentation for doXXX() functions */ int dowaitquiet(void) { unsigned long timeout,timequiet,quiet,now; int c,quit; timeout=htime()+getdvalue(); quiet=getdvalue(); timequiet=htime()+quiet; quit=1; while(quit==1) { now=htime(); c=getonebyte(); if(c!= -1) timequiet=now+quiet; if(now>=timequiet) quit=0; if(now>=timeout) quit=255; } return(quit); } int dowaitfor(void) { char strings[20][80]; char buffer[128]; unsigned long timeout; unsigned int a; int b,c; b=0; buffer[127]=0; skipspaces(); timeout=htime()+getdvalue(); while(script[pc]==',' || script[pc]=='$' || script[pc]=='"' || script[pc]=='\'' ) { if(script[pc]==',') pc++; getstring(); skipspaces(); strcpy(strings[b],string); if(ignorecase) { for(a=0;a='A' && strings[b][a]<='Z') { strings[b][a]=strings[b][a]-'A'+'a'; } } } b++; } strings[b][0]=0; while(htime()='A' && c<='Z') c=c-'A'+'a'; } for(a=0;a<127;a++) buffer[a]=buffer[a+1]; //shuffle down buffer[126]=c; b=0; while(strings[b][0]) { c=strlen(strings[b]); if (strcmp(strings[b],&buffer[127-c]) == 0){ return(b); } b++; } } } return(-1); } /* Parse script for "on" or "off" wich are tokens, not strings */ BOOL getonoroff(void) { int a,b; b=pc; gettoken(); if(strcmp(token,"on")==0) return(1); if(strcmp(token,"off")==0) return(0); pc=b; a=getvalue(); if(a!=0 && a!=1) serror("Bad value (should be on or off, 1 or 0.)",5); return(a); } void setcom(void) { stbuf.c_cflag &= ~(CBAUD | CSIZE | CSTOPB | CLOCAL | PARENB); stbuf.c_cflag |= (speed | bits | CREAD | clocal | parity | stopbits ); if (ioctl(comfd, TCSETA, &stbuf) < 0) { serror("Can't ioctl set device",1); } } void doset(void) { struct termio console; int a,b; gettoken(); if(strcmp(token,"echo")==0) { a=0; if(getonoroff()) a=ECHO|ECHOE; if(ioctl(0, TCGETA, &console)<0) { serror("Can't ioctl FD zero!\n",2); } console.c_lflag &= ~(ECHO | ECHOE); console.c_lflag |= a; ioctl(0, TCSETA, &console); } else if(strcmp(token,"senddelay")==0) { senddelay=10000L*getdvalue(); } else if(strcmp(token,"clocal")==0) { clocal=0; if(getonoroff()) clocal=CLOCAL; setcom(); } else if(strcmp(token,"umask")==0) { umask(getvalue()&0777); } else if(strcmp(token,"verbose")==0) { verbose=getonoroff(); } else if(strcmp(token,"comecho")==0) { comecho=getonoroff(); } else if(strcmp(token,"ignorecase")==0) { ignorecase=getonoroff(); } else if(strcmp(token,"com")==0) { skipspaces(); if(script[pc]=='$' || script[pc]=='\'' || script[pc]=='"') { getstring(); strcpy(token,string); } else gettoken(); a=0; b=0; while(token[b]>='0' && token[b]<='9') { a=10*a+token[b++]-'0'; } if(token[b]) { switch(token[b]) { case 'n': parity=0; break; case 'e': parity=PARENB; break; case 'o': parity=PARENB|PARODD; break; default : serror("Parity can only ben E, N, or O",5); } b++; if(token[b]) { switch(token[b]) { case '5' : bits=CS5; break; case '6' : bits=CS6; break; case '7' : bits=CS7; break; case '8' : bits=CS8; break; default : serror("Bits can only be 5, 6, 7, or 8",5); } b++; if(token[b]) { switch(token[b]) { case '1': stopbits=0; break; case '2': stopbits=CSTOPB; break; default : serror("Stop bits can only be 1 or 2",5); } } } } sprintf(cspeed,"%d",a); switch(a) { case 0: speed = B0;break; case 50: speed = B50;break; case 75: speed = B75;break; case 110: speed = B110;break; case 150: speed = B150;break; case 300: speed = B300;break; case 600: speed = B600;break; case 1200: speed = B1200;break; case 2400: speed = B2400;break; case 4800: speed = B4800;break; case 9600: speed = B9600;break; case 19200: speed = B19200;break; case 38400: speed = B38400;break; case 57600: speed = B57600;break; case 115200: { if(high_speed == 0) speed = B115200; else speed = B57600; break; } case 460800: speed = B460800; break; default: serror("Invalid baudrate",1); } setcom(); } } void dogoto(void) { int a,originalpos; originalpos=pc; gettoken(); for(a=0;a=labels) { pc=originalpos; sprintf(msg,"Label \"%s\" not found",token); serror(msg,5); } else { pc=labelpc[a]; } } void dogosub(void) { int a; if(preturn==MAXGOSUBS) serror("Reached maximum GOSUB depth",3); a=pc; gettoken(); returns[preturn++]=pc; pc=a; dogoto(); } /* Gets arguments and returns 0 for a string, 1 for an int. Used with if */ BOOL getonearg(void) { if(script[pc]=='"' || script[pc]=='\'' || script[pc]=='$' ) { getstring(); return(0); } else { number=getvalue(); return(1); } } void doif(void) { char stringarg[STRINGL]; char tokencopy[MAXTOKEN]; int intarg; skipspaces(); ifres=0; if(getonearg()) { intarg=number; gettoken(); skipspaces(); if(getonearg()!=1) serror("Comparison mis-match",7); if(strcmp(token,"<")==0) { if(intarg")==0) { if(intarg>number) ifres=1; } else if(strcmp(token,">=")==0) { if(intarg>=number) ifres=1; } else if(strcmp(token,"<>")==0) { if(intarg!=number) ifres=1; } else if(strcmp(token,"!=")==0 || strcmp(token,"<>")==0) { if(intarg!=number) ifres=1; } } else { strcpy(stringarg,string); gettoken(); strcpy(tokencopy,token); skipspaces(); if(getonearg()!=0) serror("Comparison mis-match",7); if(strcmp(tokencopy,"<")==0) { if(strcmp(stringarg,string)<0) ifres=1; } if(strcmp(tokencopy,"<=")==0) { if(strcmp(stringarg,string)<=0) ifres=1; } else if(strcmp(tokencopy,"=")==0) { if(strcmp(stringarg,string)==0) ifres=1; } else if(strcmp(tokencopy,">")==0) { if(strcmp(stringarg,string)>0) ifres=1; } else if(strcmp(tokencopy,">=")==0) { if(strcmp(stringarg,string)>=0) ifres=1; } else if(strcmp(tokencopy,"!=")==0 || strcmp(tokencopy,"<>")==0) { if(strcmp(stringarg,string)!=0) ifres=1; } } if(!ifres) skipline(); } int getindex(void) { int index; index=script[pc++]; if(index>='A' && index<='Z') index=index-'A'+'a'; if(index>'z' || index<'a') serror("Malformed variable name",7); index=index-'a'; if(script[pc]>='0' && script[pc]<='9') { index=index+(1+script[pc++]-'0')*26; } return(index); } /* Parse script to find integer variable index */ int getintindex(void) { skipspaces(); if(script[pc]=='$') serror("Integer variable expected",7); return(getindex()); } /* Parse script to find string variable index and allocate memory for storage as needed. */ int getstringindex(void) { int index; skipspaces(); if(script[pc++]!='$') serror("String variable expected",7); index=getindex(); if(stringvars[index]==NullString) { stringvars[index]=(char *)malloc(STRINGL); if(stringvars[index]==NULL) serror("Could not malloc",3); stringvars[index][0]=0; } return(index); } void doget(void) { char terminators[STRINGL]; unsigned int a; int b,c,index; int goahead=1; unsigned long timeout; timeout=htime()+getdvalue(); getstring(); strcpy(terminators,string); index=getstringindex(); string[0]=0; b=0; resultcode=0; while(goahead && htime()