X-Git-Url: https://git.jankratochvil.net/?p=mdsms.git;a=blobdiff_plain;f=mdsms.c;h=757124d57002e69169ca40399f4addcfa68f652e;hp=03f391f2ada88f41be9f93c1eecdd2d5f9447345;hb=6a96f22d3c3e11f63ee17687a9de7f4c6ba854c5;hpb=361ff25359715a1d1242b6854578ba93d002d80d diff --git a/mdsms.c b/mdsms.c index 03f391f..757124d 100644 --- a/mdsms.c +++ b/mdsms.c @@ -1,3 +1,4 @@ +#define WANT_DECLARATIONS 1 #include "config.h" #ifndef lint static char rcsid[] ATTR_UNUSED = "$Id$"; @@ -62,6 +63,9 @@ static char rcsid[] ATTR_UNUSED = "$Id$"; #ifdef HAVE_LOCALE_H #include #endif +#ifdef HAVE_STDDEF_H +#include +#endif #ifdef HAVE_GETOPT_LONG #include @@ -69,6 +73,13 @@ static char rcsid[] ATTR_UNUSED = "$Id$"; #include "getopt.h" #endif + +/* Always override possible system defintions as it is safe (used by glib) */ +#undef MAX +#define MAX(a,b) ((a)>(b)?(a):(b)) +#undef MIN +#define MIN(a,b) ((a)<(b)?(a):(b)) + #define NELEM(x) (sizeof((x))/sizeof(*(x))) #ifndef DEBUG @@ -99,9 +110,9 @@ static int verbose static char *pname; static int dis_cleanup=0,devfd=-1; -static char *phone,*device,*logname,*lockfile,*smsmode,*pdusmscmode,*smsc,*maxretry,*readtime,*chartime,*cmdtime,*baud,*restore; +static char *phone,*device,*logname,*lockfile,*smsmode,*pdusmscmode,*smsc,*maxretry,*readtime,*chartime,*cmdtime,*waittime,*baud,*restore; static int readbody; -static long maxretryn=DEF_MAXRETRY,readtimen=-1,chartimen=DEF_CHARTIME,cmdtimen=DEF_CMDTIME,baudn=DEF_BAUD; +static long maxretryn=DEF_MAXRETRY,readtimen=-1,chartimen=DEF_CHARTIME,cmdtimen=DEF_CMDTIME,waittimen=DEF_WAITTIME,baudn=DEF_BAUD; #ifdef HAVE_CRTSCTS static int handshake_rtscts; static unsigned handshake_stamp; @@ -129,6 +140,8 @@ static char *body; static char *logoname,*gsmnet; /* --ring-send specific */ static char *ringname; +/* --picture-send specific */ +static char *picturename; static enum modenum { MODE_UNKNOWN=0, @@ -138,7 +151,8 @@ static enum modenum { 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_RING_SEND =MODE_FIRST+4 /* --ring-send */ + MODE_RING_SEND =MODE_FIRST+4, /* --ring-send */ + MODE_PICTURE_SEND =MODE_FIRST+5 /* --picture-send */ } mode=MODE_UNKNOWN; #define MODE_ORDER(x) ((x)-MODE_FIRST) #define MODE_NAME(x) (longopts[MODE_ORDER((x))].name) @@ -263,7 +277,7 @@ Usage: %s [-c|--config ] [-d|--device ]\n\ [-M|--smsmode ] [-P|--pdusmscmode ]\n\ [-s|--smsc ] [-m|--maxretry <#>]\n\ [-r|--readtime ] [-t|--chartime ] [-T|--cmdtime ]\n\ - [-v|--verbose] [-h|--help] [-V|--version]\n\ + [-w|--waittime ] [-v|--verbose] [-h|--help] [-V|--version]\n\ {--send | --send-mobildock | --receive | --logo-send}\n\ --send / --send-mobildock:\n\ [-f|--file] \n\ @@ -273,6 +287,8 @@ Usage: %s [-c|--config ] [-d|--device ]\n\ []\n\ --ring-send:\n\ \n\ + --picture-send:\n\ + \n\ \n\ -c, --config\tRead this additional config file\n\ \t\t(def. \"%s\" and \"$HOME%s\")\n\ @@ -292,6 +308,7 @@ Usage: %s [-c|--config ] [-d|--device ]\n\ \t\t multiplied %dx for long cmds)\n\ -t, --chartime\tMilliseconds between each char (def. %dms)\n\ -T, --cmdtime\tMilliseconds before each whole AT command (def. %dms)\n\ + -w, --waittime\tSeconds to prevent timeout of 9110 FaxModem (def. %ds)\n\ -v, --verbose\tIncrease verbosity level, more \"-v\"s give more messages\n\ -h, --help\tPrint a summary of the options\n\ -V, --version\tPrint the version number\n\ @@ -319,7 +336,7 @@ You may need to use the following line to catch all of this help text:\n\ #else _("\n\t\t(Not supported on this platform!)"), #endif -DEF_MAXRETRY,DEF_READTIME,DEF_READTIME_MOBILDOCK,EXT_READTIME,DEF_CHARTIME,DEF_CMDTIME, +DEF_MAXRETRY,DEF_READTIME,DEF_READTIME_MOBILDOCK,EXT_READTIME,DEF_CHARTIME,DEF_CMDTIME,DEF_WAITTIME, WORD_NET,WORD_GROUP); exit(EXIT_FAILURE); } @@ -331,12 +348,14 @@ static const struct option longopts[]={ {"receive" ,0,0,MODE_RECEIVE}, {"logo-send" ,0,0,MODE_LOGO_SEND}, {"ring-send" ,0,0,MODE_RING_SEND}, +{"picture-send" ,0,0,MODE_PICTURE_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}, +{"picture" ,0,0,MODE_PICTURE_SEND}, {"config" ,1,0,'c'}, {"device" ,1,0,'d'}, {"log" ,1,0,'L'}, @@ -351,6 +370,7 @@ static const struct option longopts[]={ {"readtime" ,1,0,'r'}, {"chartime" ,1,0,'t'}, {"cmdtime" ,1,0,'T'}, +{"waittime" ,1,0,'w'}, {"file" ,0,0,'f'}, {"verbose" ,0,0,'v'}, {"help" ,0,0,'h'}, @@ -562,6 +582,7 @@ static struct { { 'r',&readtime }, { 't',&chartime }, { 'T',&cmdtime }, + { 'w',&waittime }, }; static void processargs(int argp,char **args,const char *from) @@ -572,7 +593,7 @@ int i; seq++; optarg=NULL; optind=0; /* FIXME: Possible portability problem. */ - while ((optc=getopt_long(argp,args,"c:d:L:l:b:xCM:P:s:m:r:t:T:fvhV",longopts,NULL))!=EOF) switch (optc) { + while ((optc=getopt_long(argp,args,"c:d:L:l:b:xCM:P:s:m:r:t:T:w:fvhV",longopts,NULL))!=EOF) switch (optc) { case 'c': if (cfgstacki>=NELEM(cfgstack)) { error(_("Looping (%d) during attempt to read config file \"%s\", break-out"),NELEM(cfgstack),from); @@ -580,7 +601,7 @@ int i; } chk(cfgstack[cfgstacki++]=strdup(optarg)); break; - case 'd': case 'L': case 'b': case 'l': case 'M': case 'P': case 's': case 'm': case 'r': case 't': case 'T': + case 'd': case 'L': case 'b': case 'l': case 'M': case 'P': case 's': case 'm': case 'r': case 't': case 'T': case 'w': for (i=0;i=2) error(_(".Retrying phase, %d out of %ld.."),retrycnt,maxretryn); } -static char *reform(const char *s,int slot) +static const char *reform(const char *s,int slot) { static struct formslot { char *s; @@ -1229,7 +1264,7 @@ unsigned char bin[140]={ 0x05, /* IEI */ 0x04, /* IEDL */ 0x15, 0x83, /* dest port (group gfx) */ - 0x00, 0x00 /* src port (unused) */ + 0x15, 0x83 /* src port (unused) */ }; size_t got,r=0 /* GCC happiness */,w; ssize_t chars,bits; @@ -1376,6 +1411,91 @@ long size; #undef WORD } +#define PICTURE_WIDTH (72) +#define PICTURE_HEIGHT (28) + +static inline void pictureread(void) +{ +FILE *f; +unsigned char bin1[140]={ + 6, /* UDH length */ + 0x05, /* IEI */ + 0x04, /* IEDL */ + 0x15, 0x8A, /* dest port (ring tones) */ + 0x15, 0x8A /* src port (unused) */ +#define BIN1_PAYLOAD (140-7) + }; +unsigned char binn[140]={ + 11, /* UDH length */ + 0x05, /* IEI */ + 0x04, /* IEDL */ + 0x15, 0x8A, /* dest port (ring tones) */ + 0x15, 0x8A, /* src port (unused) */ + 0x00, 0x03, /* multipart */ + /* 0x??, unique serial ID */ + /* 0x??, total messages */ + /* 0x??, message number (# from 1) */ +#define BINN_PAYLOAD (140-12) + }; +unsigned char header[]={ + 0x30, /* version string '0' */ + 0x02, /* item=OTA bitmap */ +#define PICTURE_BYTES ((PICTURE_WIDTH*PICTURE_HEIGHT+7)/8) +#define PICTURE_BYTES_INCL_HEADER (PICTURE_BYTES +4/*header*/) + PICTURE_BYTES_INCL_HEADER>>8,PICTURE_BYTES_INCL_HEADER&0xFF, /* picture size in bytes incl. header */ + 0x00, /* animation pictures - 0=static picture */ + PICTURE_WIDTH,PICTURE_HEIGHT, /* picture size in pixels */ + 0x01, /* picture depth - B/W */ + }; +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(picturename,"rb"))) + error(_("^!Cannot open picture file \"%s\" for r/o"),picturename); + if ((size=getfilesize(f,picturename))==-1) + error(_("!File size determination is essential to continue operation")); + if (size!=PICTURE_BYTES) + error(_("!File \"%s\" size %ld doesn't match .res size for %dx%d picture"), + picturename,size,PICTURE_WIDTH,PICTURE_HEIGHT); + if (size<=BIN1_PAYLOAD-sizeof(header)) { + memcpy(bin1+7,header,sizeof(header)); + if ((got=fread(bin1+7+sizeof(header),1,size,f))!=size) + error(_("^Read error on \"%s\", wanted %ld, got %d"),picturename,size,got); + error(_("\nSending picture \"%s\" as single SMS (size %ld, max %d)"), + picturename,size,BIN1_PAYLOAD-sizeof(header)); + nokiaprep(bin1,7+sizeof(header)+size); + } + else { + memcpy(binn+12,header,sizeof(header)); + totn=(sizeof(header)+size+BINN_PAYLOAD-1)/BINN_PAYLOAD; + if (totn>0xFF) + error(_("!File size %ld too large even for multi-SMS picture upload (max=%d)"), + size,BINN_PAYLOAD*0xFF-sizeof(header)); + binn[10]=totn; + if (verbose>=1) + error(_("\nSending picture \"%s\" as %d multi-SMSes (size %ld, max %d, frag %d, header %d)"), + picturename,totn,size,BIN1_PAYLOAD,BINN_PAYLOAD,sizeof(header)); + 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++) { +size_t isheader=(fragn==1 ? sizeof(header) : 0); + + binn[11]=fragn; + want=MIN(size,BINN_PAYLOAD-isheader); + if ((got=fread(binn+12+isheader,1,want,f))!=want) + error(_("^Read error on \"%s\", wanted %d, got %d"),picturename,want,got); + nokiaprep(binn,12+isheader+want); + size-=want; + } + } + chkfclose(f,picturename); +#undef WORD +} + static inline void genpdu(void) { static unsigned char pdu[64+MAXNUMLEN/2+(MAXBODYLEN*7)/8]; @@ -1456,7 +1576,7 @@ char *finame; } } -static int datawait(char immed) +static int datawait(int timeout) { int i; #ifdef HAVE_POLL @@ -1467,14 +1587,14 @@ fd_set rfds,xfds; assert(devfd>=0); retry: - if (!immed && verbose>=2) + if (timeout && verbose>=2) error(_(".Waiting for device incoming data..")); #ifdef HAVE_POLL ufd.fd=devfd; ufd.events=POLLIN; ufd.revents=0; errno=0; - i=poll(&ufd,1,(immed?0:-1)); + i=poll(&ufd,1,timeout*1000); #else /* HAVE_POLL */ #ifdef HAVE_FD_SETSIZE if (devfd>=FD_SETSIZE) @@ -1486,7 +1606,7 @@ retry: errno=0; i=select(devfd+1,&rfds,NULL,&xfds,NULL); #endif /* HAVE_POLL */ - if (immed && i==0) return(0); + if (i==0) return(0); if (i==-1 && errno==EINTR) goto retry; /* silent retry, for example SIGCHLD could occur */ if (i!=1) @@ -1514,8 +1634,8 @@ retry: static char *check_format(const char *fmt,const char *string) { static char err[LINE_MAX],sub[50]; -char *subp,cf,cs; -const char *sf,*ss; +char cf,cs; +const char *sf,*ss,*subp; for (sf=fmt,ss=string;(cf=*sf) && (cs=*ss);sf++,ss++) { subp=NULL; @@ -1626,8 +1746,6 @@ int i; memset(&tm,0,sizeof(tm)); /* may be redundant */ for (i=0;i=2) @@ -1655,7 +1776,7 @@ int i; FILE *f; d2("receive_text: %s\n",bodyline); - signal(SIGCHLD,signal_chld); + signal(SIGCHLD,(RETSIGTYPE (*)(int))signal_chld); #if RECEIVE_TEST pid=0; #else @@ -1898,6 +2019,7 @@ static struct { { &readtime,&readtimen,"readtime" }, { &chartime,&chartimen,"chartime" }, { &cmdtime ,&cmdtimen ,"cmdtime" }, + { &waittime,&waittimen,"waittime" }, { &baud ,&baudn ,"baud" }, }; @@ -1965,10 +2087,11 @@ char *buf=malloc(l+50); switch (mode) { 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; + 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_PICTURE_SEND: cmdline_picture_send(); break; + case MODE_RECEIVE: cmdline_receive (); break; default: assert(0); } cmdline_done(); @@ -2036,6 +2159,9 @@ size_t l=strlen(device); case MODE_RING_SEND: ringread(); break; + case MODE_PICTURE_SEND: + pictureread(); + break; case MODE_RECEIVE: break; default: assert(0); } @@ -2082,34 +2208,38 @@ time_t start,end; if ((end-=start)>LOCKREPORT) logmsg(_("Device lock succeeded after %ld seconds"),(long)end); } + +retryopen: + if (verbose>=1) error(_(".Opening device \"%s\".."),device); if ((devfd=open(device,O_RDWR|O_NDELAY))<0) error(_("^!Cannot open device \"%s\" for r/w access"),device); - if (tcgetattr(devfd,&restios)) - error(_("^Unable to get termios settings")); - else { - restios.c_cflag=(restios.c_cflag&~(CBAUD|CBAUDEX))|B0|HUPCL; - restios_yes=1; - } - tios.c_iflag=IGNBRK|IGNPAR|(handshake_rtscts ? 0 : IXON|IXOFF); - tios.c_oflag=0; - tios.c_cflag=CS8|CREAD|CLOCAL|HUPCL|portbaud|(handshake_rtscts ? CRTSCTS : 0); - tios.c_lflag=IEXTEN|NOFLSH; - memset(tios.c_cc,_POSIX_VDISABLE,sizeof(tios.c_cc)); - tios.c_cc[VTIME]=0; - tios.c_cc[VMIN ]=1; - cfsetispeed(&tios,portbaud); - if (cfsetospeed(&tios,portbaud)|cfsetispeed(&tios,portbaud)) - error(_("^Error setting termios baudrate on device")); - if (tcflush(devfd,TCIOFLUSH)) - error(_("^Error flushing termios (TCIOFLUSH) on device")); - if (tcsetattr(devfd,TCSANOW,&tios)) - error(_("^!Unable to set initial termios device settings")); +retryall: - setalarm(); + if (tcgetattr(devfd,&restios)) + error(_("^Unable to get termios settings")); + else { + restios.c_cflag=(restios.c_cflag&~(CBAUD|CBAUDEX))|B0|HUPCL; + restios_yes=1; + } + tios.c_iflag=IGNBRK|IGNPAR|(handshake_rtscts ? 0 : IXON|IXOFF); + tios.c_oflag=0; + tios.c_cflag=CS8|CREAD|CLOCAL|HUPCL|portbaud|(handshake_rtscts ? CRTSCTS : 0); + tios.c_lflag=IEXTEN|NOFLSH; + memset(tios.c_cc,_POSIX_VDISABLE,sizeof(tios.c_cc)); + tios.c_cc[VTIME]=0; + tios.c_cc[VMIN ]=1; + cfsetispeed(&tios,portbaud); + if (cfsetospeed(&tios,portbaud)|cfsetispeed(&tios,portbaud)) + error(_("^Error setting termios baudrate on device")); + if (tcflush(devfd,TCIOFLUSH)) + error(_("^Error flushing termios (TCIOFLUSH) on device")); + if (tcsetattr(devfd,TCSANOW,&tios)) + error(_("^!Unable to set initial termios device settings")); + + setalarm(); -retryall: devcmd("",NULL,"\r\nAT\033\032"); /* ESCAPE, CTRL-Z */ devcmd(NULL,NULL,"\r\nAT"); smscset(); @@ -2155,7 +2285,8 @@ retryall: } break; case MODE_LOGO_SEND: - case MODE_RING_SEND: { + case MODE_RING_SEND: + case MODE_PICTURE_SEND: { struct hexdata *hd; restore="\r\nAT+CSMP=17,,0,0"; @@ -2168,47 +2299,55 @@ struct hexdata *hd; parts++; } } break; - case MODE_RECEIVE: + case MODE_RECEIVE: { +int gotdatawait; + restore="\r\nAT+CNMI=,0"; devcmd(NULL,NULL,"\r\nAT+CNMI=,2"); devcmd(NULL,NULL,"\r\nAT+CSDH=0"); - for (;;) { continue_receive: - unlockdevice(0); - /* Never bail-out when we got up to this point */ - if (maxretryn!=-1 && verbose>=1) - error(_(".Initialization successful, infinite retry count set")); - maxretryn=-1; + unlockdevice(0); + /* Never bail-out when we got up to this point */ + if (maxretryn!=-1 && verbose>=1) + error(_(".Initialization successful, infinite retry count set")); + maxretryn=-1; #if RECEIVE_TEST - receive_headerparse(" \"+420602123456\",,\"99/10/25,03:21:03-00\""); - receive_accept("TESTBODY"); - exit(EXIT_SUCCESS); + receive_headerparse(" \"+420602123456\",,\"99/10/25,03:21:03-00\""); + receive_accept("TESTBODY"); + exit(EXIT_SUCCESS); #endif - datawait(0); - if (!lockdevice(1)) { - if (verbose>=1) - error(_(".Dialout detected, waiting for lock..")); - lockdevice(0); + gotdatawait=datawait(waittimen); + if (!lockdevice(1)) { + if (verbose>=1) + error(_(".Dialout detected, waiting for lock..")); + if (verbose>=1) error(_(".Closing device \"%s\".."),device); + if (close(devfd)) + error(_("Error closing device \"%s\""),device); + lockdevice(0); + goto retryopen; + } + d1("Lock-device succeeded\n"); + do { + if (!(s=devcmd("\n","+CMT:"," "))) goto retryall; - } - d1("Lock-device succeeded\n"); - do { - d1("Reading a message for us...\n"); - if (!(s=devcmd("\n","+CMT:"," "))) - goto retryall; - if (s==&devcmd_empty_return) /* only newlines found */ - goto continue_receive; - if (cmgf && !(i=receive_headerparse(s))) - error(_("Receive-header parsing failed on: %s"),s); - if (!(s=devcmd("\n","@"," "))) + if (s==&devcmd_empty_return) { /* only newlines found */ + if (gotdatawait==0) /* timeout, rather reinitialize the modem */ goto retryall; - if (cmgf) { - if (i) receive_text(s); - } - else receive_pdu(s); - } while (datawait(1)); - } /* return to 'continue receive' point */ - break; + goto continue_receive; + } + d1("Reading a message for us...\n"); + if (cmgf && !(i=receive_headerparse(s))) + error(_("Receive-header parsing failed on: %s"),s); + if (!(s=devcmd("\n","@"," "))) + goto retryall; + if (cmgf) { + if (i) receive_text(s); + } + else receive_pdu(s); + } while (datawait(0)); + goto retryall; + } + default: assert(0); } if (!s) { retrying(); goto retryall; }