package uk.co.mmscomputing.sms; import java.io.*; import uk.co.mmscomputing.dsp.phone.FSKInputStream; public class SMSLandLineInputStream extends FilterInputStream implements SMSConstants{ // Data Link Layer [1] 5.3.2 protected boolean sc2ms; // Service Center to Mobile Station or vice versa protected SMSDataUnitListener listener; private byte[] bytes; // buffer data private int len,index; public SMSLandLineInputStream(InputStream in,SMSDataUnitListener listener,boolean direction){ super(new FSKInputStream(in)); this.listener = listener; this.sc2ms = direction; } protected byte[] readDataUnit()throws IOException{ byte[] bytes=null; boolean isSegmented; int type,hlen,alen,csum; if(((FSKInputStream)in).readMarkSignal(55)){ // MARK signal; 55 .. 80 .. 105 MARK bits; [1] p.15 byte[] buf=new byte[176]; ByteArrayOutputStream data=new ByteArrayOutputStream(buf.length); type=in.read()&0x00FF; data.write(type&0x007F); // cache type at beginning of data array do{ isSegmented=((type&0x80)==0); hlen=in.read()&0x00FF; if((hlen+1)!=in.available()){ // available bytes: payload plus checksum throw new SMSException.Length(); } alen=in.read(buf,0,hlen); csum=in.read()&0x00FF; int checksum=type+hlen; // evaluate checksum for(int i=0;i<alen;i++){ // [1] 5.3.2.1 p.16 checksum+=buf[i]&0x00FF; } checksum=(-checksum)&0x00FF; // checksum: Two's complement modulo 256 of sum of bytes (excluding checksum byte). if(checksum!=csum){throw new SMSException.Checksum();} data.write(buf,0,alen); if(isSegmented){ // to do: send acknowledgement here if(!((FSKInputStream)in).readMarkSignal(55)){ throw new SMSException.Unspecified("Corrupt segmented message: Missing data chunk."); } type=in.read()&0x00FF; } }while(isSegmented); bytes=data.toByteArray(); System.out.println(toString(bytes,bytes.length)); } return bytes; } public int read()throws IOException{ while(!(index<len)){ try{ bytes=readDataUnit(); if(bytes==null){return -1;} SMSDataUnit tpdu=SMSDataUnitFactory.decode(sc2ms,bytes); listener.received(tpdu); // Tell listener about new data unit. bytes=tpdu.getUserData(); // data: i.e. the actual text message len =bytes.length; // length of message index=0; }catch(SMSException smse){ System.err.println(getClass().getName()+".read:\n\t"+smse); smse.printStackTrace(); if(smse instanceof SMSException.Length){ listener.send(new SMSDLLError(SMS_DLL_ERROR_LENGTH)); }else if(smse instanceof SMSException.Checksum){ listener.send(new SMSDLLError(SMS_DLL_ERROR_CHECKSUM)); }else if(smse instanceof SMSException.Type){ listener.send(new SMSDLLError(SMS_DLL_ERROR_TYPE)); }else if(smse instanceof SMSException.Unspecified){ listener.send(new SMSDLLError(SMS_DLL_ERROR_UNSPECIFIED)); } in.read(new byte[in.available()],0,in.available());// waste message index=len; // read next message } } return bytes[index++]; } public int read(byte[] buf, int off, int len)throws IOException{ if(buf==null){ throw new NullPointerException(getClass().getName()+".read(byte[] buf, int off, int len): buf is null"); } if((off<0)||(len<0)||(buf.length<(off+len))){ throw new IndexOutOfBoundsException(getClass().getName()+".read(byte[] buf, int off, int len): index off ["+off+"] or len ["+len+"] out of bounds ["+buf.length+"]."); } int b; int count=0; while(count<len){ b=read(); if(b==-1){return (count==0)?-1:count;} buf[off++]=(byte)b; count++; } return count; } static String[] hexs={"0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"}; static public String toString(byte[] bytes,int len){ String s="\n"; int i=0; while(i<len){ s+=" "; s+=hexs[(bytes[i]>>4)&0x0F]; s+=hexs[(bytes[i] )&0x0F]; if(((i+1)%8)==0){s+="\n";} i++; } if(((i+1)%8)!=0){s+="\n";} return s; } } // [1] ETSI ES 201 912 V1.2.1 (2004-06) // [2] ETS 300 659-1/2 (1997-02)