X-Git-Url: http://git.jankratochvil.net/?p=mdsms.git;a=blobdiff_plain;f=mdsms.c;fp=mdsms.c;h=a630131a73c38d9808e1a5e252518592090b2b0d;hp=2b7edd1d795a576593d123e8de9823c47e1d4a2d;hb=f5a4142536d9895cf78d2e83c1d7ea0391081af0;hpb=3ded411478eb74cce19986adf7a6419ba907c446 diff --git a/mdsms.c b/mdsms.c index 2b7edd1..a630131 100644 --- a/mdsms.c +++ b/mdsms.c @@ -273,8 +273,10 @@ Usage: %s [-c|--config ] [-d|--device ]\n\ \tProgram to run on receive, message will be on stdin\n\ \t\tFollowing substitutes are recognized:\n\ \t\t%%p - source phone number\n\ -\t\t%%T - timestamp from SMSC as number of seconds from 1970\n\ -\t\t%%t - ctime(3) style timestamp (e.g. \"Wed Jun 30 21:49:08 1993\")\n\ +\t\t%%T - timestamp from SMSC as # of seconds from 1970 (-1 if invalid)\n\ +\t\t%%t - ctime(3) style timestamp (e.g. \"Wed Jun 30 21:49:08 1993\"),\n\ +\t\t empty string if invalid\n\ +\t\t%%s - originating SMSC number, if available (else empty)\n\ --logo-send:\n\ \t* Oper. logo: Enter custom network code MccMnc, e.g. 23002\n\ \t\t* Oper. logo: Specify \"%s\" to read network code from NOL file\n\ @@ -661,7 +663,7 @@ char *s; body=glueargstack(&bodylen," "); for (s=body;(s=strchr(s,'%'));s++) switch (*++s) { - case 'p': case 'T': case 't': break; + case 'p': case 'T': case 't': case 's': break; default: error(_("Unknown formatsymbol '%c' (use \"%%%%%c\" to fix it) at pos %d in: %s"), *s,*s,s-body,body); @@ -1088,7 +1090,7 @@ unsigned char bin[2+(MAXNUMLEN+1)/2]; textconv(pdusmsc,bin,bin[0]+1); } -static inline unsigned char charconv(char c,size_t offs) +static inline unsigned char charconv_send(char c,size_t offs) { switch (c) { case '@': return(0); @@ -1105,6 +1107,17 @@ static inline unsigned char charconv(char c,size_t offs) #endif } +static inline unsigned char charconv_recv(char c,size_t offs) +{ /* FIXME: unify with charconv_send() */ + switch (c) { + case 0: return('@'); + case 2: return('$'); + default: + return(c); + } +/* strict checking not done, see charconv_send */ +} + /* Logo format shamelessly stolen from GNokii-0.3.0: http://www.gnokii.org/ * Beware - Nokia Smart Messaging specification 1.0.0 and 2.0.0 is incompatible * with Nokia current product line implementation @@ -1311,7 +1324,7 @@ size_t offs=0; while (bodylen || inb) { if (!inb) { assert(bodylen>0); assert(!!*body); - inreg=charconv(*bodyr++,offs++); + inreg=charconv_send(*bodyr++,offs++); bodylen--; inb=7; } @@ -1457,13 +1470,9 @@ const char *sf,*ss; return(NULL); } -static char *receive_number; +static char *receive_number,*receive_smsc; static time_t receive_time; -/* +CMT: "+420602431329",,"99/10/25,03:21:03-00" */ -static int receive_headerparse(char *buf) -{ -char *s,*s1,*err; struct tm tm; static const struct { off_t strpos; @@ -1480,9 +1489,36 @@ static const struct { TP_ENT(18,tm_sec ,0,59,N_("second")), /* Time zone ignored */ }; -int i,val; +#define GETTIME(i) (*(int *)(((char *)&tm)+timeparse[(i)].tmpos)) + +static void maketime(const char *string) +{ +int val; +int i; + + for (i=0;itimeparse[i].max) { + error(_("Weird value of %s, is %d but expected %d..%d, setting to %d"), + _(timeparse[i].name),val,timeparse[i].min,timeparse[i].max,timeparse[i].min); + GETTIME(i)=timeparse[i].min; + } + } + if (tm.tm_year<70) tm.tm_year+=100; + tm.tm_mon--; + d7("mktime(y%dm%dd%dh%dm%ds%d)\n", + tm.tm_year,tm.tm_mon,tm.tm_mday,tm.tm_hour,tm.tm_min,tm.tm_sec); + if ((receive_time=mktime(&tm))==-1) + error(_("^mktime(3) failed for %s"),string); +} -#define DIGIT2(s) (((s)[0]-'0')*10+((s)[1]-'0')) +/* +CMT: "+420602431329",,"99/10/25,03:21:03-00" */ +static int receive_headerparse(char *buf) +{ +char *s,*s1,*err; +int i; + +#define DIGIT2ASC(s) (((s)[0]-'0')*10+((s)[1]-'0')) for (s=buf;*s==' ';s++); if (*s++!='"') { @@ -1494,6 +1530,7 @@ int i,val; error(_("Only one '\"' found in CMT header: %s"),buf); return(0); } + free(receive_smsc); receive_smsc=NULL; free(receive_number); chk(receive_number=malloc(s-s1+1)); memcpy(receive_number,s1,s-s1); receive_number[s-s1]='\0'; @@ -1504,28 +1541,16 @@ int i,val; return(0); } memset(&tm,0,sizeof(tm)); /* may be redundant */ - for (i=0;itimeparse[i].max) { - error(_("Weird value of %s, is %d but expected %d..%d, setting to %d"), - _(timeparse[i].name),val,timeparse[i].min,timeparse[i].max,timeparse[i].min); - val=timeparse[i].min; - } - *(int *)(((char *)&tm)+timeparse[i].tmpos)=val; - } + for (i=0;i>4; + b&=0x0F; + if (b<=0x09) + *text=b+'0'; + else { + *text='?'; + r++; + } + } + *text='\0'; + return(r); +} + +static void sctsparse(unsigned char *bin,const char *pduline,int offs) +{ +#define DIGIT2BIN(v) (((v)&0x0F)*10+(((v)>>4)&0x0F)) +int i; + + receive_time=-1; + memset(&tm,0,sizeof(tm)); /* may be redundant */ + for (i=0;i0x09 || (*bin&0xF0)>0x90) { + error(_("Invalid value of \"%s\" at offset %d in: %s"), + timeparse[i].name,offs,pduline); + return; + } + GETTIME(i)=DIGIT2BIN(*bin); + bin++; + } + maketime(pduline); + +#undef DIGIT2BIN +} + +static void receive_pdu(char *pduline) +{ +unsigned char pdu[140+0x100],*pdup,*pdue,oalen,inreg; +char text[160+1],*textp,*s; +size_t pdulinel=strlen(pduline),want; +size_t udl,udlb; +int inb,outb,xb; + + d2("receive_pdu: %s\n",pduline); + if (pdulinel>2*sizeof(pdu)) + { error(_("PDU too long (%d/2) to be valid: %s"),pdulinel,pduline); return; } + if (pdulinel&1) + { error(_("PDU length odd (%d): %s"),pdulinel,pduline); return; } + if (pdulinel<2*13) + { error(_("PDU length %d too small (min. 2*%d): %s"),pdulinel,13,pduline); return; } + for (pdup=pdu;*pduline;pduline+=2) { + if (!isxdigit(pduline[0]) || !(isxdigit(pduline[1]))) + { error(_("Invalid hex byte: %c%c on byte %d in: %s"), + pduline[0],pduline[1],pdup-pdu,pduline); return; } + *pdup++=(fromhex(pduline[0])<<4)|fromhex(pduline[1]); + } + pdue=pdup; + free(receive_smsc); + if (*pdu<=1) { + receive_smsc=NULL; + } + else { + if (*pdu>10) + { error(_("SMSC length too large (%d, max. %d): %s"),*pdu,10,pduline); return; } + chk(receive_smsc=malloc(1+2*(*pdu)+1)); + s=receive_smsc; + if (pdu[1]==ADDR_INT) *s++='+'; + else { + if (pdu[1]!=ADDR_NAT) + error(_("Unknown address type 0x%02X of %s, ignoring in PDU: %s"),_("SMSC"),pdu[1],pduline); return; + } + if (teldecode(s,pdu+2,2*(*pdu-1)-((pdu[1+(*pdu)]&0xF0)==0xF0))) + error(_("Some digits unrecognized in %s \"%s\", ignoring in PDU: %s"),_("SMSC"),receive_smsc,pduline); + } + pdup=pdu+1+(*pdu); + if (*pdup&0x03) /* PDU type */ + error(_("Unrecognized PDU type 0x%02X at offset %d, dropping: %s"),*pdup,pdup-pdu,pduline); + pdup++; + free(receive_number); + if ((oalen=*pdup++)>10) /* OA len */ + { error(_("Originating number too large (%d, max. %d): %s"),oalen,10,pduline); return; } + if (pdup+(want=1+(oalen+1)/2+10)>pdue) + { error(_("PDU length too short (want %d, is %d): %s"),(pdup-pdu)+want,pdue-pdu,pduline); return; } + chk(receive_number=malloc(1+2*(*pdup)+1)); + s=receive_number; + if (*pdup==ADDR_INT) *s++='+'; + else { + if (*pdup!=ADDR_NAT) + error(_("Unknown address type 0x%02X of %s, ignoring in PDU: %s"),_("originating number"),*pdup,pduline); return; + } + pdup++; + if (teldecode(s,pdup,oalen)) + error(_("Some digits unrecognized in %s \"%s\", ignoring in PDU at offset %d: %s"), + _("originating number"),receive_number,pdup-pdu,pduline); + pdup+=(oalen+1)/2; + if (*pdup) /* PID */ + error(_("PID number %02X unsupported, ignoring: %s"),*pdup,pduline); + pdup++; + if (*pdup) { /* DCS */ + if ((*pdup&0xF4)==0xF4) + { error(_("DCS 0x%02X indicates 8-bit data, unsupported, dropping: %s"),*pdup,pduline); return; } + error(_("DCS 0x%02X unsupported, will attempt decoding: %s"),*pdup,pduline); + } + pdup++; + sctsparse(pdup,pduline,pdup-pdu); + pdup+=7; + /* UDL */ + udl=*pdup++; + if (pdue-pdup>140) { + error(_("PDU data (%d) exceed maximum length of %d bytes, cut: %s"), + pdue-pdup,140,pduline); + pdue=pdup+140; + } + udlb=(udl*7+7)/8; + if (pdup+udlb>pdue) { +size_t udl1,udlb1; + + udlb1=pdue-pdup; + udl1=(udlb*8)/7; + error(_("PDU data length (%d/7->%d/8) longer than data (%d), cut to %d/7->%d/8: %s"), + udl,udlb,pdue-pdup,pduline); + udl=udl1; udlb=udlb1; + } + else + error(_("Trailing garbage ignored in PDU data (UDL %d/7->%d/8, got %d) in: %s"), + udl,udlb,pdue-pdup,pduline); + textp=text; + inb=outb=0; + inreg=0; /* GCC happiness */ + while (udl) { + if (!inb) { + inreg=*pdup++; + inb=8; + } + if (!outb) { + assert(textp>(unsigned)(7-inb))&((1<=1) + error(_(".Using AT+CMGF=1 (text mode)..")); + cmgf=1; + } + else { + /* CMGF=0 */ + if (verbose>=1) + error(_(".Using AT+CMGF=0 (PDU mode)..")); + cmgf=0; + } + } while (cmgf==-1); + } + switch (mode) { + case MODE_SEND: + if (cmgf) { devcmd("\n> ",NULL,"\r\nAT+CMGS=\"%s\"",phone); s=devcmd(NULL,"\n+CMGS:","!~%s\032",body); } else { - /* CMGF=0 */ devcmd("\n> ",NULL,"\r\nAT+CMGS=%d",(strlen(pdusmsc)+strlen(pdudata))/2); s=devcmd(NULL,"\n+CMGS:","!~%s%s\032",pdusmsc,pdudata); } @@ -1827,10 +2037,9 @@ struct hexdata *hd; } } break; case MODE_RECEIVE: - devcmd(NULL,NULL,"\r\nAT+CMGF=1"); restore="\r\nAT+CNMI=,0"; - devcmd(NULL,NULL,"\r\nAT+CSDH=0"); devcmd(NULL,NULL,"\r\nAT+CNMI=,2"); + devcmd(NULL,NULL,"\r\nAT+CSDH=0"); unlockdevice(0); /* Never bail-out when we got up to this point */ if (maxretryn!=-1 && verbose>=1) @@ -1853,11 +2062,14 @@ struct hexdata *hd; d1("Reading a message for us...\n"); if (!(s=devcmd("\r","@+CMT:"," "))) goto retryall; - if (!(i=receive_headerparse(s))) + if (cmgf && !(i=receive_headerparse(s))) error(_("Receive-header parsing failed on: %s"),s); if (!(s=devcmd("\r","@\n"," "))) goto retryall; - if (i) receive_accept(s); + if (cmgf) { + if (i) receive_text(s); + } + else receive_pdu(s); if (!devcmd("\n",NULL," ")) /* eat last '\n' */ goto retryall; } while (datawait(1));