libsms_putsms.c

00001 /*
00002 SMS Server Tools
00003 Copyright (C) 2000-2002 Stefan Frings
00004 
00005 This program is free software unless you got it under another license directly
00006 from the author. You can redistribute it and/or modify it under the terms of
00007 the GNU General Public License as published by the Free Software Foundation.
00008 Either version 2 of the License, or (at your option) any later version.
00009 
00010 http://www.isis.de/members/~s.frings
00011 mailto:s.frings@mail.isis.de
00012  */
00013 
00014 
00015 #include <sys/types.h>
00016 #include <sys/stat.h>
00017 #include <fcntl.h>
00018 #include <termios.h>
00019 #include <stdio.h>
00020 #include <string.h>
00021 #include <unistd.h>
00022 #include <syslog.h>
00023 #include "sms_funcs.h"
00024 #include "libsms_charset.h"
00025 #include "libsms_modem.h"
00026 
00027 
00028 
00029 static char hexa[16] = {
00030         '0','1','2','3','4','5','6','7',
00031         '8','9','A','B','C','D','E','F'
00032         };
00033 
00034 
00035 void swapchars(char* string, int len) /* Swaps every second character */
00036 {
00037         int position;
00038         char c;
00039 
00040         for (position=0; position<len-1; position+=2)
00041         {
00042                 c=string[position];
00043                 string[position]=string[position+1];
00044                 string[position+1]=c;
00045         }
00046 }
00047 
00048 
00049 
00050 
00051 /* Work with the complex bit building to generate a 7 bit PDU string
00052    encapsulated in 8 bit */
00053 int ascii2pdu(char* ascii, int asciiLength, char* pdu, int cs_convert)
00054 {
00055         static char tmp[500];
00056         int pdubitposition=0;
00057         int pdubyteposition=0;
00058         int character;
00059         int bit;
00060         int pdubitnr;
00061         char converted;
00062         unsigned char foo;
00063 
00064         memset(tmp,0,asciiLength);
00065         for (character=0;character<asciiLength;character++)
00066         {
00067                 if (cs_convert)
00068                         converted=ascii2sms(ascii[character]);
00069                 else
00070                         converted=ascii[character];
00071                 for (bit=0;bit<7;bit++)
00072                 {
00073                         pdubitnr=7*character+bit;
00074                         pdubyteposition=pdubitnr/8;
00075                         pdubitposition=pdubitnr%8;
00076                         if (converted & (1<<bit))
00077                                 tmp[pdubyteposition]=tmp[pdubyteposition]|(1<<pdubitposition);
00078                         else
00079                                 tmp[pdubyteposition]=tmp[pdubyteposition]&~(1<<pdubitposition);
00080                 }
00081         }
00082         tmp[pdubyteposition+1]=0;
00083         for (character=0;character<=pdubyteposition; character++)
00084         {
00085                 foo = tmp[character] ;
00086                 pdu[2*character  ] = hexa[foo>>4];
00087                 pdu[2*character+1] = hexa[foo&0x0f];
00088         }
00089         pdu[2*(pdubyteposition+1)]=0;
00090         return 2*(pdubyteposition+1);
00091 }
00092 
00093 
00094 
00095 
00096 /* Create a HEX Dump */
00097 int binary2pdu(char* binary, int length, char* pdu)
00098 {
00099         int character;
00100         unsigned char foo;
00101 
00102         for (character=0;character<length; character++)
00103         {
00104                 foo = binary[character];
00105                 pdu[2*character  ] = hexa[foo>>4];
00106                 pdu[2*character+1] = hexa[foo&0x0f];
00107         }
00108         pdu[2*length]=0;
00109         return 2*length;
00110 }
00111 
00112 
00113 
00114 
00115 /* make the PDU string. The destination variable pdu has to be big enough. */
00116 int make_pdu(struct sms_msg *msg, struct modem *mdm, char* pdu)
00117 {
00118         int  coding;
00119         int  flags;
00120         char tmp[500];
00121         int  pdu_len=0;
00122         int  foo;
00123 
00124         memcpy(tmp,msg->to.s,msg->to.len);
00125         foo = msg->to.len;
00126         tmp[foo] = 0;
00127         // terminate the number with F if the length is odd
00128         if ( foo%2 ) {
00129                 tmp[foo]='F';
00130                 tmp[++foo] = 0;
00131         }
00132         // Swap every second character
00133         swapchars(tmp,foo);
00134         flags = 0x01;   /* SMS-Submit MS to SMSC */
00135         if (sms_report_type!=NO_REPORT)
00136                 flags |= 0x20 ; /* status report request */
00137         coding=240+1; // Dummy + Class 1
00138         if (mdm->mode!=MODE_OLD)
00139                 flags+=16; // Validity field
00140         /* concatenate the first part of the PDU string */
00141         if (mdm->mode==MODE_OLD)
00142                 pdu_len += sprintf(pdu,"%02X00%02X91%s00%02X%02X",flags,
00143                         msg->to.len,tmp,coding,msg->text.len);
00144         else
00145                 pdu_len += sprintf(pdu,"00%02X00%02X91%s00%02XA7%02X",flags,
00146                         msg->to.len,tmp,coding,msg->text.len);
00147         /* Create the PDU string of the message */
00148         /* pdu_len += binary2pdu(msg->text.s,msg->text.len,pdu+pdu_len); */
00149         pdu_len += ascii2pdu(msg->text.s,msg->text.len,pdu+pdu_len,1/*convert*/);
00150         /* concatenate the text to the PDU string */
00151         return pdu_len;
00152 }
00153 
00154 
00155 
00156 
00157 /* search into modem reply for the sms id */
00158 inline int fetch_sms_id(char *answer)
00159 {
00160         char *p;
00161         int  id;
00162 
00163         p = strstr(answer,"+CMGS:");
00164         if (!p)
00165                 goto error;
00166         p += 6;
00167         /* parse to the first digit */
00168         while(p && *p && (*p==' ' || *p=='\r' || *p=='\n'))
00169                 p++;
00170         if (*p<'0' || *p>'9')
00171                 goto error;
00172         /* convert the number*/
00173         id = 0;
00174         while (p && *p>='0' && *p<='9')
00175                 id = id*10 + *(p++)-'0';
00176 
00177         return id;
00178 error:
00179         return -1;
00180 }
00181 
00182 
00183 
00184 
00185 /* send sms */
00186 int putsms( struct sms_msg *sms_messg, struct modem *mdm)
00187 {
00188         char command[500];
00189         char command2[500];
00190         char answer[500];
00191         char pdu[500];
00192         int clen,clen2;
00193         int retries;
00194         int err_code;
00195         int pdu_len;
00196         int sms_id;
00197 
00198         pdu_len = make_pdu(sms_messg, mdm, pdu);
00199         if (mdm->mode==MODE_OLD)
00200                 clen = sprintf(command,"AT+CMGS=%i\r",pdu_len/2);
00201         else if (mdm->mode==MODE_ASCII)
00202                 clen = sprintf(command,"AT+CMGS=\"+%.*s\"\r",sms_messg->to.len,
00203                         sms_messg->to.s);
00204         else
00205                 clen = sprintf(command,"AT+CMGS=%i\r",pdu_len/2-1);
00206 
00207         if (mdm->mode==MODE_ASCII)
00208                 clen2=sprintf(command2,"%.*s\x1A",sms_messg->text.len,
00209                 sms_messg->text.s);
00210         else
00211                 clen2=sprintf(command2,"%.*s\x1A",pdu_len,pdu);
00212 
00213         sms_id = 0;
00214         for(err_code=0,retries=0;err_code<2 && retries<mdm->retry; retries++)
00215         {
00216                 if (put_command(mdm,command,clen,answer,sizeof(answer),50,"\r\n> ")
00217                 && put_command(mdm,command2,clen2,answer,sizeof(answer),1000,0)
00218                 && strstr(answer,"OK") )
00219                 {
00220                         /* no error during sending and the modem said OK */
00221                         err_code = 2;
00222                         /* if reports were request, we have to fetch the sms id from
00223                         the modem reply to keep trace of the status reports */
00224                         if (sms_report_type!=NO_REPORT) {
00225                                 sms_id = fetch_sms_id(answer);
00226                                 if (sms_id==-1)
00227                                         err_code = 1;
00228                         }
00229                 } else {
00230                         /* we have an error */
00231                         if (checkmodem(mdm)==-1) {
00232                                 err_code = 0;
00233                                 LM_WARN("resending last sms! \n");
00234                         } else if (err_code==0) {
00235                                 LM_WARN("possible corrupted sms. Let's try again!\n");
00236                                 err_code = 1;
00237                         }else {
00238                                 LM_ERR("We have a FUBAR sms!! drop it!\n");
00239                                 err_code = 3;
00240                         }
00241                 }
00242         }
00243 
00244         if (err_code==0)
00245                 LM_WARN("something spooky is going on with the modem!"
00246                         " Re-inited and re-tried for %d times without success!\n",
00247                         mdm->retry);
00248         return (err_code==0?-2:(err_code==2?sms_id:-1));
00249 }
00250