"Fossies" - the Fresh Open Source Software Archive

Member "netxms-3.8.193/src/agent/subagents/sms/sender.cpp" (4 Mar 2021, 8518 Bytes) of package /linux/misc/netxms-3.8.193.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "sender.cpp" see the Fossies "Dox" file reference documentation.

    1 /*
    2 ** NetXMS SMS sending subagent
    3 ** Copyright (C) 2006-2014 Raden Solutions
    4 **
    5 ** This program is free software; you can redistribute it and/or modify
    6 ** it under the terms of the GNU General Public License as published by
    7 ** the Free Software Foundation; either version 2 of the License, or
    8 ** (at your option) any later version.
    9 **
   10 ** This program is distributed in the hope that it will be useful,
   11 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
   12 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   13 ** GNU General Public License for more details.
   14 **
   15 ** You should have received a copy of the GNU General Public License
   16 ** along with this program; if not, write to the Free Software
   17 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
   18 **
   19 ** File: sender.cpp
   20 **
   21 **/
   22 
   23 #include "sms.h"
   24 
   25 bool SMSCreatePDUString(const char* phoneNumber, const char* message, char* pduBuffer);
   26 
   27 /**
   28  * Static data
   29  */
   30 static Serial s_serial;
   31 static const char *s_eosMarks[] = { "OK", "ERROR", NULL };
   32 static const char *s_eosMarksSend[] = { ">", "ERROR", NULL };
   33 static enum { OM_TEXT, OM_PDU } s_operationMode = OM_TEXT;
   34 
   35 /**
   36  * Read input to OK
   37  */
   38 static bool ReadToOK(Serial *serial, char *data = NULL)
   39 {
   40    char buffer[1024];
   41    memset(buffer, 0, 1024);
   42    while(true)
   43    {
   44       char *mark;
   45       int rc = serial->readToMark(buffer, 1024, s_eosMarks, &mark);
   46       if (rc <= 0)
   47       {
   48          AgentWriteDebugLog(5, _T("SMS: ReadToOK: readToMark returned %d"), rc);
   49          return false;
   50       }
   51       if (mark != NULL) 
   52       {
   53          if (data != NULL)
   54          {
   55             int len = (int)(mark - buffer);
   56             memcpy(data, buffer, len);
   57             data[len] = 0;
   58          }
   59 
   60          if (!strncmp(mark, "OK", 2))
   61             return true;
   62  
   63 #ifdef UNICODE
   64         AgentWriteDebugLog(5, _T("SMS: non-OK response (%hs)"), mark);
   65 #else
   66         AgentWriteDebugLog(5, _T("SMS: non-OK response (%s)"), mark);
   67 #endif
   68          return false;
   69       }
   70    }
   71 }
   72 
   73 /**
   74  * Initialize modem
   75  */
   76 static bool InitModem(Serial *serial)
   77 {
   78     serial->write("\x1A\r\n", 3); // in case of pending send operation
   79    ReadToOK(serial);
   80 
   81     serial->write("ATZ\r\n", 5); // init modem
   82    if (!ReadToOK(serial))
   83       return false;
   84     AgentWriteDebugLog(5, _T("SMS: ATZ sent, got OK"));
   85 
   86    serial->write("ATE0\r\n", 6); // disable echo
   87    if (!ReadToOK(serial))
   88       return false;
   89     AgentWriteDebugLog(5, _T("SMS: ATE0 sent, got OK"));
   90    
   91    return true;
   92 }
   93 
   94 /**
   95  * Initialize sender
   96  * pszInitArgs format: portname,speed,databits,parity,stopbits
   97  */
   98 bool InitSender(const TCHAR *pszInitArgs)
   99 {
  100     TCHAR *portName;
  101     
  102     if (pszInitArgs == NULL || *pszInitArgs == 0)
  103     {
  104 #ifdef _WIN32
  105         portName = _tcsdup(_T("COM1:"));
  106 #else
  107         portName = _tcsdup(_T("/dev/ttyS0"));
  108 #endif
  109     }
  110     else
  111     {
  112         portName = _tcsdup(pszInitArgs);
  113     }
  114     
  115     AgentWriteDebugLog(1, _T("SMS Sender: initializing GSM modem at %s"), pszInitArgs);
  116     
  117     TCHAR *p;
  118     const TCHAR *parityAsText;
  119     int portSpeed = 9600;
  120     int dataBits = 8;
  121     int parity = NOPARITY;
  122     int stopBits = ONESTOPBIT;
  123     
  124     if ((p = _tcschr(portName, _T(','))) != NULL)
  125     {
  126         *p = 0; p++;
  127         int tmp = _tcstol(p, NULL, 10);
  128         if (tmp != 0)
  129         {
  130             portSpeed = tmp;
  131             
  132             if ((p = _tcschr(p, _T(','))) != NULL)
  133             {
  134                 *p = 0; p++;
  135                 tmp = _tcstol(p, NULL, 10);
  136                 if (tmp >= 5 && tmp <= 8)
  137                 {
  138                     dataBits = tmp;
  139                     
  140                     // parity
  141                     if ((p = _tcschr(p, _T(','))) != NULL)
  142                     {
  143                         *p = 0; p++;
  144                         switch (tolower((char)*p))
  145                         {
  146                             case 'n': // none
  147                                 parity = NOPARITY;
  148                                 break;
  149                             case 'o': // odd
  150                                 parity = ODDPARITY;
  151                                 break;
  152                             case 'e': // even
  153                                 parity = EVENPARITY;
  154                                 break;
  155                         }
  156                         
  157                         // stop bits
  158                         if ((p = _tcschr(p, _T(','))) != NULL)
  159                         {
  160                             *p = 0; p++;
  161                             
  162                             if (*p == _T('2'))
  163                             {
  164                                 stopBits = TWOSTOPBITS;
  165                             }
  166 
  167                             // Text or PDU mode
  168                             if ((p = _tcschr(p, _T(','))) != NULL)
  169                             {
  170                                 *p = 0; p++;
  171                                 if (*p == _T('T'))
  172                                     s_operationMode = OM_TEXT;
  173                                 else if (*p == _T('P'))
  174                                     s_operationMode = OM_PDU;
  175                             }
  176                         }
  177                     }
  178                 }
  179             }
  180         }
  181     }
  182     
  183     switch (parity)
  184     {
  185         case ODDPARITY:
  186             parityAsText = _T("ODD");
  187             break;
  188         case EVENPARITY:
  189             parityAsText = _T("EVEN");
  190             break;
  191         default:
  192             parityAsText = _T("NONE");
  193             break;
  194     }
  195     AgentWriteDebugLog(1, _T("SMS: initialize for port=\"%s\", speed=%d, data=%d, parity=%s, stop=%d"),
  196                     portName, portSpeed, dataBits, parityAsText, stopBits == TWOSTOPBITS ? 2 : 1);
  197     
  198     if (s_serial.open(portName))
  199     {
  200         AgentWriteDebugLog(5, _T("SMS: port opened"));
  201         s_serial.setTimeout(2000);
  202         
  203       if (!s_serial.set(portSpeed, dataBits, parity, stopBits))
  204       {
  205         AgentWriteDebugLog(5, _T("SMS: cannot set port parameters"));
  206          goto cleanup;
  207       }
  208         
  209       if (!InitModem(&s_serial))
  210          goto cleanup;
  211 
  212         // enter PIN: AT+CPIN="xxxx"
  213         // register network: AT+CREG1
  214         
  215         s_serial.write("ATI3\r\n", 6); // read vendor id
  216         char vendorId[1024];
  217       if (!ReadToOK(&s_serial, vendorId))
  218          goto cleanup;
  219         AgentWriteDebugLog(5, _T("SMS init: ATI3 sent, got OK"));
  220         
  221         char *sptr, *eptr;  
  222         for(sptr = vendorId; (*sptr != 0) && ((*sptr == '\r') || (*sptr == '\n') || (*sptr == ' ') || (*sptr == '\t')); sptr++);
  223         for(eptr = sptr; (*eptr != 0) && (*eptr != '\r') && (*eptr != '\n'); eptr++);
  224         *eptr = 0;
  225 #ifdef UNICODE
  226         MultiByteToWideChar(CP_ACP, MB_PRECOMPOSED, sptr, -1, g_szDeviceModel, 256);
  227         g_szDeviceModel[255] = 0;
  228 #else
  229         nx_strncpy(g_szDeviceModel, sptr, 256);
  230 #endif
  231         AgentWriteLog(EVENTLOG_INFORMATION_TYPE, _T("SMS Sender: GSM modem initialized (Device=\"%s\" Model=\"%s\")"), pszInitArgs, g_szDeviceModel);
  232     }
  233     else
  234     {
  235         AgentWriteLog(EVENTLOG_WARNING_TYPE, _T("SMS Sender: Unable to open serial port (%s)"), pszInitArgs);
  236     }
  237 
  238 cleanup:
  239     MemFree(portName);
  240    s_serial.close();
  241     return TRUE;   // return TRUE always to keep subagent in memory
  242 }
  243 
  244 /**
  245  * Send SMS
  246  */
  247 bool SendSMS(const char *pszPhoneNumber, const char *pszText)
  248 {
  249     if ((pszPhoneNumber == NULL) || (pszText == NULL))
  250       return false;
  251 
  252     AgentWriteDebugLog(3, _T("SMS: send to {%hs}: {%hs}"), pszPhoneNumber, pszText);
  253    if (!s_serial.restart())
  254    {
  255     AgentWriteDebugLog(5, _T("SMS: failed to open port"));
  256       return false;
  257    }
  258 
  259    bool success = false;
  260    if (!InitModem(&s_serial))
  261       goto cleanup;
  262     
  263    if (s_operationMode == OM_PDU)
  264    {
  265        s_serial.write("AT+CMGF=0\r\n", 11); // =0 - PDU message
  266       if (!ReadToOK(&s_serial))
  267          goto cleanup;
  268        AgentWriteDebugLog(5, _T("SMS: AT+CMGF=0 sent, got OK"));
  269 
  270         char pduBuffer[PDU_BUFFER_SIZE];
  271         SMSCreatePDUString(pszPhoneNumber, pszText, pduBuffer);
  272 
  273       char buffer[256];
  274         snprintf(buffer, sizeof(buffer), "AT+CMGS=%d\r\n", (int)strlen(pduBuffer) / 2 - 1);
  275        s_serial.write(buffer, (int)strlen(buffer));
  276 
  277       char *mark;
  278       if (s_serial.readToMark(buffer, sizeof(buffer), s_eosMarksSend, &mark) <= 0)
  279          goto cleanup;
  280       if ((mark == NULL) || (*mark != '>'))
  281       {
  282        AgentWriteDebugLog(5, _T("SMS: wrong response to AT+CMGS=\"%hs\" (%hs)"), pszPhoneNumber, mark);
  283          goto cleanup;
  284       }
  285 
  286       s_serial.write(pduBuffer, (int)strlen(pduBuffer)); // send PDU
  287       s_serial.write("\x1A\r\n", 3); // send ^Z
  288    }
  289    else
  290    {
  291        s_serial.write("AT+CMGF=1\r\n", 11); // =1 - text message
  292       if (!ReadToOK(&s_serial))
  293          goto cleanup;
  294        AgentWriteDebugLog(5, _T("SMS: AT+CMGF=1 sent, got OK"));
  295 
  296       char buffer[256];
  297       snprintf(buffer, sizeof(buffer), "AT+CMGS=\"%s\"\r\n", pszPhoneNumber);
  298        s_serial.write(buffer, (int)strlen(buffer)); // set number
  299 
  300       char *mark;
  301       if (s_serial.readToMark(buffer, sizeof(buffer), s_eosMarksSend, &mark) <= 0)
  302          goto cleanup;
  303       if ((mark == NULL) || (*mark != '>'))
  304       {
  305        AgentWriteDebugLog(5, _T("SMS: wrong response to AT+CMGS=\"%hs\" (%hs)"), pszPhoneNumber, mark);
  306          goto cleanup;
  307       }
  308     
  309       if (strlen(pszText) <= 160)
  310       {
  311          snprintf(buffer, sizeof(buffer), "%s\x1A\r\n", pszText);
  312       }
  313       else
  314       {
  315          strncpy(buffer, pszText, 160);
  316          strcpy(&buffer[160], "\x1A\r\n");
  317       }
  318        s_serial.write(buffer, (int)strlen(buffer)); // send text, end with ^Z
  319    }
  320 
  321    s_serial.setTimeout(30000);
  322    if (!ReadToOK(&s_serial))
  323       goto cleanup;
  324 
  325    AgentWriteDebugLog(5, _T("SMS: AT+CMGS + message body sent, got OK"));
  326    success = true;
  327 
  328 cleanup:
  329    s_serial.setTimeout(2000);
  330    s_serial.close();
  331     return success;
  332 }