X-Git-Url: https://git.jankratochvil.net/?p=mdsms.git;a=blobdiff_plain;f=mdsms.c;h=bb64c6939275209fa9d76f1f9931e365f5c3a3e0;hp=845c6297691f88a198dd2a8d495f33aa32cab68f;hb=7a7d9459bf612525398b5bcda5a5969838d2090b;hpb=3b127365dbbc640bc1a0813b24baa925b99f5079 diff --git a/mdsms.c b/mdsms.c index 845c629..bb64c69 100644 --- a/mdsms.c +++ b/mdsms.c @@ -101,6 +101,8 @@ static size_t bodylen; static char *body; /* --logo-send specific */ static char *logoname,*gsmnet; +/* --ring-send specific */ +static char *ringname; static enum modenum { MODE_UNKNOWN=0, @@ -109,7 +111,8 @@ static enum modenum { MODE_SEND =MODE_FIRST+0, /* --send / --send-mobildock */ MODE_SEND_MOBILDOCK=MODE_FIRST+1, /* --send-mobildock in before readtimen is set */ MODE_RECEIVE =MODE_FIRST+2, /* --receive */ - MODE_LOGO_SEND =MODE_FIRST+3 /* --logo-send */ + MODE_LOGO_SEND =MODE_FIRST+3, /* --logo-send */ + MODE_RING_SEND =MODE_FIRST+4 /* --ring-send */ } mode=MODE_UNKNOWN; #define MODE_ORDER(x) ((x)-MODE_FIRST) #define MODE_NAME(x) (longopts[MODE_ORDER((x))].name) @@ -240,6 +243,8 @@ Usage: " PACKAGE " [-c|--config ] [-d|--device ]\n\ \n\ --logo-send:\n\ []\n\ + --ring-send:\n\ + \n\ \n\ -c, --config\tRead this additional config file\n\ \t\t(def. \"" CONFIG_MAIN "\" and \"$HOME" CONFIG_HOME "\")\n\ @@ -284,10 +289,13 @@ static const struct option longopts[]={ {"send-mobildock",0,0,MODE_SEND_MOBILDOCK}, {"receive" ,0,0,MODE_RECEIVE}, {"logo-send" ,0,0,MODE_LOGO_SEND}, +{"ring-send" ,0,0,MODE_RING_SEND}, /* Mode aliases may follow in no particular order * * as long as no non-mode options is between them */ {"send-md" ,0,0,MODE_SEND_MOBILDOCK}, {"recv" ,0,0,MODE_RECEIVE}, +{"logo" ,0,0,MODE_LOGO_SEND}, +{"ring" ,0,0,MODE_RING_SEND}, {"config" ,1,0,'c'}, {"device" ,1,0,'d'}, {"log" ,1,0,'L'}, @@ -314,6 +322,18 @@ static void chkfclose(FILE *f,const char *fname) error("^Error closing \"%s\"",fname); } +static long getfilesize(FILE *f,const char *fname) +{ +long size; + + if (fseek(f,0,SEEK_END)) + error("^Error seeking to end of \"%s\"",fname); + if ((size=ftell(f))<0) + size=-1,error("^Error measuring \"%s\"",fname); + rewind(f); + return(size); +} + static void readfile(const char *fname,char quiet) { FILE *f; @@ -334,14 +354,10 @@ static unsigned tot=0; } if (verbose>=2) error(".Reading config file \"%s\"",fname); - if (fseek(f,0,SEEK_END)) - error("^Error seeking to end of \"%s\"",fname); - if ((size=ftell(f))<0) - size=0,error("^Error measuring \"%s\"",fname); + if ((size=getfilesize(f,fname))==-1) size=0; if (size>MAXCONFIG) error("File \"%s\" is too long, read only %d bytes",fname,MAXCONFIG); chk(buf=malloc((size?size:MAXCONFIG)+1)); - rewind(f); got=fread(buf,1,(size?size:MAXCONFIG),f); if (size && got!=size) error("File \"%s\" read error, got only %u bytes of %ld",fname,got,size); @@ -534,6 +550,7 @@ int i; case MODE_SEND_MOBILDOCK: case MODE_RECEIVE: case MODE_LOGO_SEND: + case MODE_RING_SEND: if (mode_stamp && mode_stamp!=seq) break; mode=optc; mode_stamp=seq; @@ -572,6 +589,7 @@ static const struct nullcheck { {&phone,MODE_BIT(MODE_SEND)|MODE_BIT(MODE_SEND_MOBILDOCK)|MODE_BIT(MODE_LOGO_SEND), "destination phone number"}, {&logoname,MODE_BIT(MODE_LOGO_SEND),"logo filename"}, + {&ringname,MODE_BIT(MODE_RING_SEND),"ring filename"}, {&body,MODE_BIT(MODE_RECEIVE),"body text"}, /* we allow empty bodies for SENDs */ #if 0 {&gsmnet,"GSM operator network code",MODE_LOGO_SEND}, @@ -689,6 +707,12 @@ either \"" WORD_NET "\" or \"" WORD_GROUP "\", but found length %d: %s", } } +static inline void cmdline_ring_send(void) +{ + cmdline_phone(); + if (!ringname) ringname=nextargstack(); +} + static void lockclose(int fd) { if (close(fd)) @@ -784,17 +808,15 @@ static const char *record; static char *catchdata; static size_t catchdatal,catchdatasiz; -static void catched(const char *end) +static void catched(const char *end,char edata) { size_t len; -const char *p1,*p2; +const char *p; if (!record) return; assert(end>=record); - p1=memchr(record,'\n',end-record); - p2=memchr(record,'\r',end-record); - if (!p1 || (p1 && p2 && p2catchdatasiz) @@ -803,7 +825,7 @@ const char *p1,*p2; memcpy(catchdata+catchdatal,record,len); catchdatal+=len; } - record=(p1?NULL:end); + record=(p?NULL:end); assert(catchdatal<=catchdatasiz); } @@ -860,21 +882,21 @@ static size_t bufl; ssize_t got; char *hit,*s; va_list ap; -char errout,extend,convcr; +char errout,extend,noconvcr,edata; long alarmtime; const char *osend; static const char emptystring[]=""; if (!term) term="\nOK\n"; - convcr=!strchr(term,'\r'); if (!strcmp(send," ")) send=NULL; /* GCC formatstring-check workaround */ if (!(osend=send)) send=""; + if ((noconvcr=(catch && *catch=='@'))) catch++; if ((errout=(*send=='!'))) send++; errout|=(maxretryn==-1); if ((extend=(*send=='~'))) send++; alarmtime=readtimen*(extend?EXT_READTIME:1); - d8("devcmd(), alarmtime=%ld, errout=%d, extend=%d, convcr=%d, osend=%p, bufl=%d, buf: %s\n", - alarmtime,errout,extend,convcr,osend,bufl,reform(buf,0)); + d8("devcmd(), alarmtime=%ld, errout=%d, extend=%d, noconvcr=%d, osend=%p, bufl=%d, buf: %s\n", + alarmtime,errout,extend,noconvcr,osend,bufl,reform(buf,0)); if (0) { err: alarm(0); @@ -922,6 +944,7 @@ err: record=NULL; wasalarm=0; alarm(alarmtime); + edata=(noconvcr?'\r':'\n'); if (!osend) { got=bufl; bufl=0; @@ -946,14 +969,14 @@ skipread: buf[bufl2]='\0'; s=buf+bufl; while (buf+bufl2>s && (s=memchr(s,'\0',buf+bufl2-s))) *s++=REPL_NULLCHAR; - if (verbose>=2) + if (verbose>=3) error("\nGot chunk of data from device: %s",reform(buf+bufl,0)); - if (convcr) { + if (!noconvcr) { s=buf+bufl; while (buf+bufl2>s && (s=memchr(s,'\r',buf+bufl2-s))) *s++='\n'; } bufl=bufl2; - catched(buf+bufl); assert(!record || record==buf+bufl); + catched(buf+bufl,edata); assert(!record || record==buf+bufl); assert(bufl=catchl && (hit=strstr(buf,catch))) { + if (catch && !record && bufl>=catchl && (hit=strstr(buf,catch))) { record=hit+catchl; - catched(buf+bufl); assert(!record || record==buf+bufl); + catched(buf+bufl,edata); assert(!record || record==buf+bufl); } if ( bufl>= terml && (hit=strstr(buf,term))) { memmove(buf,hit+terml,(bufl2=(buf+bufl)-(hit+terml))); bufl=bufl2; @@ -972,7 +995,7 @@ skipread: } if (bufl=2) error(".Returning data %s for cmd %s",reform(catchdata,0),reform(send,1)); return(catchdata); } @@ -1084,7 +1107,22 @@ static inline unsigned char charconv(char c,size_t offs) */ static char *pdudata; -static char hexdata[140*2+1]; +static struct hexdata { + struct hexdata *next; + char data[140*2+1]; + } *hexdata,**hexdatatail=&hexdata; + +static void nokiaprep(unsigned char *bin,size_t w) +{ +struct hexdata *hd; + assert(w<=140); + chk(hd=malloc(sizeof(*hd))); + *hexdatatail=hd; + hd->next=NULL; + hexdatatail=&hd->next; + textconv(hd->data,bin,w); + if (verbose>=2) error("\nWill send hexdata: %s",hd->data); +} static inline void logoread(void) { @@ -1107,6 +1145,7 @@ int sizex,sizey,bit; if (!(f=fopen(logoname,"rb"))) error("^!Cannot open logo file \"%s\" for r/o",logoname); got=fread(buf,1,sizeof(buf),f); + chkfclose(f,logoname); if (got>=20 && !memcmp(buf,"NOL",4)) { VARPRINTF2(gsmnetf,"%03.3u%02.2u",WORD(6),WORD(8)); assert(strlen(gsmnetf)==5); @@ -1165,9 +1204,79 @@ int sizex,sizey,bit; } w++; } - assert(chars==-1); assert(bits==0); assert(w==got); assert(w<=140); - textconv(hexdata,bin,w); - if (verbose>=2) error("\nWill send hexdata: %s",hexdata); + assert(chars==-1); assert(bits==0); assert(w==got); + nokiaprep(bin,w); +#undef WORD +} + +static inline void ringread(void) +{ +FILE *f; +unsigned char bin1[140]={ + 6, /* UDH length */ + 0x05, /* IEI */ + 0x04, /* IEDL */ + 0x15, 0x81, /* dest port (ring tones) */ + 0x15, 0x81 /* src port (unused) */ +#define BIN1_PAYLOAD (140-7) + }; +unsigned char binn[140]={ + 11, /* UDH length */ + 0x05, /* IEI */ + 0x04, /* IEDL */ + 0x15, 0x81, /* dest port (ring tones) */ + 0x15, 0x81, /* src port (unused) */ + 0x00, 0x03, /* multipart */ + /* 0x??, unique serial ID */ + /* 0x??, total messages */ + /* 0x??, message number (# from 1) */ +#define BINN_PAYLOAD (140-12) + }; +size_t got,want; +int totn,fragn; +long size; + +#define WORD(n) (((unsigned char)buf[(n)])|(((unsigned char)buf[(n)+1])<<8)) + + if (!(f=fopen(logoname,"rb"))) + error("^!Cannot open logo file \"%s\" for r/o",logoname); + if ((size=getfilesize(f,logoname))==-1) + error("!File size is essential to continue operation"); + if (size<0x103) + error("!File \"%s\" size %ld too small (must >=0x103)! Is it .000 file?", + logoname,size); + if (fseek(f,0x100,SEEK_SET)) + error("^Seeking error on \"%s\", ignoring",logoname); + size-=0x100; + if (size<=BIN1_PAYLOAD) { + if ((got=fread(bin1+7,1,size,f))!=size) + error("^Read error on \"%s\", wanted %ld, got %d",logoname,size,got); + error("\nSending ring tone \"%s\" as single SMS (size %ld, max %d)", + ringname,size,BIN1_PAYLOAD); + nokiaprep(bin1,7+size); + } + else { + totn=(size+BINN_PAYLOAD-1)/BINN_PAYLOAD; + if (totn>0xFF) + error("!File size %ld too large for multi-SMS ring upload (max=%d)", + size,BINN_PAYLOAD*0xFF); + binn[10]=totn; + if (verbose>=1) + error("\nSending ring tone \"%s\" as %d multi-SMSes (size %ld, max %d, frag %d)", + ringname,totn,size,BIN1_PAYLOAD,BINN_PAYLOAD); + binn[9]=time(NULL)&0x100; /* rand() would be better but it is a compatibility pain */ + if (verbose>=1) + error("\nUsing unique multi-SMS ID 0x%02X",(unsigned)binn[9]); + for (fragn=1;fragn<=totn;fragn++) { + binn[11]=fragn; + want=MIN(size,BINN_PAYLOAD); + if ((got=fread(binn+12,1,want,f))!=want) + error("^Read error on \"%s\", wanted %d, got %d",logoname,want,got); + nokiaprep(binn,12+want); + size-=want; + } + } + chkfclose(f,logoname); #undef WORD } @@ -1513,7 +1622,7 @@ enum modenum argsmode; for (i=0;i ",NULL,"\r\nAT+CMGS=\"%s\"",phone); - s=devcmd(NULL,"\n+CMGS:","!~%s\032",hexdata); - break; + while ((hd=hexdata)) { + if (!(s=devcmd(NULL,"\n+CMGS:","!~%s\032",hd->data))) break; + hexdata=hd->next; + free(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"); unlockdevice(0); /* Never bail-out when we got up to this point */ @@ -1716,11 +1837,11 @@ retrysendcmgf: d1("Lock-device succeeded\n"); do { d1("Reading a message for us...\n"); - if (!(s=devcmd("\r","+CMT:"," "))) + if (!(s=devcmd("\r","@+CMT:"," "))) goto retryall; if (!(i=receive_headerparse(s))) error("Receive-header parsing failed on: %s",s); - if (!(s=devcmd("\r","\n"," "))) + if (!(s=devcmd("\r","@\n"," "))) goto retryall; if (i) receive_accept(s); if (!devcmd("\n",NULL," ")) /* eat last '\n' */