Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

smsc_sema.c

Go to the documentation of this file.
00001 /* ==================================================================== 
00002  * The Kannel Software License, Version 1.0 
00003  * 
00004  * Copyright (c) 2001-2008 Kannel Group  
00005  * Copyright (c) 1998-2001 WapIT Ltd.   
00006  * All rights reserved. 
00007  * 
00008  * Redistribution and use in source and binary forms, with or without 
00009  * modification, are permitted provided that the following conditions 
00010  * are met: 
00011  * 
00012  * 1. Redistributions of source code must retain the above copyright 
00013  *    notice, this list of conditions and the following disclaimer. 
00014  * 
00015  * 2. Redistributions in binary form must reproduce the above copyright 
00016  *    notice, this list of conditions and the following disclaimer in 
00017  *    the documentation and/or other materials provided with the 
00018  *    distribution. 
00019  * 
00020  * 3. The end-user documentation included with the redistribution, 
00021  *    if any, must include the following acknowledgment: 
00022  *       "This product includes software developed by the 
00023  *        Kannel Group (http://www.kannel.org/)." 
00024  *    Alternately, this acknowledgment may appear in the software itself, 
00025  *    if and wherever such third-party acknowledgments normally appear. 
00026  * 
00027  * 4. The names "Kannel" and "Kannel Group" must not be used to 
00028  *    endorse or promote products derived from this software without 
00029  *    prior written permission. For written permission, please  
00030  *    contact org@kannel.org. 
00031  * 
00032  * 5. Products derived from this software may not be called "Kannel", 
00033  *    nor may "Kannel" appear in their name, without prior written 
00034  *    permission of the Kannel Group. 
00035  * 
00036  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 
00037  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
00038  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
00039  * DISCLAIMED.  IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS 
00040  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,  
00041  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  
00042  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR  
00043  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
00044  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE  
00045  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  
00046  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
00047  * ==================================================================== 
00048  * 
00049  * This software consists of voluntary contributions made by many 
00050  * individuals on behalf of the Kannel Group.  For more information on  
00051  * the Kannel Group, please see <http://www.kannel.org/>. 
00052  * 
00053  * Portions of this software are based upon software originally written at  
00054  * WapIT Ltd., Helsinki, Finland for the Kannel project.  
00055  */ 
00056 
00057 
00058  /*
00059  * smsc_sema.c - implement sms2000 protocal by using X25 access
00060  * the data communication layer is implemented by using X28 protocol
00061  * 
00062  * Code implement submit invoke, status invoke, deliver invoke session
00063  * there is no internal db for storing delivered and undelivered message
00064  * 
00065  * IA5 is most common line coding scheme. 
00066  * smsc_sema support only IA5 encoding, hex and binary line encoding is not
00067  * supported.
00068  * 
00069  * smsc_sema support IA5 and GSM Data Code Scheme for delivered invoke message
00070  * smsc_sema support only IA5 Data Code Scheme for submit invoke message
00071  *  
00072  * Reference : SMS2000 Version 4.0 Open Interface Specification
00073  *             Open Source WAP Gateway Architecture Design 
00074  *             ESTI GSM 03.40
00075  *
00076  * Hao Shi 2000
00077  */
00078 
00079 #include <errno.h>
00080 #include <stdarg.h>
00081 #include <stdio.h>
00082 #include <stdlib.h>
00083 #include <string.h>
00084 #include <unistd.h>
00085 #include <fcntl.h>
00086 #include <termios.h>
00087 
00088 #include <sys/time.h>
00089 #include <sys/types.h>
00090 #include <sys/socket.h>
00091 #include <sys/param.h>
00092 
00093 
00094 #include <netinet/in.h>
00095 #include <netdb.h>
00096 
00097 #include "gwlib/gwlib.h"
00098 #include "smsc.h"
00099 #include "smsc_p.h"
00100 #include "alt_charsets.h"
00101 #include "smsc_sema.h"
00102 #include "sms.h"
00103 
00104 #ifndef CRTSCTS
00105 #define CRTSCTS 0
00106 #endif
00107 
00108 
00109 static unsigned char sema_counter[4] = "0000";
00110 static int sema_wait_report = 1;
00111 static int x28_data_mode = X28_COMMAND_MODE;
00112 
00113 SMSCenter * sema_open(char* smscnua, char* homenua, 
00114               char* serialdevice, int waitreport)
00115 {
00116     SMSCenter *smsc;
00117     int nret = -1;
00118 
00119     smsc = smscenter_construct();
00120     if(smsc == NULL)
00121       goto error;
00122 
00123     sprintf(smsc->name, "SEMA:X28:"); 
00124 
00125     smsc->type = SMSC_TYPE_SEMA_X28;
00126     smsc->sema_smscnua = gw_strdup(smscnua);
00127     smsc->sema_homenua = gw_strdup(homenua);
00128     smsc->sema_serialdevice = gw_strdup(serialdevice);
00129     sema_wait_report = waitreport;
00130 
00131     smsc->sema_mt = sema_msglist_new();
00132     if(smsc->sema_mt == NULL) goto error;
00133     
00134     smsc->sema_mo = sema_msglist_new();
00135     if(smsc->sema_mo == NULL) goto error;
00136 
00137     /* Open the device properly. Remember to set the
00138        access codes correctly. */
00139     debug("smsc.sema", 0, "sema_open: open datalink");
00140     smsc->sema_fd = X28_open_data_link(smsc->sema_serialdevice);
00141     if(smsc->sema_fd == -1) goto error;
00142 
00143     /*  test the outgoing callX28 to smsc center */
00144         debug("smsc.sema", 0, "sema_open: test send link");
00145     nret = X28_open_send_link(smsc->sema_fd, smsc->sema_smscnua);
00146     if(nret < 1){
00147       sleep(2);
00148       nret = X28_open_send_link(smsc->sema_fd, smsc->sema_smscnua);  
00149       if(nret < 1)
00150         goto error;
00151     }
00152     X28_close_send_link(smsc->sema_fd);
00153     return smsc;
00154 
00155 error:
00156     error(0, "sema_open: could not open");
00157     smscenter_destruct(smsc);
00158     return NULL;
00159 }
00160 
00161 
00162 int sema_reopen(SMSCenter *smsc)
00163 {
00164     int nret = 0;
00165 
00166     debug("smsc.sema", 0, "reopening the connection");
00167 
00168     /*deallocate*/
00169     sema_msglist_free(smsc->sema_mt);
00170     sema_msglist_free(smsc->sema_mo);
00171     /*reallocate*/
00172     smsc->sema_mt = sema_msglist_new();
00173     if(smsc->sema_mt == NULL) goto error;
00174     smsc->sema_mo = sema_msglist_new();
00175     if(smsc->sema_mo == NULL) goto error;
00176     memset(smsc->buffer,0,sizeof(smsc->buffer));
00177 
00178     /* Open the device properly. Remember to set the
00179      access codes correctly. */
00180     smsc->sema_fd = X28_reopen_data_link(smsc->sema_fd, smsc->sema_serialdevice);
00181     if(smsc->sema_fd == -1){
00182     error(0,"sema_reopen_data_link: device file error");
00183     goto error;
00184     }
00185     /*test outgoing call to the smsc */
00186     nret = X28_open_send_link(smsc->sema_fd, smsc->sema_smscnua);
00187     if(nret < 1){
00188     error(0,"test send data link failed");
00189     goto error;
00190     }
00191     X28_close_send_link(smsc->sema_fd);
00192     return 0;
00193 error:
00194     error(0, "sema_reopen_data_link: failed");
00195     return -1;
00196   
00197 }
00198 
00199 int sema_close(SMSCenter *smsc)
00200 {
00201     if(smsc->sema_fd > 0)
00202     close(smsc->sema_fd);
00203     /*deallocate*/
00204     sema_msglist_free(smsc->sema_mt);
00205     sema_msglist_free(smsc->sema_mo);
00206     return 0;
00207 }
00208 
00209 
00210 int sema_submit_msg(SMSCenter *smsc, Msg *msg)
00211 {
00212         int nret = 0;
00213         struct sema_msg *lmsg = NULL;
00214     struct sm_submit_invoke *submit_sm = NULL;
00215     char x28sender[2] = "A3";
00216         
00217     /* Validate msg */
00218     if(smsc == NULL){
00219         error(0,"sema_submit_msg: SMSC is empty");
00220         goto error;
00221     }
00222     if(msg == NULL){
00223         error(0, "sema_submit_msg: Msg is empty");
00224         goto error;
00225     }
00226 
00227     if(msg_type(msg) != sms) {
00228         error(0, "sema_submit_sms: Msg is WRONG TYPE");
00229         goto error;
00230     }
00231     /*  user data header is not supported in sm2000 X25 access
00232         if(msg->sms.coding == DC_7BIT ...|| DC_UNDEF?){
00233         error(0, "sema_submit_sms: submit invoke support in IA5 encoding(8 bits chars)");
00234         goto error;
00235         }
00236 
00237         if(octstr_len(msg->sms.udhdata)){
00238         error(0, "sema_submit_sms: submit invoke not support in IA5 encoding ");
00239         goto error;
00240         }
00241     */
00242     lmsg = sema_msg_new();
00243     
00244     submit_sm = gw_malloc(sizeof(struct sm_submit_invoke));
00245     memset(submit_sm, 0, sizeof(struct sm_submit_invoke));
00246 
00247     lmsg->type = 'S';
00248     lmsg->encodetype = LINE_ENCODE_IA5;
00249 
00250     /* set operation reference */
00251     increment_counter();
00252     memcpy(lmsg->optref,sema_counter,4);
00253     /*set sme reference number*/
00254     increment_counter();
00255     memcpy(submit_sm->smerefnum, sema_counter, 4);
00256     /*we send as not key type*/
00257     submit_sm->smereftype= 2; /*key type is 1*/
00258     /*we set prority as normal*/
00259     submit_sm->priority = 1; /*0 is high*/ 
00260     /*set valid period type as relative*/
00261     submit_sm->validperiodtype = 2; /* 1 is absolute */
00262     /*time*/
00263     submit_sm->validperiodrela = 1; /* from 0 to 143 , fomula is (V+1)*5 min*/
00264     /*send msg without 00 header*/
00265     submit_sm->msisdnlen= octstr_len(msg->sms.receiver);
00266     submit_sm->msisdn = octstr_copy(msg->sms.receiver,0,submit_sm->msisdnlen);
00267     /* X25 access will always append sender during data transfer */
00268     submit_sm->origaddlen= 2; /* we need only to orignate address type */
00269     submit_sm->origadd = octstr_create_from_data(x28sender,2);
00270     /*data encoding scheme ,support only IA5 in current version*/
00271     submit_sm->DCS = 15; /*gsm is 0 ,IA5 is 15*/    
00272     /*protocal ,support only default value  0 in current version*/ 
00273     submit_sm->protocal = 0;
00274     /*replypath*/
00275     submit_sm->replypath= 0; /*gateway do not pay for reply*/
00276     /*status report*/
00277     if(sema_wait_report > 0)
00278         submit_sm->statusreportrequest =4; /* deliver success, in bin form 00000100*/
00279     else
00280         submit_sm->statusreportrequest = 0;/* no report */
00281     /* we support submit invoke only in IA5 line encoding*/
00282     submit_sm->textsizeoctect = submit_sm->textsizeseptet =
00283         octstr_len(msg->sms.msgdata);
00284     /*copy msg buffer*/
00285     submit_sm->shortmsg = octstr_copy(msg->sms.msgdata,
00286                       0, submit_sm->textsizeoctect);
00287     
00288     memset(submit_sm->smscrefnum,0,sizeof(submit_sm->smscrefnum));  
00289         /*pack the message body in 2kmsg*/
00290     lmsg->msgbody = submit_sm;
00291     nret = sema_msg_session_mt(smsc, lmsg);
00292 
00293     gw_free(submit_sm);
00294     submit_sm = NULL;
00295     sema_msg_free(lmsg);
00296     lmsg = NULL;
00297     
00298 
00299     if(nret == SESSION_MT_RECEIVE_SUCCESS){
00300         debug("smsc.sema", 0, "sema_submit_msg: message is successfully delivered");
00301         return 1; /*success*/
00302     }
00303     else if(nret == SESSION_MT_RECEIVE_TIMEOUT){
00304         info(0, "sema_submit msg: session timed out without return");
00305         return 0;
00306     }
00307     else if(nret == SESSION_MT_RECEIVE_ERR){
00308         info(0, "sema_submit msg: smsc says submit failed!");
00309         return 0;
00310     }
00311 
00312     return 1;
00313     
00314 error:
00315     if(submit_sm)
00316         gw_free(submit_sm);
00317     if(lmsg)
00318         sema_msg_free(lmsg);
00319     return -1;
00320 }
00321 
00322 
00323 int sema_receive_msg(SMSCenter *smsc, Msg **msg)
00324 {
00325 
00326     struct sema_msg *rmsg = NULL;
00327     struct sm_deliver_invoke *recieve_sm = NULL;
00328  
00329     while(sema_msglist_pop(smsc->sema_mo, &rmsg) == 1 ) {
00330   
00331     *msg = msg_create(sms);
00332     if(*msg==NULL) goto error;
00333     
00334     recieve_sm = (struct sm_deliver_invoke*) rmsg->msgbody;
00335     if(recieve_sm==NULL) goto error;
00336           
00337     /* as IA5(8 bit character) is the default line encoding used by X28
00338      * and we do not support other line encoding scheme like binary or
00339      * hex encoding
00340      */
00341     (*msg)->sms.coding = DC_8BIT;
00342     /* OIS in X28 implementation does not include udh field */
00343 
00344     (*msg)->sms.sender = octstr_create_from_data(
00345         octstr_get_cstr(recieve_sm->origadd) +2,
00346         octstr_len(recieve_sm->origadd)-2);  
00347     (*msg)->sms.receiver = octstr_create_from_data(
00348         octstr_get_cstr(recieve_sm->destadd) +2,
00349         octstr_len(recieve_sm->destadd)-2);
00350   
00351     (*msg)->sms.msgdata = octstr_duplicate(recieve_sm->shortmsg);
00352     (*msg)->sms.udhdata = octstr_create("");
00353     gw_free(recieve_sm);
00354     sema_msg_free(rmsg);
00355     rmsg = NULL;
00356     }
00357     return 1;
00358 
00359 error:
00360     error(0, "sema_receive_msg: can not create Smart Msg");
00361     return -1;
00362 }
00363 
00364 
00365 int sema_pending_smsmessage(SMSCenter *smsc)
00366 {
00367 
00368     char data[1024];
00369     int ret = 0;
00370     char clrbuff[]="CLR\0";
00371     char errbuff[]="ERR\0";
00372     /* struct sema_msg* smsg = NULL;*/
00373 
00374   /* Receive raw data */
00375     ret = X28_data_read(smsc->sema_fd, smsc->buffer);
00376     if(ret == -1) {
00377     ret = X28_reopen_data_link(smsc->sema_fd, smsc->sema_serialdevice);
00378     if(ret == -1) goto error;
00379     return 0;
00380     } 
00381 
00382     /* Interpret the raw data */
00383     memset(data,0,sizeof(data));
00384     while(X28_msg_pop(smsc->buffer, data) == 0 ) {
00385     if(strlen(data) > 0){
00386         if(strstr(data,clrbuff) != NULL ||
00387            strstr(data,errbuff) != NULL){
00388         debug("smsc.sema", 0, "sema_pending_msg: Radio Pad Command line-%s",data);
00389         }
00390         else{   
00391           
00392         ret = sema_msg_session_mo(smsc, data);
00393         if(ret == -1) goto error;
00394         }
00395         memset(data,0,sizeof(data));
00396     }
00397     }
00398 
00399     /* Signal that we got a MO message if mo list is not empty*/
00400     if(smsc->sema_mo->first != NULL){
00401     return 1;
00402     }
00403 
00404 
00405     return 0;
00406 
00407 error:
00408     error(0,"sema_pending message: device file error");
00409     return -1;
00410 }
00411 
00412 
00413 
00414 static sema_msg* sema_msg_new(void)
00415 {
00416     struct sema_msg *msg = NULL;
00417     msg = gw_malloc(sizeof(struct sema_msg));
00418     memset(msg, 0, sizeof(struct sema_msg));
00419     return msg;
00420 }
00421 
00422 static int sema_msg_free(sema_msg *msg) {
00423     if(msg == NULL) return 0;
00424     gw_free(msg);
00425     return 1;
00426 }
00427 
00428 static sema_msglist* sema_msglist_new(void) {
00429 
00430     struct sema_msglist *mlist = NULL;
00431     mlist = gw_malloc(sizeof(struct sema_msglist));
00432     memset(mlist, 0, sizeof(struct sema_msglist));
00433   
00434     mlist->first = NULL;
00435     mlist->last = NULL;
00436     mlist->count = 0;
00437     return mlist;
00438 }
00439 
00440 static void sema_msglist_free(sema_msglist *mlist) {
00441 
00442     struct sema_msg *pmsg = NULL;
00443     if(mlist == NULL) return; 
00444     while( sema_msglist_pop(mlist, &pmsg) == 1 )  {
00445     if(pmsg==NULL) break;
00446     sema_msg_free(pmsg);
00447     pmsg = NULL;
00448     }
00449     gw_free(mlist);
00450     mlist->count = 0;
00451 }
00452 
00453 static int sema_msglist_push(sema_msglist *plist, sema_msg *pmsg) {
00454 
00455     struct sema_msg * lmsg = NULL;
00456     if(plist == NULL) {
00457     info(0, "msglist_push: NULL msg list");
00458     goto error;
00459     }
00460     if(pmsg == NULL) {
00461     info(0, "msglist_push: NULL input");
00462     goto error;
00463     }
00464     /* If list is completely empty. */
00465     if( plist->first == NULL ) {
00466     plist->last = pmsg;
00467     plist->first = pmsg;
00468     pmsg->prev = NULL;
00469     pmsg->next = NULL;
00470     }
00471     else{
00472     lmsg=plist->last;
00473     lmsg->next=pmsg;
00474     pmsg->prev=lmsg;
00475     pmsg->next=NULL;
00476     plist->last=pmsg;
00477     }
00478     plist->count += 1;
00479     return 1;
00480 
00481 error:
00482     error(0, "msglist_push: error");
00483     return 0;
00484 
00485 }
00486 
00487 static int sema_msglist_pop(sema_msglist *plist, sema_msg **msg) {
00488 
00489    if(plist == NULL) {
00490     info(0, "msglist_pop: NULL list");
00491     goto no_msg;
00492     }
00493     if(plist->first == NULL) {
00494     goto no_msg;
00495     }
00496 
00497     *msg = plist->first;
00498     if(plist->last == *msg) {
00499     plist->first = NULL;
00500     (*msg)->prev = NULL;
00501     plist->last = NULL;
00502     } 
00503     else {
00504     plist->first = (*msg)->next;
00505     plist->first->prev = NULL; 
00506     if(plist->first->next == NULL) 
00507         plist->last = plist->first;
00508     }
00509     plist->count -= 1;
00510     return 1;
00511 
00512 no_msg:
00513     return 0;
00514 }
00515 
00516 
00517 
00518 static int X28_open_data_link(char* device){
00519     int fd = -1, iret;
00520     struct termios tios;
00521     info(0,"open serial device %s",device);
00522     fd = open(device, O_RDWR|O_NONBLOCK|O_NOCTTY);
00523     if(fd==-1) {
00524     error(errno, "sema_open_data_link: error open(2)ing the character device <%s>",
00525           device);
00526     if(errno == EACCES)
00527         error(0, "sema_open_data_link: user has no right to access the serial device");
00528     return -1;
00529     }
00530 
00531     tcgetattr(fd, &tios);
00532     cfsetospeed(&tios, B4800);  /* check radio pad parameter*/
00533     cfsetispeed(&tios, B4800);
00534     kannel_cfmakeraw(&tios);
00535     tios.c_iflag |= IGNBRK|IGNPAR|INPCK|ISTRIP;
00536     tios.c_cflag |= (CSIZE|HUPCL | CREAD | CRTSCTS);
00537     tios.c_cflag ^= PARODD;
00538     tios.c_cflag |=CS7;
00539     iret = tcsetattr(fd, TCSANOW, &tios);
00540     if(iret == -1){
00541     error(errno,"sema_open_data_link: fail to set termios attribute");
00542     goto error;
00543     }
00544     tcflush(fd, TCIOFLUSH);
00545     return fd;
00546   
00547 error:
00548     return -1;
00549 }
00550 
00551 static int X28_reopen_data_link(int oldpadfd ,char* device){
00552     int nret = 0;
00553     if(oldpadfd > 0){
00554     nret= close(oldpadfd);
00555     if(nret == -1){
00556         error(errno,"sema_reopen_data_link: close device file failed!!");
00557     }
00558     }
00559     sleep(1);
00560     return X28_open_data_link(device);
00561 }
00562 
00563     
00564 static int X28_close_send_link(int padfd)
00565 {
00566     char discnntbuff[5];
00567     char readbuff[1024];
00568     char finishconfirm[]="CLR CONF\0";
00569     int nret = 0, readall = 0;
00570     time_t tstart;
00571     time(&tstart);
00572 
00573     sprintf(discnntbuff,"%cCLR\r",0x10);
00574     memset(readbuff,0,sizeof(readbuff));
00575 
00576     /* what ever is the close return, data mode is unreliable now*/
00577     x28_data_mode = X28_COMMAND_MODE;
00578 
00579     if(padfd <= 0)
00580     goto datalink_error;
00581     while((time(NULL) - tstart) < INTERNAL_DISCONNECT_TIMEVAL){
00582     nret =write(padfd, discnntbuff, 5);
00583     if(nret == -1){
00584         if(errno == EAGAIN || errno ==EINTR) continue;
00585         else{
00586         goto datalink_error;
00587         }
00588     }   
00589     sleep(1); /*wait 1 senconds for virtual link break*/    
00590     nret=read(padfd, readbuff+readall,128);
00591     if(nret == -1){
00592         if(errno == EAGAIN || errno ==EINTR) continue;
00593         else{
00594         goto datalink_error;
00595         }
00596     }
00597     if(nret >0){
00598         readall += nret;
00599         if(strstr(readbuff,finishconfirm))
00600         return 1;
00601     }
00602     }
00603     return 0;
00604 datalink_error:
00605     error(errno,"sema_close_send_link, device file error");
00606     return -1;
00607 }
00608 
00609 
00610 
00611 static int X28_open_send_link(int padfd, char *nua) {
00612 
00613     char readbuff[1024]; 
00614     char writebuff[129];
00615     char smscbuff[129];
00616     int readall = 0, readonce = 0, writeonce = 0, writeall = 0, i = 0;
00617     char X28prompt[]="*\r\n\0";
00618     time_t timestart;
00619   
00620     debug("smsc.sema", 0, "sema_open send link: call smsc  <%s> for <%i> seconds",
00621       nua, (int)INTERNAL_CONNECT_TIMEVAL);
00622     
00623     /*  type few <cr> to invoke DTE */
00624     writebuff[0] = '\r';       
00625     memset(readbuff,0,sizeof(readbuff));     
00626     for(i = 0; i <= 3; i++)
00627     {
00628     readonce = writeonce = -1;
00629     writeonce = write(padfd, writebuff, 1);
00630     if(writeonce < 1){
00631         if(errno == EINTR || errno == EAGAIN) continue;
00632         else{
00633         goto datalink_error;
00634         }
00635     }
00636     usleep(1000); /* wait for prompt */
00637     readonce = read(padfd, &readbuff[readall],1024);
00638     if(readonce == -1){
00639         if(errno == EINTR || errno == EAGAIN) continue;
00640         else{
00641         goto datalink_error;
00642         }
00643     }
00644     else
00645         readall += readonce;
00646     }
00647     if(strstr(readbuff, X28prompt) == NULL){
00648     warning(0,"X28_open_send_link: can not read command prompt, abort");
00649     return 0;
00650     }
00651     
00652 
00653     /* second, connect to the smsc now */
00654     memset(writebuff,0,sizeof(writebuff));
00655     memset(readbuff,0,sizeof(readbuff));  
00656     writeall = readall = 0;
00657     sprintf(writebuff, "%s\r", nua);
00658     sprintf(smscbuff, "%s COM",nua);
00659   
00660     while((size_t) writeall < strlen(writebuff)){
00661     writeonce = -1;
00662     writeonce = write(padfd, writebuff+writeall, strlen(writebuff)-writeall);
00663     if(writeonce == -1){
00664         if(errno == EINTR || errno == EAGAIN)
00665         continue;
00666         else
00667         goto datalink_error;
00668     }
00669     if(writeonce > 0)
00670         writeall +=writeonce;
00671     }
00672     tcdrain(padfd); 
00673     usleep(1000*1000);/* wait for smsc answer */
00674 
00675     time(&timestart);
00676     while(time(NULL) - timestart < INTERNAL_CONNECT_TIMEVAL){
00677     if((size_t) readall >= sizeof(readbuff))
00678         goto error_overflow;
00679     /* We read 1 char a time */
00680     readonce = read(padfd, &readbuff[readall], 1);
00681     if(readonce == -1) {
00682         if(errno == EINTR || errno == EAGAIN) continue;
00683         else
00684         goto datalink_error;
00685     }
00686     if(readonce > 0)
00687         readall += readonce;
00688     /* Search for reponse line. */
00689     if(readall > 2 &&
00690        readbuff[readall-1] == '\n' && 
00691        readbuff[readall-2] == '\r') {
00692         if(strstr(readbuff, smscbuff)) {
00693         debug("smsc.sema", 0,
00694               "sema_open send link: smsc responded, virtual link established");
00695         x28_data_mode = X28_MT_DATA_MODE; 
00696         return 1;   
00697         }
00698     } 
00699     usleep(1000);
00700     }
00701     info(0,"sema_open_send_link: connect timeout");
00702     return 0;
00703 error_overflow:
00704     warning(0, "sema_open_send_link: command buffer overflow");
00705     return 0;
00706 datalink_error:
00707     error(errno,"sema_open_send_link: device file error");
00708     return -1;
00709 }
00710 
00711 
00712 
00713 static int X28_data_read(int padfd, char *cbuffer) {
00714     char *p = NULL;
00715     int ret,  len;
00716     fd_set read_fd;
00717     struct timeval tv, tvinit;
00718     size_t readall;
00719      
00720     tvinit.tv_sec = 0;
00721     tvinit.tv_usec = 1000;
00722      
00723     readall = 0;
00724     for (;;) {
00725     FD_ZERO(&read_fd);
00726     FD_SET(padfd, &read_fd);
00727     tv = tvinit;
00728     ret = select(padfd + 1, &read_fd, NULL, NULL, &tv);
00729     if (ret == -1) {
00730         if(errno==EINTR) goto got_data;
00731         if(errno==EAGAIN) goto got_data;
00732         error(errno, "Error doing select for fad");
00733         return -1;
00734     } else if (ret == 0)
00735         goto got_data;
00736     len = strlen(cbuffer);
00737     ret = read(padfd,
00738            cbuffer + len,
00739            256);    
00740     if (ret == -1) {
00741             error(errno," read device file");
00742         return -1;
00743     }
00744     if (ret == 0)
00745         goto eof;
00746        
00747     readall += ret;
00748     if ((size_t) len >  sizeof(cbuffer)- 256) {
00749         p = gw_realloc(cbuffer, sizeof(cbuffer) * 2);
00750         memset(p+len,0,sizeof(cbuffer)*2 - len);
00751         cbuffer = p;
00752     }
00753     if(readall > 0)
00754         break;
00755     }
00756      
00757 eof:
00758     if(readall > 0)
00759     ret = 1;
00760     goto unblock;
00761      
00762 got_data:
00763     ret = 0;
00764     goto unblock;
00765 
00766 unblock:
00767     return ret;  
00768 
00769 }
00770 
00771 static int X28_data_send(int padfd, char *cbuffer,int sentonce) {
00772     int len = 0, pos = 0,writeonce = 0,writeall = 0;
00773  
00774     tcdrain(padfd);
00775     len = strlen(cbuffer);
00776     while(len > 0){
00777     if(len < sentonce) {
00778         writeonce = write(padfd, cbuffer+pos, len);
00779     }
00780     else
00781         writeonce = write(padfd, cbuffer+pos, sentonce);
00782  
00783     if (writeonce == -1) {
00784         if(errno == EINTR || errno == EINTR)
00785         continue;
00786         else{
00787         goto error;
00788         }
00789     }
00790     if(writeonce > 0){
00791         len -= writeonce;
00792         pos += writeonce;
00793         writeall = pos;
00794     }
00795     }
00796     tcdrain(padfd);
00797     return writeall;
00798 
00799 error:
00800     error(errno,"sema_send data error: device file error");
00801     return -1;
00802 }
00803 
00804 static int X28_msg_pop(char *from, char *to)
00805 {
00806     char* Rbuff =NULL;
00807     char* RRbuff = NULL;
00808     char mobuff[] ="COM\r\n\0";
00809     char mobuffend[] = "\r\0";
00810     char prompbuff[] = "*\r\0";
00811     int len = 0, Llen= 0, Rlen = 0,RRlen = 0;
00812 
00813     len = strlen(from);
00814     if(len <=0) goto no_msg;
00815 
00816     /* trim off rabbish header */
00817     while(*from == '\r' || *from == '\n'){
00818     len = strlen(from);
00819     if(len > 1){
00820         memmove(from, from +1, len-1);
00821         memset(from+(len-1), 0, 1);
00822     }
00823     else{
00824         memset(from,0,len);
00825         return -1;
00826     }
00827     }   
00828 
00829     len = strlen(from); 
00830     /*all kinds of useful infomation contains \r*/
00831     if((Rbuff=memchr(from,'\r',len)) == NULL)
00832     goto no_msg;
00833 
00834  
00835     /*check if it is a command prompt *\r\n */
00836     if((Rbuff -from) > 0 && *(Rbuff -1) == '*'){
00837     if(strlen(Rbuff) < 2) goto no_msg; /*\n is not coming yet*/
00838      
00839     if(Rbuff -from > 4){ /* command info */
00840         Rlen = Rbuff -1 -from;
00841         memcpy(to,from,Rlen);
00842     }
00843     x28_data_mode = X28_COMMAND_MODE;
00844     if(strlen(Rbuff+1) > 1){
00845         Rlen = strlen(Rbuff +2);
00846         memmove(from, Rbuff +2, Rlen);
00847         memset(from+Rlen, 0, len-Rlen);
00848     }
00849     else
00850         memset(from, 0,len);
00851     }/* check mo msg , format X121address+COM\r\n+msg+\r*/
00852     else if((Rbuff-from) > 3 &&  strstr(Rbuff-4,mobuff)!= NULL){
00853     if(strlen(Rbuff) < 3 ||
00854        (RRbuff = strstr(Rbuff + 2, mobuffend)) == NULL)
00855         goto no_msg; /*the msg+\r  is still coming*/
00856 
00857     RRlen = RRbuff - (Rbuff+2);
00858     if(RRlen > 4){ /* msg header is 4 byte always+msg content*/ 
00859         memcpy(to, Rbuff +2 , RRlen);
00860         x28_data_mode = X28_MO_DATA_MODE;
00861     }
00862 
00863     if(strlen(RRbuff) > 1){
00864         Rlen = strlen(RRbuff +1);
00865         memmove(from, RRbuff+1 ,Rlen);
00866         memset(from+Rlen,0,len -Rlen);
00867     }
00868     else
00869         memset(from,0,len);
00870     }
00871     else{/* it can be mt reply */
00872     if(Rbuff  - from > 0){ 
00873         Llen = Rbuff - from;
00874         memcpy(to, from, Llen);
00875     }    
00876     if(strlen(Rbuff) > 1){
00877         Rlen = strlen(Rbuff+1);
00878         memmove(from,Rbuff+1,Rlen);
00879         memset(from+Rlen,0,len-Rlen);
00880     }
00881     else
00882         memset(from,0,len);
00883     }
00884 
00885     /* check rest of line for link state: command mode or data mode */
00886     if(strstr(from,prompbuff) != NULL)
00887     x28_data_mode = X28_COMMAND_MODE;
00888 
00889     return 0;
00890 no_msg:
00891     return -1;
00892 }
00893 
00894 
00895 
00896 static int sema_submit_result(SMSCenter *smsc, sema_msg* srcmsg, int result)
00897 {
00898     char IA5buff[1024];
00899     unsigned char oct1byte[1];
00900     unsigned char ia5byte[2];
00901     unsigned char cTr='t';
00902     unsigned char cMr='m';
00903     unsigned char ccontinuebyte = 'P', ccr = '\r';
00904     int j = 0, iret;
00905 
00906     memset(IA5buff,0,sizeof(IA5buff));
00907     switch(srcmsg->type)
00908     {
00909     case 'M':
00910     memcpy(IA5buff,&cMr,1);/*msg type*/
00911     memcpy(IA5buff+1,&ccontinuebyte,1); /*continue bit*/
00912     memcpy(IA5buff+2,srcmsg->optref,4); /*operation reference*/
00913     write_variable_value(result,oct1byte);
00914     j=internal_char_hex_to_IA5(oct1byte[0],ia5byte);
00915     memcpy(IA5buff+6,ia5byte,j);
00916     memcpy(IA5buff+6+j,&ccr,1);/*result*/
00917     iret = X28_data_send(smsc->sema_fd,IA5buff,strlen(IA5buff));
00918     if(iret == -1) goto error;
00919     break;
00920     case 'T':
00921     memcpy(IA5buff,&cTr,1);
00922     memcpy(IA5buff+1,&ccontinuebyte,1);
00923     memcpy(IA5buff+2,srcmsg->optref,4); 
00924     write_variable_value(result,oct1byte);
00925     j=internal_char_hex_to_IA5(oct1byte[0],ia5byte);
00926     memcpy(IA5buff+6,ia5byte,j);
00927     memcpy(IA5buff+6+j,&ccr,1);
00928     iret = X28_data_send(smsc->sema_fd,IA5buff,strlen(IA5buff));
00929     if(iret == -1) goto error;    
00930     break;
00931     default:  
00932     return 0; /*unsupoorted result msg type*/
00933     }
00934     return 1;   
00935 error:
00936     error(0,"sk_submit_result: write to device file failed");
00937     return -1;
00938 }
00939 
00940 static int sema_msg_session_mt(SMSCenter *smsc, sema_msg* pmsg){
00941     struct msg_hash *segments = NULL;
00942     struct sema_msg* mtrmsg = NULL;
00943     struct sm_statusreport_invoke* report_invoke = NULL;
00944     struct sm_submit_result* submit_result = NULL;
00945     struct sm_submit_invoke* submit_invoke = NULL;
00946     struct sm_deliver_invoke* deliver_invoke = NULL;
00947 
00948     char data[1024], IA5buff[256], IA5chars[1024], mochars[10*1024];
00949     unsigned char ccontinuebyte, ccr = '\r';
00950     unsigned char cerr[] = "ERR\0",cclr[] = "CLR\0", tmp1[5] , tmp2[5];
00951   
00952     int  i, iseg = 0, ilen = 0,iret = 0, moret;
00953     int isrcved = 0, iTrcved = 0, decoderesult = 0;
00954     time_t tstart;
00955 
00956     submit_invoke = (struct sm_submit_invoke*) pmsg->msgbody;
00957     if(submit_invoke == NULL) goto error;
00958 
00959     /*encode first*/
00960     memset(IA5chars,0,sizeof(IA5chars));
00961 
00962     if(sema_encode_msg(pmsg, IA5chars) < 1) goto encode_error;
00963 
00964     /*divide segments, we send buffer no more than 128 byte once*/
00965     iseg = strlen(IA5chars)/121 + 1;
00966     segments = gw_malloc(iseg * sizeof(struct msg_hash));
00967     if(segments == NULL) goto error;
00968 
00969 
00970     /*first segments*/  
00971     if(strlen(IA5chars) < 121)
00972     ilen = strlen(IA5chars);
00973     else
00974     ilen = 121;
00975     segments[0].content = octstr_create_from_data((char *)&(pmsg->type), 1);/*msg type, in hex*/
00976     ccontinuebyte = pack_continous_byte(pmsg->encodetype, 1, iseg -1);
00977     octstr_insert_data(segments[0].content, 1, 
00978                (char *)&ccontinuebyte, 1);  /*continue char, in hex*/
00979     octstr_insert_data(segments[0].content,
00980                2, (char *)pmsg->optref, 4); /*operation reference, in hex*/
00981     octstr_insert_data(segments[0].content, 6,
00982                IA5chars, ilen);
00983     octstr_insert_data(segments[0].content,
00984                octstr_len(segments[0].content), (char *)&ccr, 1); /*<cr>*/
00985  
00986     /*rest segments*/
00987     for( i = 1; i < iseg; i++){
00988     if(strlen(IA5chars) - i*121 < 121)
00989         ilen = strlen(IA5chars) - i*121;
00990     else
00991         ilen =121;
00992     segments[i].content= octstr_create_from_data((char *)&(pmsg->type), 1); 
00993     ccontinuebyte = pack_continous_byte(pmsg->encodetype, 0, iseg -i-1);
00994     octstr_insert_data(segments[i].content, 1, (char *)&ccontinuebyte, 1); 
00995     octstr_insert_data(segments[i].content, 2, (char *)pmsg->optref, 4); 
00996     octstr_insert_data(segments[i].content, 6, 
00997                IA5chars + i*121, ilen);
00998     octstr_insert_data(segments[i].content,
00999                octstr_len(segments[i].content),(char *)&ccr, 1); 
01000     }
01001 
01002     if(x28_data_mode != X28_MT_DATA_MODE){
01003     /* do not trust any existing data mode*/    
01004     X28_close_send_link(smsc->sema_fd);     
01005     /*open send link*/
01006     if((iret = X28_open_send_link(smsc->sema_fd,smsc->sema_smscnua)) < 1){
01007         if(iret == -1){
01008         iret = X28_reopen_data_link(smsc->sema_fd, smsc->sema_serialdevice);
01009         if(iret == -1){
01010             goto error;
01011         }
01012         }
01013         X28_close_send_link(smsc->sema_fd); 
01014         sleep(1);
01015         iret = X28_open_send_link(smsc->sema_fd,smsc->sema_smscnua);
01016         if(iret < 1)
01017         goto sendlink_error;
01018     }
01019     }
01020     /*deliver buff*/
01021     for(i = 0; i < iseg; i++){
01022     memset(IA5buff,0,sizeof(IA5buff));
01023     memcpy(IA5buff,octstr_get_cstr(segments[i].content),
01024            octstr_len(segments[i].content));
01025 
01026     iret =X28_data_send(smsc->sema_fd,IA5buff,strlen(IA5buff));
01027     if(iret == -1)
01028         goto error;
01029     octstr_destroy(segments[i].content);
01030     }
01031     gw_free(segments);
01032 
01033     /*wait result and report return*/
01034     mtrmsg = sema_msg_new();
01035     memset(mochars,0,sizeof(mochars));
01036 
01037     time(&tstart);
01038     while(time(NULL) -tstart < INTERNAL_SESSION_MT_TIMEVAL){
01039     iret = X28_data_read(smsc->sema_fd, smsc->buffer);
01040     if(iret == -1)
01041         goto error;
01042     
01043     /* Interpret the raw data */
01044     memset(data,0,sizeof(data));
01045     while(X28_msg_pop(smsc->buffer, data) == 0 ) {
01046         if(strlen(data) > 0){
01047         if(strstr(data,(char *)cerr) != NULL ||
01048            strstr(data,(char *)cclr) != NULL){
01049           debug("smsc.sema", 0, "sema_mt_session: Radio Pad Command line-%s",data);
01050             goto sendlink_error;
01051         }
01052         /* decode msg*/      
01053         decoderesult = sema_decode_msg(&mtrmsg,data);  
01054         if(decoderesult >= 0){
01055             if(mtrmsg->type == 's'){ /*submit result*/
01056      
01057             submit_result = (struct sm_submit_result*) mtrmsg->msgbody;
01058             if(submit_result == NULL) goto error;
01059             /* check result operation number is what we send */
01060             memset(tmp1,0,5); memset(tmp2,0,5);
01061             memcpy(tmp1,mtrmsg->optref,4);
01062             memcpy(tmp2, pmsg->optref,4);
01063             if(strstr((char *)tmp1,(char *)tmp2) != NULL){
01064                 isrcved = 1;
01065                 memcpy(submit_invoke->smscrefnum, submit_result->smscrefnum,4);
01066             }
01067             if(isrcved == 1 &&
01068                submit_result->smeresult != 0){       
01069                 gw_free(submit_result);
01070                 goto smsc_say_fail;  
01071             }
01072             gw_free(submit_result);
01073     
01074             } 
01075             else if(mtrmsg->type == 'T'){ /*report invoke*/
01076         
01077             report_invoke = (struct sm_statusreport_invoke*) mtrmsg->msgbody;
01078             if(report_invoke == NULL) goto error;
01079             /*check if report reference number is what we expect*/
01080             memset(tmp1,0,sizeof(tmp1)); memset(tmp2,0,sizeof(tmp2));
01081             memcpy(tmp1,report_invoke->smscrefnum,4);
01082             memcpy(tmp2,submit_invoke->smscrefnum,4);
01083             if(strstr((char *)tmp1,(char *)tmp2) != NULL){
01084                 iTrcved = 1;
01085             }
01086             decoderesult = 0; 
01087             iret = sema_submit_result(smsc, mtrmsg, decoderesult);
01088             if(iret == -1) goto error;
01089             if(iTrcved == 1 &&
01090                report_invoke->status != 3){ /*3 means msg delivered*/
01091                 info(0,"sema_mt_session: submit invoke failed with report value-%i",report_invoke->status);
01092                 gw_free(report_invoke);
01093                 goto smsc_say_fail;
01094             }
01095             gw_free(report_invoke);
01096 
01097             }
01098             else if(mtrmsg->type == 'M'){/* deliver invoke*/
01099       
01100             /* we do not deal with deliver in mt session*/ 
01101             decoderesult = 0;
01102             iret = sema_submit_result(smsc, mtrmsg, decoderesult);
01103             if(iret == -1) goto error;
01104             deliver_invoke = (struct sm_deliver_invoke*) mtrmsg->msgbody;
01105             if(deliver_invoke != NULL){
01106                 gw_free(deliver_invoke);
01107                 /*append buffer back to  smsc->buffer*/
01108                 ilen=strlen(mochars);
01109                 memcpy(mochars+ilen,data,strlen(data));
01110                 ilen=strlen(mochars);
01111                 memcpy(mochars+ilen,&ccr,1);
01112             }       
01113             time(&tstart);
01114             }
01115             /* clean msg for next read*/
01116             memset(mtrmsg,0,sizeof(struct sema_msg));
01117         }
01118         /* clean buffer for next useful info*/
01119         memset(data,0,sizeof(data));
01120         if(sema_wait_report == 0 && isrcved == 1)
01121         {
01122             info(0,"sema_mt_session: submit invoke delivered successfully to smsc");
01123             goto mo_success;
01124         }
01125         if(sema_wait_report > 0 &&
01126            isrcved == 1 && iTrcved == 1)
01127         {
01128             info(0,"sema_mt_session: submit invoke delivered successfully to msisdn");
01129             goto mo_success;
01130         }
01131         }
01132     }
01133     }
01134 
01135 /* mo_timeout: */
01136       info(0,"sema_mt_session: timeout without receiving all expected returns");
01137       moret = SESSION_MT_RECEIVE_TIMEOUT;
01138       goto mo_return;
01139 mo_success:
01140     moret = SESSION_MT_RECEIVE_SUCCESS;
01141     goto mo_return;
01142 smsc_say_fail:
01143     info(0,"sema_mt_session: smsc says message deliver failed!");
01144     moret = SESSION_MT_RECEIVE_ERR;
01145     goto mo_return;
01146 mo_return:
01147     X28_close_send_link(smsc->sema_fd);
01148     /* we have to close here, otherwise smsc will wait for a long time
01149        untill it find out nothing is coming */
01150     sema_msg_free(mtrmsg);
01151     ilen = strlen(mochars);
01152     i =  strlen(smsc->buffer);
01153     if(ilen > 0){
01154     memmove( smsc->buffer+ilen,smsc->buffer,i);
01155     memcpy(smsc->buffer, mochars,ilen);
01156     }
01157     return moret;       
01158 sendlink_error:
01159     info(0,"sema_mt_session: X28 data link has broken");
01160     if(mtrmsg != NULL)
01161     sema_msg_free(mtrmsg);
01162     return 0;
01163 encode_error:
01164     info(0,"sema_mt_session: Msg encode error");
01165     return 0;
01166 error:
01167     error(0,"sema_mt session: memory allocation error or device file error");
01168     return -1;
01169 
01170 }
01171 
01172 
01173 static int sema_msg_session_mo(SMSCenter *smsc, char* cbuff){
01174   
01175     struct sema_msg *rmsg = NULL;
01176     int iret = 0, retresult = 0;
01177 
01178     struct sm_deliver_invoke* deliver_invoke = NULL;
01179     struct sm_statusreport_invoke* report_invoke = NULL;
01180  
01181     rmsg = sema_msg_new();
01182 
01183     iret = sema_decode_msg(&rmsg,cbuff);
01184     if(iret == - 1) goto msg_error;/* decode error */
01185 
01186     if(x28_data_mode == X28_COMMAND_MODE){
01187     /* do not trust any existing data mode*/
01188 
01189     /* XXX this should be fixed? -rpr */
01190     
01191     X28_close_send_link(smsc->sema_fd);     
01192     /*open send link*/
01193     if(X28_open_send_link(smsc->sema_fd,smsc->sema_smscnua) < 1){
01194         info(0,"sema_mo_session: can not establish send link");
01195         return 0;
01196     }     
01197     }
01198 
01199     if(rmsg->type == 'M'){  /* deliver invoke */
01200     retresult = 0;      /* deliver invoke */  
01201     iret = sema_submit_result(smsc, rmsg, retresult); 
01202     if(iret == -1) goto error;
01203     deliver_invoke = (struct sm_deliver_invoke*) rmsg->msgbody;
01204     if(deliver_invoke == NULL) goto msg_error;
01205     sema_msglist_push(smsc->sema_mo, rmsg);  
01206     return 1;
01207     }
01208     else if(rmsg->type == 'T'){ /* status report */
01209     retresult = 0;      /* let msg through */
01210     sema_submit_result(smsc, rmsg, retresult);
01211     if(iret == -1) goto error;
01212     report_invoke = (struct sm_statusreport_invoke*) rmsg->msgbody;
01213     if(report_invoke != NULL)  
01214         gw_free(report_invoke);
01215     }
01216     else{ /* add your additional support here*/
01217     }
01218     sema_msg_free(rmsg);
01219     return 1;
01220   
01221 msg_error:
01222     sema_msg_free(rmsg);
01223     error(0,"sema_mo session: Msg decode failed");
01224     return 0;
01225 error:  
01226     error(0,"sema_mo session: device file error or memory allocation problem!");
01227     return -1;
01228 }
01229 
01230 
01231 
01232 static int sema_decode_msg(sema_msg **desmsg, char* octsrc) {
01233     struct sm_deliver_invoke *receive_sm = NULL;
01234     struct sm_statusreport_invoke* receive_report = NULL;
01235     struct sm_submit_result* submit_result = NULL;
01236     
01237     unsigned char tmp[1024],tmpgsm[1024];
01238     int octetlen, iret, iusedbyte;
01239     int imsgtopseg = 0, imsgfollownum = 0, imsgencodetype = 0;
01240     unsigned char cmsgtype, cmsgcontinuebyte;
01241 
01242     /* message type */
01243     if(strlen(octsrc) <= 4) goto no_msg;
01244 
01245     /* check if we support this type */
01246     cmsgtype = *octsrc;
01247     if(cmsgtype != 's'      /* invoke reseult */
01248        && cmsgtype != 'M'   /* deliver invoke */
01249        && cmsgtype != 'T'){     /* report invoke */
01250     info(0,"sema_decode: msg type not supported");
01251     goto error_msg;
01252     }
01253 
01254     /*check if continue bit is correct */
01255     cmsgcontinuebyte = *(octsrc+1);
01256     iret = unpack_continous_byte(cmsgcontinuebyte,
01257                  &imsgencodetype,&imsgtopseg, &imsgfollownum);
01258 
01259     if(iret == -1){
01260     info(0,"sema_decode: msg continue bit can not be interpreted");
01261     goto error_msg;
01262     }
01263 
01264     /*status report and submit result will always be 1 segments
01265       for deliver invoke, if smsc can not send all the data in one packet,
01266       text data will be truncated ,so it's also 1 packet*/
01267     
01268     if(imsgtopseg == 0){
01269     info(0, "sema_decode: can not interpret more than one segments msg");
01270     goto error_msg;
01271     }   
01272 
01273     (*desmsg)->type = cmsgtype;
01274     (*desmsg)->continuebyte = cmsgcontinuebyte;
01275     (*desmsg)->encodetype = imsgencodetype;
01276 
01277     /*operation reference*/
01278 
01279     memcpy((*desmsg)->optref, octsrc +2, 4);
01280     octsrc += 6;
01281     iusedbyte = 0;
01282  
01283     switch(cmsgtype){
01284     case 's': /* submit invoke result */
01285     submit_result = gw_malloc(sizeof(struct sm_submit_result)); 
01286     memset(submit_result,0,sizeof(struct sm_submit_result));
01287 
01288     /* result */ 
01289     iusedbyte = line_scan_IA5_hex(octsrc, 1, tmp);
01290     if(iusedbyte < 1) goto error_submit;
01291     octetlen = 1;
01292     submit_result->smeresult = get_variable_value(tmp, &octetlen);
01293     if(submit_result->smeresult == SM_RESULT_SUCCESS)
01294     {
01295         /*smsc reference number*/
01296         octsrc += iusedbyte;    
01297         iusedbyte = line_scan_IA5_hex(octsrc, 4,tmp);
01298         if(iusedbyte <1) goto error_submit; 
01299         memcpy(submit_result->smscrefnum, tmp, 4);
01300         /*accept time*/
01301         octsrc += iusedbyte;     
01302         iusedbyte = line_scan_IA5_hex(octsrc, 14,tmp);
01303         if(iusedbyte < 1) goto error_submit;    
01304         memcpy(submit_result->accepttime, tmp, 4);
01305     }
01306     (*desmsg)->msgbody = submit_result;
01307     break;
01308     case 'M': 
01309     /* deliver invoke*/
01310     receive_sm = gw_malloc(sizeof(struct sm_deliver_invoke));
01311     memset(receive_sm, 0, sizeof(struct sm_deliver_invoke));
01312     /*deliver destination address length*/
01313     iusedbyte = line_scan_IA5_hex(octsrc, 1, tmp);
01314     if(iusedbyte < 1) goto error_deliver;
01315     octetlen = 1;
01316     receive_sm->destaddlen = get_variable_value(tmp, &octetlen);
01317     /*deliver destination address*/
01318     octsrc +=iusedbyte;    
01319     iusedbyte = line_scan_IA5_hex(octsrc,receive_sm->destaddlen,tmp);
01320     if(iusedbyte < 1) goto error_deliver;
01321     receive_sm->destadd= octstr_create_from_data((char *)tmp,  receive_sm->destaddlen);
01322     /*smsc reference number*/
01323     octsrc +=iusedbyte;
01324     iusedbyte = line_scan_IA5_hex(octsrc, 4,tmp);
01325     if(iusedbyte < 1) goto error_deliver;
01326     memcpy(receive_sm->smscrefnum, tmp, 4);
01327     /*originate address length*/
01328     octsrc +=iusedbyte;
01329     iusedbyte = line_scan_IA5_hex(octsrc, 1, tmp);
01330     if(iusedbyte < 1) goto error_deliver;
01331     octetlen = 1;
01332     receive_sm->origaddlen = get_variable_value(tmp, &octetlen);
01333     /*originate address*/
01334     octsrc +=iusedbyte;
01335     iusedbyte = line_scan_IA5_hex(octsrc, receive_sm->origaddlen, tmp);
01336     if(iusedbyte < 1) goto error_deliver;
01337     receive_sm->origadd= octstr_create_from_data((char *)tmp,receive_sm->origaddlen);
01338     /* data code scheme */ 
01339     octsrc +=iusedbyte;
01340     if(iusedbyte < 1) goto error_deliver;
01341     iusedbyte = line_scan_IA5_hex(octsrc, 1,tmp);
01342     octetlen = 1;
01343     receive_sm->DCS = get_variable_value(tmp, &octetlen);
01344     if(receive_sm->DCS != ENCODE_IA5 && receive_sm->DCS !=ENCODE_GSM){
01345         info(0, "sema_decode, Data encoding scheme not supported");
01346         goto error_deliver;
01347     }
01348     /* protocol */ 
01349     octsrc +=iusedbyte;
01350     iusedbyte = line_scan_IA5_hex(octsrc, 1,tmp);
01351     if(iusedbyte < 1) goto error_deliver;
01352     octetlen = 1;
01353     receive_sm->protocal = get_variable_value(tmp, &octetlen);
01354     /* reply path */
01355     octsrc +=iusedbyte;
01356     iusedbyte = line_scan_IA5_hex(octsrc, 1,tmp);
01357     if(iusedbyte < 1) goto error_deliver;
01358     octetlen = 1;
01359     receive_sm->replypath = get_variable_value(tmp, &octetlen);
01360     /*text size in septect*/
01361     octsrc +=iusedbyte;
01362     iusedbyte = internal_char_IA5_to_hex(octsrc, tmp);
01363     if(iusedbyte < 1) goto error_deliver;
01364     receive_sm->textsizeseptet = tmp[0];
01365     /*text size in octects*/
01366     octsrc +=iusedbyte;
01367     iusedbyte = internal_char_IA5_to_hex(octsrc, tmp);
01368     if(iusedbyte < 1) goto error_deliver;
01369     receive_sm->textsizeoctect = tmp[0];
01370     octsrc+=iusedbyte;
01371     
01372     /*message text*/
01373     
01374     iusedbyte = 0;
01375     memset(tmp,0,sizeof(tmp));                      
01376     if(receive_sm->DCS == ENCODE_IA5 && receive_sm->textsizeoctect > 0) 
01377     {
01378         iusedbyte = line_scan_IA5_hex(octsrc,receive_sm->textsizeoctect,tmp);      
01379         if(iusedbyte < 1) goto error_deliver;   
01380         receive_sm->shortmsg =octstr_create_from_data( (char *)tmp,receive_sm->textsizeoctect);
01381     }
01382     else if(receive_sm->DCS == ENCODE_GSM &&  receive_sm->textsizeseptet > 0)
01383     {
01384         memset(tmpgsm,0,sizeof(tmpgsm));
01385       
01386         iusedbyte = line_scan_IA5_hex(octsrc,receive_sm->textsizeoctect,tmp);
01387         if(iusedbyte < 1) goto error_deliver;
01388         line_scan_hex_GSM7(tmp,receive_sm->textsizeoctect,
01389                    receive_sm->textsizeseptet, tmpgsm);
01390         receive_sm->shortmsg = octstr_create_from_data((char *)tmpgsm,
01391                                receive_sm->textsizeseptet);
01392     
01393     }
01394     else if(receive_sm->textsizeoctect <= 0)
01395       receive_sm->shortmsg = octstr_create("");
01396 
01397     /*accepttime*/
01398     octsrc +=iusedbyte;
01399     iusedbyte = line_scan_IA5_hex(octsrc,14,tmp);
01400     if(iusedbyte < 1) goto error_deliver;
01401     memcpy(receive_sm->accepttime, tmp,14);
01402     /*valid time*/
01403     octsrc +=iusedbyte;
01404     iusedbyte = line_scan_IA5_hex(octsrc,14,tmp);
01405     if(iusedbyte < 1) goto error_deliver;
01406     memcpy(receive_sm->invoketime, tmp,14);
01407     (*desmsg)->msgbody = receive_sm;
01408     break;
01409     case 'T': 
01410     /* status report invoke */
01411     receive_report = gw_malloc(sizeof(struct sm_statusreport_invoke)); 
01412     memset(receive_report,0,sizeof(struct sm_statusreport_invoke));
01413     /*deliver msisdn address length*/
01414     iusedbyte = line_scan_IA5_hex(octsrc, 1, tmp);
01415     if(iusedbyte < 1) goto error_receive;
01416     octetlen = 1;
01417     receive_report->msisdnlen = get_variable_value(tmp, &octetlen);
01418     /*msisdn*/
01419     octsrc += iusedbyte;    
01420     iusedbyte = line_scan_IA5_hex(octsrc, receive_report->msisdnlen, tmp);
01421     if(iusedbyte < 1) goto error_receive;
01422     receive_report->msisdn = octstr_create_from_data( (char *)tmp,receive_report->msisdnlen);
01423     /*sme reference type*/
01424     octsrc += iusedbyte;
01425     iusedbyte = line_scan_IA5_hex(octsrc, 1, tmp);
01426     if(iusedbyte < 1) goto error_receive;
01427     octetlen = 1;
01428     receive_report->smetype = get_variable_value(tmp, &octetlen);
01429     /*sme reference number */
01430     octsrc += iusedbyte;    
01431     iusedbyte = line_scan_IA5_hex(octsrc,4, tmp);
01432     if(iusedbyte < 1) goto error_receive;
01433     memcpy(receive_report->smerefnum ,tmp, 4);
01434     /*smsc reference number */
01435     octsrc += iusedbyte;
01436     iusedbyte = line_scan_IA5_hex(octsrc,4, tmp);
01437     if(iusedbyte < 1) goto error_receive;
01438     memcpy(receive_report->smscrefnum ,tmp, 4);
01439     /*accepted time*/ 
01440     octsrc += iusedbyte;    
01441     iusedbyte = line_scan_IA5_hex(octsrc,14, tmp);
01442     if(iusedbyte < 1) goto error_receive;
01443     memcpy(receive_report->accepttime ,tmp, 4);
01444     /*status*/
01445     octsrc += iusedbyte;    
01446     iusedbyte = line_scan_IA5_hex(octsrc, 1, tmp);
01447     if(iusedbyte < 1) goto error_receive;
01448     octetlen = 1; 
01449     receive_report->status = get_variable_value(tmp, &octetlen);
01450     octsrc += iusedbyte;
01451     if(receive_report->status != 6) /*6 means unable to deliver , but retry*/
01452     {
01453         iusedbyte = line_scan_IA5_hex(octsrc,14, tmp);
01454         if(iusedbyte < 1) goto error_receive;
01455         memcpy(receive_report->completetime ,tmp, 14);
01456     }
01457     else
01458     {
01459         iusedbyte = line_scan_IA5_hex(octsrc,14, tmp);
01460         if(iusedbyte < 1) goto error_receive;
01461         memcpy(receive_report->intermediatime ,tmp, 14);
01462     }
01463     if(receive_report->status == 6 || receive_report->status == 1) /*unable to deliver ,both case */
01464     {       
01465         octsrc += iusedbyte;
01466         iusedbyte = line_scan_IA5_hex(octsrc, 1, tmp);
01467         if(iusedbyte < 1) goto error_receive;
01468         octetlen = 1;
01469         receive_report->failreason = get_variable_value(tmp, &octetlen);
01470     }
01471     /*deliver orignate address length*/
01472     octsrc += iusedbyte;
01473     iusedbyte = line_scan_IA5_hex(octsrc, 1, tmp);
01474     if(iusedbyte < 1) goto error_receive;
01475     octetlen = 1;
01476     receive_report->origaddlen = get_variable_value(tmp, &octetlen);
01477     /*orignate address*/
01478     octsrc += iusedbyte;
01479     iusedbyte = line_scan_IA5_hex(octsrc, receive_report->origaddlen, tmp);
01480     if(iusedbyte < 1) goto error_receive;
01481     receive_report->origadd = octstr_create_from_data((char *)tmp,  receive_report->msisdnlen);
01482     /* invoke time */
01483     octsrc += iusedbyte;     
01484     iusedbyte = line_scan_IA5_hex(octsrc,14, tmp);
01485     if(iusedbyte < 1){
01486         goto error_receive;
01487     }
01488     memcpy(receive_report->invoketime ,tmp, 14);
01489     (*desmsg)->msgbody = receive_report;
01490     break;
01491     }
01492     return 1;
01493 
01494 no_msg:
01495     info(0,"sema_decode: msg is empty");
01496     return 0;
01497 error_receive:
01498     gw_free(receive_report);
01499     goto error_msg;
01500 error_submit:
01501     gw_free(submit_result);
01502     goto error_msg;
01503 error_deliver:
01504     gw_free(receive_sm);
01505     goto error_msg;
01506 error_msg:
01507     info(0,"sema_decode:msg parameter is not recognized or unsupported");
01508     return 0;
01509 }
01510 
01511 
01512 static int sema_encode_msg(sema_msg* pmsg, char* str) {
01513     struct sm_submit_invoke *submit_sm = NULL;
01514     Octstr *IA5msg = NULL;
01515     int tSize = 0;
01516     unsigned char oc1byte[10];
01517     IA5msg = octstr_create(""); 
01518     switch(pmsg->type)
01519     {
01520     case 'S':
01521     submit_sm = (struct sm_submit_invoke *) pmsg->msgbody; 
01522     write_variable_value(submit_sm->msisdnlen, oc1byte); /*msisdn len*/
01523     line_append_hex_IA5(IA5msg, oc1byte,1);
01524     line_append_hex_IA5(IA5msg, 
01525                 (unsigned char *)octstr_get_cstr(submit_sm->msisdn),
01526                 octstr_len(submit_sm->msisdn)); /*msisdn*/
01527     write_variable_value(submit_sm->smereftype, oc1byte);/*smetype*/
01528     line_append_hex_IA5(IA5msg, oc1byte,1);
01529     line_append_hex_IA5(IA5msg, submit_sm->smerefnum,4);/*sme reference*/
01530     write_variable_value(submit_sm->priority, oc1byte);/*priority*/
01531     line_append_hex_IA5(IA5msg, oc1byte,1);
01532     write_variable_value(submit_sm->origaddlen, oc1byte); /*orignating address length*/
01533     line_append_hex_IA5(IA5msg, oc1byte,1);
01534     line_append_hex_IA5(IA5msg, 
01535                 (unsigned char *)octstr_get_cstr(submit_sm->origadd),
01536                 octstr_len(submit_sm->origadd)); /*orignating address*/
01537     write_variable_value(submit_sm->validperiodtype, oc1byte); /*valid period type*/
01538     line_append_hex_IA5(IA5msg, oc1byte,1);
01539     write_variable_value(submit_sm->validperiodrela, oc1byte); /*relative period*/
01540     line_append_hex_IA5(IA5msg, oc1byte,1);
01541     write_variable_value(submit_sm->DCS, oc1byte);/*data code scheme*/
01542     line_append_hex_IA5(IA5msg, oc1byte,1);
01543     write_variable_value(submit_sm->statusreportrequest, oc1byte);/*request report*/
01544     line_append_hex_IA5(IA5msg, oc1byte,1);
01545     write_variable_value(submit_sm->protocal, oc1byte);/*protocal id*/
01546     line_append_hex_IA5(IA5msg, oc1byte, 1);
01547     write_variable_value(submit_sm->replypath, oc1byte);/*use reply path*/
01548     line_append_hex_IA5(IA5msg, oc1byte, 1);
01549     
01550             /*text size in 7 bits char*/
01551         tSize = internal_char_hex_to_IA5(submit_sm->textsizeseptet,oc1byte);
01552     octstr_insert_data(IA5msg, octstr_len(IA5msg), (char *)oc1byte, tSize);
01553 
01554             /*text size in 8 bits char*/
01555     tSize = internal_char_hex_to_IA5(submit_sm->textsizeoctect,oc1byte);  
01556     octstr_insert_data(IA5msg, octstr_len(IA5msg),(char *) oc1byte, tSize);
01557 
01558     line_append_hex_IA5(IA5msg,           
01559                 (unsigned char *)octstr_get_cstr(submit_sm->shortmsg),
01560                 submit_sm->textsizeoctect); /*msg text*/
01561     memcpy(str,octstr_get_cstr(IA5msg),octstr_len(IA5msg));
01562     octstr_destroy(IA5msg);
01563     return 1;
01564     }
01565     return 0;
01566 }
01567 
01568 
01569 static int line_scan_hex_GSM7(unsigned char* from, 
01570                   int octects ,int spetets, unsigned char* to)
01571 {
01572     char* cin2 =NULL;
01573     unsigned char c;
01574     char cin7[8];
01575     int i, pos, value;
01576 
01577     int lenin2=octects*8;
01578     cin2 = gw_malloc(lenin2);
01579 
01580     memset(cin2,48,lenin2); /*make many zeros*/
01581     /*tranverse the octects first, so ABC -> CBA(in bin form)*/
01582     for(i = 0; i < octects; i ++)
01583     {
01584     c = *(from + i);
01585       
01586     if(c & 1) 
01587         cin2[(octects-1-i)*8 +7] = 49;
01588     if(c & 2) 
01589         cin2[(octects-1-i)*8 +6] = 49;
01590     if(c & 4) 
01591         cin2[(octects-1-i)*8 +5] = 49;
01592     if(c & 8) 
01593         cin2[(octects-1-i)*8 +4] = 49;
01594     if(c & 16) 
01595         cin2[(octects-1-i)*8 +3] = 49;
01596     if(c & 32) 
01597         cin2[(octects-1-i)*8 +2] = 49;
01598     if(c & 64) 
01599         cin2[(octects-1-i)*8 +1] = 49;
01600     if(c & 128) 
01601         cin2[(octects-1-i)*8] = 49;
01602     }
01603   
01604     i= 1;
01605     while( i <= spetets ){
01606     pos=lenin2 -1 -(i*7 -1);
01607     memset(cin7,0,sizeof(cin7));
01608     memcpy(cin7, cin2 + pos, 7);
01609     value = 0;
01610 
01611     if(cin7[6] == '1')
01612         value += 1;
01613     if(cin7[5] == '1')
01614         value += 2;
01615     if(cin7[4] == '1')
01616         value += 4;
01617     if(cin7[3] == '1')
01618         value += 8;
01619     if(cin7[2] == '1')
01620         value += 16;
01621     if(cin7[1] == '1')
01622         value += 32;
01623     if(cin7[0] == '1')
01624         value += 64;
01625       
01626     to[i-1]=internal_char_hex_to_gsm(value);
01627     i +=1;
01628     }
01629     return i;
01630   
01631 }
01632 
01633 /* check SMS2000 Version 4.0 B.4.2.3 */
01634 static int line_append_hex_IA5(Octstr* des, unsigned char* src, int len)
01635 {
01636 
01637     unsigned char IA5char[3];
01638     unsigned char tmp[1024];
01639     int j=0;
01640     int i=0, iall=0;
01641     for(i=0; i<len; i++)
01642     {
01643     memset(IA5char, 0, sizeof(IA5char));
01644     j=internal_char_hex_to_IA5(*(src+i),IA5char);
01645     if(j >0){
01646         memcpy(tmp+iall,IA5char,j);
01647         iall += j;
01648     }
01649     }
01650     octstr_insert_data(des,octstr_len(des),(char *)tmp,iall);
01651     return iall;
01652 }
01653 
01654 
01655 /* check SMS2000 Version 4.0 B.4.2.3 */
01656 static int line_scan_IA5_hex(char* from, 
01657                  int hexnum, unsigned char* to)
01658 {
01659     unsigned char cha[1];
01660     int cn =0, cnall = 0, i = 0;
01661     char *tmpfrom = NULL;
01662     tmpfrom = from;
01663     for(i = 0; i< hexnum; i++)
01664     {
01665     cn=internal_char_IA5_to_hex(tmpfrom, cha);
01666     if(cn >0)
01667     {
01668         memcpy(to+i,cha,1);
01669         tmpfrom += cn;
01670         cnall += cn;
01671     }
01672     else
01673         return -1;
01674     }
01675     return cnall;
01676 }
01677 
01678 
01679 static unsigned char internal_char_hex_to_gsm(unsigned char from)
01680 {
01681     switch (from){
01682     case 0x00: return '@';  
01683     case 0x01: return '£';
01684     case 0x02: return '$';
01685     case 0x03: return '¥';
01686     case 0x04: return 'è';
01687     case 0x05: return 'é';
01688     case 0x06: return 'ù';
01689     case 0x07: return 'ì';
01690     case 0x08: return 'ò';
01691     case 0x09: return 'Ç';
01692     case 0x0A: return '\n';
01693     case 0x0B: return 'Ø';
01694     case 0x0C: return 'ø';
01695     case 0x0D: return '\r';
01696     case 0x0E: return 'Å';
01697     case 0x0F: return 'å';
01698     case 0x10: return 'D';
01699     case 0x11: return ' ';
01700     case 0x12: return 'F';
01701     case 0x13: return 'G';
01702     case 0x14: return 'L';
01703     case 0x15: return 'W';
01704     case 0x16: return 'P';
01705     case 0x17: return 'Y';
01706     case 0x18: return 'S';
01707     case 0x19: return 'Q';
01708     case 0x1A: return 'X';
01709     case 0x1B: return ' ';
01710     case 0x1C: return 'Æ';
01711     case 0x1D: return 'æ';
01712     case 0x1E: return 'b';
01713     case 0x1F: return 'É';
01714     case 0x5B: return 'Ä';
01715     case 0x5C: return 'Ö';
01716     case 0x5D: return 'Ñ';
01717     case 0x5E: return 'Ü';
01718     case 0x5F: return '§';
01719     case 0x60: return '¿';
01720     case 0x7B: return 'a';
01721     case 0x7C: return 'ö';
01722     case 0x7D: return 'ñ';
01723     case 0x7E: return 'ü';
01724     case 0x7F: return 'à';
01725     default: return from;
01726     }
01727 }
01728 
01729 /* check SMS2000 Version 4.0 B.4.2.3 */
01730 static int internal_char_hex_to_IA5(unsigned char from, unsigned char * to){
01731 
01732     if(from <= 0x1F)
01733     {
01734     to[0] = '^';
01735     to[1] = 0x40 + from;
01736     return 2;
01737     }
01738     else if(from ==0x5C) 
01739     {
01740     to[0] = 0x5C;
01741     to[1] = 0x5C;
01742     return 2;
01743     }
01744     else if(from == 0x5E)
01745     {   
01746     to[0] = 0x5C; 
01747     to[1] = 0x5E;
01748     return 2;
01749     }
01750     else if(from == 0x60)
01751     {   
01752     to[0] = 0x5C;
01753     to[1] = 0x60;
01754     return 2;
01755     }
01756     else if(from == 0x7E)
01757     {   
01758     to[0] = 0x5C;
01759     to[1] = 0x7E;
01760     return 2;
01761     }
01762     else if(from >= 0x20 && from <= 0x7E)
01763     {
01764     to [0] = from; 
01765     return 1;
01766     }
01767     else if(from == 0x7F)
01768     {
01769     to[0] = 0x5E;
01770     to[1] = 0x7E;
01771     return 2;
01772     }
01773     else if(from >= 0x80 && from <=0x9F)
01774     {
01775     to[0] = 0x7E;
01776     to[1] = from -0x40;
01777     return 2;
01778     }
01779     else if(from >= 0xA0 && from <=0xFE)
01780     {
01781     to[0] = 0x60;
01782     to[1] = from -0x80;
01783     return 2;
01784     }
01785     else if(from == 0xFF)
01786     {
01787     to[0] =to[1] = 0x7E;
01788     return 2;
01789     }
01790     else
01791     
01792     return -1;
01793 }
01794 
01795 static int internal_char_IA5_to_hex(char *from, unsigned char * to){
01796     int ret = -1;
01797     int len = strlen(from);
01798 
01799     if(*from == '^' && len >= 2 &&
01800        *(from +1) == '~') 
01801     {
01802     *to = 0x7F; 
01803     ret = 2;
01804     }
01805     else if(*from ==0x5C && len >= 2 &&
01806         *(from +1) == 0x5C) 
01807     {   
01808     *to= 0x5C;      
01809     ret = 2;
01810     }
01811     else if(*from == 0x5C && len >= 2 &&
01812         *(from+1) == 0x5E)
01813     {   
01814     *to= 0x5E;  
01815     ret = 2;
01816     }
01817     else if(*from == 0x5C && len >= 2 &&
01818         *(from+1) == 0x60)
01819     {   
01820     *to= 0x60;
01821     ret = 2;
01822     }
01823     else if(*from == 0x5C && len >=2 &&
01824         *(from+1) == 0x7E)
01825     {   
01826     *to= 0x7E;
01827     ret = 2;
01828     }
01829     else if(*from == '^' && len >= 2 && 
01830         (*(from +1) >= 0x40 &&  *(from +1) <= 0x5F))
01831     {       
01832     *to = *(from +1) -0x40;     
01833     ret = 2;
01834     }
01835     else if(*from == '~' && len >= 2 && 
01836         (*(from +1) >= 0x40 && *(from +1) <= 0x5F))
01837     {       
01838     *to = *(from +1) +0x40; 
01839     ret = 2;
01840     }
01841     else if(*from == '`' && len >= 2 &&
01842         (*(from+1) >= 0x20 && *(from +1) <= 0x7E))
01843     {   
01844     *to = *(from +1) +0x80;
01845     ret = 2;
01846     }
01847     else if(*from >=0x20 && 
01848         *from <=0x7E)
01849     {
01850     *to= *from;
01851     ret = 1;
01852     }
01853         
01854     return ret;
01855 }
01856         
01857 
01858 static void increment_counter(void)
01859 {
01860     if(sema_counter[3] == 0x39)
01861     sema_counter[3] = 0x30;
01862     else
01863     {
01864     sema_counter[3] += 0x01;
01865     return;
01866     }
01867     if(sema_counter[2] == 0x39)
01868     sema_counter[2] = 0x30;
01869     else
01870     {
01871     sema_counter[2] += 0x01;
01872     return;
01873     }
01874     if(sema_counter[1] == 0x39)
01875     sema_counter[1] = 0x30;
01876     else
01877     {
01878     sema_counter[1] += 0x01;
01879     return;
01880     }   
01881     if(sema_counter[0] == 0x39)
01882     sema_counter[0] = 0x30;
01883     else
01884     sema_counter[0] += 0x01;
01885     return;
01886 }   
01887 
01888 /* check SMS2000 Version 4.0 B.4.2.2 */
01889 static unsigned char pack_continous_byte(int encode, 
01890                      int isfirst, int follownum)
01891 {
01892     char bin[4];
01893     int value;
01894 
01895     memset(bin, 0, 4);
01896     value = 0;
01897 
01898     if(isfirst == 1)
01899     strncpy(bin,"0101",4);
01900     else
01901     strncpy(bin,"0110",4);
01902 
01903     if(bin[3] == '1')
01904     value += 16;
01905     if(bin[2] == '1')
01906     value += 32;
01907     if(bin[1] == '1')
01908     value += 64;
01909     if(bin[0] == '1') /* although it's impossible */
01910     value += 128;
01911     return (value+follownum);
01912 }
01913 
01914 /* check SMS2000 Version 4.0 B.4.2.2 */
01915 static int unpack_continous_byte(unsigned char continueCount, 
01916                  int * encode,
01917                  int * isfirst, 
01918                  int * follownum)
01919 {
01920     int rest = 0;
01921     int head = 0;
01922       
01923     if(continueCount & 1)
01924     rest +=1;
01925     if(continueCount & 2)
01926     rest +=2;
01927     if(continueCount & 4)
01928     rest += 4;
01929     if(continueCount & 8)
01930     rest += 8;
01931 
01932     *follownum = rest;
01933 
01934     if(continueCount & 16)
01935     head += 1;
01936     
01937     if(continueCount & 32)
01938     head += 2;
01939 
01940     if(continueCount & 64)
01941     head += 4;
01942 
01943     if(continueCount & 128) /* though not possible */
01944     head += 8;
01945 
01946 
01947     *encode = *isfirst = -1;
01948 
01949     if(head == 5)
01950     {
01951     *encode =LINE_ENCODE_IA5;
01952     *isfirst = 1;
01953     }
01954     else if(head == 6)
01955     {
01956     *encode =LINE_ENCODE_IA5;
01957     *isfirst = 0;
01958     }
01959     else if(head == 4)
01960     {
01961     *encode =LINE_ENCODE_HEX;
01962     *isfirst = 1;
01963     }
01964     else if(head == 3)
01965     {
01966     *encode =LINE_ENCODE_HEX;
01967     *isfirst = 0;
01968     }
01969     else if(head == 7)
01970     {
01971     *encode =LINE_ENCODE_BIN;
01972     *isfirst = 1;
01973     }
01974     else if(head == 2)
01975     {
01976     *encode =LINE_ENCODE_BIN;
01977     *isfirst = 0;
01978     }
01979     if(*encode != -1 && *isfirst != -1)
01980     return 0;
01981     else
01982     return -1;
01983 }
01984 
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.