#pragma module MX_SITE2SMS "MX_SITE2SMS-1-X" #define __MODULE__ "MX_SITE2SMS" /* **++ ** FACILITY: SMTP to SMS Gateway ** ** MODULE DESCRIPTION: ** This module implements a functionality of SMTP to SMS gateway by using ** MX 5.x SITE Delivery interface and SMPP/EMSE API. ** ** ** AUTHORS: ** ** Ruslan R. Laishev ** ** CREATION DATE: 16-OCT-2002 ** ** BUILD: ** $ CC /NOWARNING/INCLUDE=[] MX_SITE2SMS.C ** $ LINK MX_SITE2SMS,SYS$INPUT/OPT ** ESME_API_SHR/SHARE ** ^Z ** ** INSTALLATION: ** $ COPY MX_SITE2SMS.EXE MX_EXE ** ** DESIGN ISSUES: ** ** It's a MX SITE delivery agent. ** ** ** MODIFICATION HISTORY: ** ** 18-OCT-2002 RRL Added Russian character conversion. ** 22-OCT-2002 RRL Set KOI8-R as default character set. ** 21-NOV-2002 RRL Added character set converion with iconv(), ** now we sends SMS in the ISO-10646-UCS-2. ** 23-DEC-2002 RRL Commented out any UNICODE stuff. ** ** {@tbs@}... **-- */ /* ** ** INCLUDE FILES ** */ #include #include #include #include #include #include #include #include #include #include #include #include #define __NEW_STARLET 1 #include #undef __NEW_STARLET #include "macros.h" /* ** ** SMPP AND ESME API INCLUDE FILES ** */ #include "smppdef.h" #include "esme_msg.h" const int zero = 0; char stype[32],ton,npi; short stypelen; /* ** RUSSIAN CHARACTER SET TABLES */ $DESCRIPTOR(isocyr, "°±²³´µ®¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕ÷ÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîï"); $DESCRIPTOR(wincyr, "ÀÁÂÃÄŨÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãä叿çèéêëìíîïðñòóôõö÷øùúûüýþÿ"); $DESCRIPTOR(koicyr, "áâ÷çäå³öúéêëìíîïðòóôõæèãþûýøùÿüàñÁÂ×ÇÄÅ£ÖÚÉÊËÌÍÎÏÐÒÓÔÕÆÈÃÞÛÝØÙßÜÀÑ"); struct dsc$descriptor *tblcyr[] = { NULL, &isocyr, &wincyr, &koicyr}; enum cyrdc {ISODC = 1,WINDC = 2,KOIDC = 3}; int convdc ( int srcdc, char *src, short srclen ) { struct dsc$descriptor src_dsc,dest_dsc; INIT_SDESC(src_dsc,srclen,src); return str$translate(&src_dsc,&src_dsc,tblcyr[ISODC],tblcyr[srcdc]); } int esmeio_shut ( void *ectx ) { int status,resp,sts,context; /* ** Send a UNBIND request to close session with the SMSC */ if ( !(1 & (status = esme_api_tx(ectx,SMPP_CMD$K_UNBIND,NULL,NULL,NULL))) ) lib$signal(status); /* ** Shutdown ESME API */ return esme_api_shut(&ectx); } int esmeio_init ( void **ectx, char *connsts ) { int status,resp, sts,seq; char buf[256],name[256],sid[32],pwd[32],ston[4],snpi[4]; struct dsc$descriptor buf_dsc,name_dsc; /* ** Got a connection string, we expect to see: ** "SMSC.DeltaTel.RU:9000/symb/VAX/zztop/1/1" */ if ( 6 != sscanf(connsts,"%[^/]/%[^/]/%[^/]/%[^/]/%[^/]/%[^\n]",&name,&sid,&pwd,&stype,&ston,&snpi) ) return SS$_INSFARG; /* ** Initalize ESME API */ INIT_SDESC(name_dsc,strnlen(name,sizeof(name)),name); if ( !(1 & (status = esme_api_init(ectx,&name_dsc))) ) return status; stypelen = (char) strnlen(stype,sizeof(stype)); ton = (char)atoi(ston); npi = (char)atoi(snpi); /* ** Send a BIND request to open a session with the SMSC */ { /* ** Items list for BIND_TRANSMITTER request */ ILE3 bind_items [] = { {strlen(sid), SMPP_PTAG$K_SID, &sid}, {strlen(pwd), SMPP_PTAG$K_PWD, &pwd}, {stypelen, SMPP_PTAG$K_STYPE, &stype}, {1, SMPP_PTAG$K_TON, &ton}, {1, SMPP_PTAG$K_NPI, &npi}, {0,0,0}}; if ( !(1 & (status = esme_api_tx(*ectx,SMPP_CMD$K_BIND_TRANSMITTER,bind_items,NULL,NULL))) ) return status; } /* ** Receive a RESPONSE to the sent BIND request */ status = esme_api_rx(*ectx,NULL,&resp,&sts,NULL,NULL,&seq); /* ** Return a translated to VMS condition code SMPP/ESME error status */ return (status & 1)?esme_api_err2cond(sts):status; } int esmeio_sendsms ( void *ectx, char *src, short srclen, char *dest, short destlen, char *sms, short smslen, char *mid, short *midlen ) { int status,resp,sts,seq; char dc = DC$K_ISOCYR; struct dsc$descriptor buf_dsc,name_dsc; ILE3 submit_items [] = { {stypelen, SMPP_PTAG$K_STYPE, &stype}, {1, SMPP_PTAG$K_SRCTON, &ton}, {1, SMPP_PTAG$K_SRCNPI, &npi}, {srclen, SMPP_PTAG$K_SRC, src}, {1, SMPP_PTAG$K_DESTTON, &ton}, {1, SMPP_PTAG$K_DESTNPI, &npi}, {destlen, SMPP_PTAG$K_DEST, dest}, {1, SMPP_PTAG$K_DC, &dc}, {1, SMPP_PTAG$K_SMSLEN, &zero}, // {smslen, SMPP_PTAG$K_SMSBODY, sms}, {smslen, SMPP_PTAG$K_MSGPAYLD, sms}, {0,0,0}}, submit_items_resp [] = { {65, SMPP_PTAG$K_MSGID, mid,midlen}, {0,0,0,0}}; /* ** Send a SMS by SUBMIT_SM request */ if ( !(1 & (status = esme_api_tx(ectx,SMPP_CMD$K_SUBMIT_SM,submit_items,NULL,NULL))) ) return status; /* ** Receive a RESPONSE to the sent SUBMIT_SM request */ status = esme_api_rx(ectx,submit_items_resp,&resp,&sts,NULL,NULL,&seq); /* ** Return a translated to VMS condition code SMPP/ESME error status */ return (status & 1)?esme_api_err2cond(sts):status; } int main ( int argc, char ** argv ) { int status,buflen = 0,sdc = 0; // KOIDC; void *ectx = NULL; char *src = argv[2],*dest = argv[3],*smsf = argv[1], *connsts = argv[4], buf [ 8192 ],sms [ SMPP$K_SMSLEN ], mid[66]; short srclen,destlen,smslen = 0,lfcount = 0,midlen = 0; struct RAB rab = cc$rms_rab; struct FAB fab = cc$rms_fab; if ( argc != 5 ) return SS$_INSFARG; /* ** Open a message file */ fab.fab$l_fna = smsf; fab.fab$b_fns = strlen(smsf); fab.fab$v_sqo = 1; if ( !(1 & (status = sys$open(&fab))) ) return status; rab.rab$l_fab = &fab; if ( !(1 & (status = sys$connect(&rab))) ) return status; rab.rab$b_rac = RAB$C_SEQ; rab.rab$v_nlk = 1; rab.rab$l_ubf = &buf; rab.rab$w_usz = sizeof(buf); /* ** Form a first two string of the SMS: ** Fr: ** Sj: ** ** Read a header portion of the mail */ for ( smslen = 0;(1 & (status = sys$get(&rab)) && rab.rab$w_rsz );) { /* ** We looking for a "From:","Subject:" and character set fields */ if ( (rab.rab$w_rsz > 6) && (!memcmp(buf, "From: ",6)) ) { if ( smslen % 16 ) { sms[smslen++] = '\n'; lfcount++; } memcpy(sms+smslen,"Fr:",3); smslen += 3; memcpy(sms+smslen,buf+6,$min(13,rab.rab$w_rsz-6)); smslen += $min(13,rab.rab$w_rsz-6); } if ( (rab.rab$w_rsz > 9) && (!memcmp(buf, "Subject: ",9)) ) { if ( smslen % 16 ) { sms[smslen++] = '\n'; lfcount++; } memcpy(sms+smslen,"Sj:",3); smslen += 3; memcpy(sms+smslen,buf+9,$min(13,(rab.rab$w_rsz-9))); smslen += $min(13,rab.rab$w_rsz-9); } if ( !memcmp(buf, "Content-Type: text/plain; charset=",34) ) { if ( !strncasecmp(buf+34,"ISO-8859-5",10) ) sdc = ISODC; else if ( !strncasecmp(buf+34,"KOI8-R",6) ) sdc = KOIDC; else if ( !strncasecmp(buf+34,"windows-1251",12) ) sdc = WINDC; } } if ( !(1 & status) && (status != RMS$_EOF) ) return status; else if ( !(1 & status) ) return SS$_NORMAL; /* ** If a from Field is missing just stop a processing and ** returning a OK status to drop this mail. */ if ( !smslen ) return SS$_NORMAL; /* ** Now we have skiped mail header and can processing body */ while ( 1 & (status = sys$get(&rab)) ) { /* ** Skip empty lines... */ if ( !rab.rab$w_rsz ) continue; /* ** Check free cpace in the buffer */ if ( (smslen + 1) >= sizeof(sms) ) break; if ( (smslen - lfcount) % 16 ) { sms[smslen++] = '\n'; lfcount++; } /* ** Add a gotten record to the sms buffer */ memcpy(&sms[smslen],buf,$min(rab.rab$w_rsz,sizeof(sms)-smslen)); smslen += $min(rab.rab$w_rsz,sizeof(sms)-smslen); if ( smslen >= sizeof(sms) ) break; } /* ** Close input message file */ status = sys$close(&fab); /* ** Calling a character set conversion routine */ if ( sdc ) if ( !(1 & (status = convdc (sdc,sms,smslen))) ) return status; /* ** Sending formed SMS */ if ( !(1 & (status = esmeio_init(&ectx,connsts))) ) return status; srclen = strnlen(src,32); destlen = strnlen(dest,32); status = esmeio_sendsms(ectx,src,srclen,dest,destlen,sms,smslen,mid,&midlen); printf("SMS (%u bytes) from '%*s' to '%*s' / id = '%*s',status = %x\n", smslen,srclen,src,destlen,dest,midlen,mid,status); esmeio_shut(ectx); return status; }