static char *body;
/* --logo-send specific */
static char *logoname,*gsmnet;
+/* --ring-send specific */
+static char *ringname;
static enum modenum {
MODE_UNKNOWN=0,
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)
<command name>\n\
--logo-send:\n\
<dest. phone> <logo filename> [<GSMnet id>]\n\
+ --ring-send:\n\
+ <dest. phone> <ring filename>\n\
\n\
-c, --config\tRead this additional config file\n\
\t\t(def. \"" CONFIG_MAIN "\" and \"$HOME" CONFIG_HOME "\")\n\
{"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'},
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;
}
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);
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;
{&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},
}
}
+static inline void cmdline_ring_send(void)
+{
+ cmdline_phone();
+ if (!ringname) ringname=nextargstack();
+}
+
static void lockclose(int fd)
{
if (close(fd))
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) {
s=buf+bufl;
*/
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)
{
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);
}
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
}
for (i=0;i<NELEM(longopts);i++) {
if (longopts[i].val<MODE_FIRST) break;
if (!strstr(pname,longopts[i].name)) continue;
- if (mode==MODE_UNKNOWN) {
+ if (mode==MODE_UNKNOWN || mode==longopts[i].val) {
mode=longopts[i].val;
continue;
}
case MODE_SEND: /* FALLTHRU */
case MODE_SEND_MOBILDOCK: cmdline_send (); break;
case MODE_LOGO_SEND: cmdline_logo_send(); break;
+ case MODE_RING_SEND: cmdline_ring_send(); break;
case MODE_RECEIVE: cmdline_receive (); break;
default: assert(0);
}
case MODE_LOGO_SEND:
logoread();
break;
+ case MODE_RING_SEND:
+ ringread();
+ break;
case MODE_RECEIVE: break;
default: assert(0);
}
}
break;
case MODE_LOGO_SEND:
+ case MODE_RING_SEND: {
+struct hexdata *hd;
+
restore="\r\nAT+CSMP=17,,0,0";
devcmd(NULL,NULL,"\r\nAT+CSMP=81,,0,245");
devcmd("\n> ",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 */