210d11c63cef04aafc9e7cd4e23c5d3b604db55e
[public/netxms.git] / src / server / smsdrv / generic / main.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** Generic SMS driver
4 ** Copyright (C) 2003-2010 Alex Kirhenshtein
5 **
6 ** This program is free software; you can redistribute it and/or modify
7 ** it under the terms of the GNU Lesser General Public License as published by
8 ** the Free Software Foundation; either version 3 of the License, or
9 ** (at your option) any later version.
10 **
11 ** This program is distributed in the hope that it will be useful,
12 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 ** GNU General Public License for more details.
15 **
16 ** You should have received a copy of the GNU Lesser General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 **
20 ** File: main.cpp
21 **
22 **/
23
24 #include "main.h"
25
26 // extern bool SMSPack7BitChars(const char* input, char* output, int* outputLength, const int maxOutputLen);
27 bool SMSCreatePDUString(const char* phoneNumber, const char* message, char* pduBuffer, const int pduBufferSize);
28
29 static Serial m_serial;
30
31 // pszInitArgs format: portname,speed,databits,parity,stopbits
32 extern "C" BOOL EXPORT SMSDriverInit(const TCHAR *pszInitArgs)
33 {
34 bool bRet = false;
35 TCHAR *portName;
36
37 if (pszInitArgs == NULL || *pszInitArgs == 0)
38 {
39 #ifdef _WIN32
40 portName = _tcsdup(_T("COM1:"));
41 #else
42 portName = _tcsdup(_T("/dev/ttyS0"));
43 #endif
44 }
45 else
46 {
47 portName = _tcsdup(pszInitArgs);
48 }
49
50 DbgPrintf(1, _T("Loading Generic SMS Driver (configuration: %s)"), pszInitArgs);
51
52 TCHAR *p;
53 int portSpeed = 9600;
54 int dataBits = 8;
55 int parity = NOPARITY;
56 int stopBits = ONESTOPBIT;
57
58 if ((p = _tcschr(portName, _T(','))) != NULL)
59 {
60 *p = 0; p++;
61 int tmp = _tcstol(p, NULL, 10);
62 if (tmp != 0)
63 {
64 portSpeed = tmp;
65
66 if ((p = _tcschr(p, _T(','))) != NULL)
67 {
68 *p = 0; p++;
69 tmp = _tcstol(p, NULL, 10);
70 if (tmp >= 5 && tmp <= 8)
71 {
72 dataBits = tmp;
73
74 // parity
75 if ((p = _tcschr(p, _T(','))) != NULL)
76 {
77 *p = 0; p++;
78 switch (tolower(*p))
79 {
80 case _T('n'): // none
81 parity = NOPARITY;
82 break;
83 case _T('o'): // odd
84 parity = ODDPARITY;
85 break;
86 case _T('e'): // even
87 parity = EVENPARITY;
88 break;
89 }
90
91 // stop bits
92 if ((p = _tcschr(p, _T(','))) != NULL)
93 {
94 *p = 0; p++;
95
96 if (*p == _T('2'))
97 {
98 stopBits = TWOSTOPBITS;
99 }
100 }
101 }
102 }
103 }
104 }
105 }
106
107 switch (parity)
108 {
109 case ODDPARITY:
110 p = (TCHAR *)_T("ODD");
111 break;
112 case EVENPARITY:
113 p = (TCHAR *)_T("EVEN");
114 break;
115 default:
116 p = (TCHAR *)_T("NONE");
117 break;
118 }
119 DbgPrintf(2, _T("SMS init: port={%s}, speed=%d, data=%d, parity=%s, stop=%d"),
120 portName, portSpeed, dataBits, p, stopBits == TWOSTOPBITS ? 2 : 1);
121
122 bRet = m_serial.Open(portName);
123 if (bRet)
124 {
125 DbgPrintf(4, _T("SMS: port opened"));
126 m_serial.SetTimeout(1000);
127 m_serial.Set(portSpeed, dataBits, parity, stopBits);
128
129 // enter PIN: AT+CPIN="xxxx"
130 // register network: AT+CREG1
131
132 char szTmp[128];
133 m_serial.Write("ATZ\r\n", 5); // init modem && read user prefs
134 m_serial.Read(szTmp, 128); // read OK
135 DbgPrintf(4, _T("SMS init: ATZ sent, got {%hs}"), szTmp);
136 m_serial.Write("ATE0\r\n", 6); // disable echo
137 m_serial.Read(szTmp, 128); // read OK
138 DbgPrintf(4, _T("SMS init: ATE0 sent, got {%hs}"), szTmp);
139 m_serial.Write("ATI3\r\n", 6); // read vendor id
140 m_serial.Read(szTmp, 128); // read version
141 DbgPrintf(4, _T("SMS init: ATI3 sent, got {%hs}"), szTmp);
142
143 if (stricmp(szTmp, "ERROR") != 0)
144 {
145 char *sptr, *eptr;
146
147 for(sptr = szTmp; (*sptr != 0) && ((*sptr == '\r') || (*sptr == '\n') || (*sptr == ' ') || (*sptr == '\t')); sptr++);
148 for(eptr = sptr; (*eptr != 0) && (*eptr != '\r') && (*eptr != '\n'); eptr++);
149 *eptr = 0;
150 #ifdef UNICODE
151 WCHAR *wdata = WideStringFromMBString(sptr);
152 nxlog_write(MSG_GSM_MODEM_INFO, EVENTLOG_INFORMATION_TYPE, "ss", pszInitArgs, wdata);
153 free(wdata);
154 #else
155 nxlog_write(MSG_GSM_MODEM_INFO, EVENTLOG_INFORMATION_TYPE, "ss", pszInitArgs, sptr);
156 #endif
157 }
158 }
159 else
160 {
161 DbgPrintf(1, _T("SMS: Unable to open serial port (%s)"), portName);
162 }
163
164 if (portName != NULL)
165 {
166 free(portName);
167 }
168
169 return bRet;
170 }
171
172 extern "C" BOOL EXPORT SMSDriverSend_(const TCHAR *pszPhoneNumber, const TCHAR *pszText)
173 {
174 if (pszPhoneNumber != NULL && pszText != NULL)
175 {
176 char szTmp[128];
177
178 DbgPrintf(3, _T("SMS send: to {%s}: {%s}"), pszPhoneNumber, pszText);
179
180 m_serial.Write("ATZ\r\n", 5); // init modem && read user prefs
181 m_serial.Read(szTmp, 128); // read OK
182 DbgPrintf(4, _T("SMS send: ATZ sent, got {%hs}"), szTmp);
183 m_serial.Write("ATE0\r\n", 5); // disable echo
184 m_serial.Read(szTmp, 128); // read OK
185 DbgPrintf(4, _T("SMS send: ATE0 sent, got {%hs}"), szTmp);
186 m_serial.Write("AT+CMGF=1\r\n", 11); // =1 - text message
187 m_serial.Read(szTmp, 128); // read OK
188 DbgPrintf(4, _T("SMS send: AT+CMGF=1 sent, got {%hs}"), szTmp);
189 #ifdef UNICODE
190 char mbPhoneNumber[256];
191 WideCharToMultiByte(CP_ACP, WC_DEFAULTCHAR | WC_COMPOSITECHECK, pszPhoneNumber, -1, mbPhoneNumber, 256, NULL, NULL);
192 mbPhoneNumber[255] = 0;
193 snprintf(szTmp, sizeof(szTmp), "AT+CMGS=\"%s\"\r\n", mbPhoneNumber);
194 #else
195 snprintf(szTmp, sizeof(szTmp), "AT+CMGS=\"%s\"\r\n", pszPhoneNumber);
196 #endif
197 m_serial.Write(szTmp, (int)strlen(szTmp)); // set number
198 #ifdef UNICODE
199 char mbText[161];
200 WideCharToMultiByte(CP_ACP, WC_DEFAULTCHAR | WC_COMPOSITECHECK, pszText, -1, mbText, 161, NULL, NULL);
201 mbText[160] = 0;
202 snprintf(szTmp, sizeof(szTmp), "%s%c\r\n", mbText, 0x1A);
203 #else
204 snprintf(szTmp, sizeof(szTmp), "%s%c\r\n", pszText, 0x1A);
205 #endif
206 m_serial.Write(szTmp, (int)strlen(szTmp)); // send text, end with ^Z
207 m_serial.Read(szTmp, 128); // read +CMGS:ref_num
208 DbgPrintf(4, _T("SMS send: AT+CMGS + message body sent, got {%hs}"), szTmp);
209 }
210
211 return true;
212 }
213
214 extern "C" BOOL EXPORT SMSDriverSend/*PDU*/(const TCHAR *pszPhoneNumber, const TCHAR *pszText)
215 {
216 if (pszPhoneNumber != NULL && pszText != NULL)
217 {
218 const int bufferSize = 512;
219 char szTmp[bufferSize];
220 char phoneNumber[bufferSize], text[bufferSize];
221
222 DbgPrintf(3, _T("SMS send: to {%s}: {%s}"), pszPhoneNumber, pszText);
223
224 #ifdef UNICODE
225 if (WideCharToMultiByte(CP_ACP, 0, pszPhoneNumber, -1, phoneNumber, bufferSize, NULL, NULL) == 0 ||
226 WideCharToMultiByte(CP_ACP, 0, pszText, -1, text, bufferSize, NULL, NULL) == 0 )
227 {
228 DbgPrintf(2, _T("Failed to convert phone number or text to multibyte string"));
229 return FALSE;
230 }
231 #else
232 nx_strncpy(phoneNumber, pszPhoneNumber, bufferSize);
233 nx_strncpy(text, pszText, bufferSize);
234 #endif
235
236 m_serial.Write("ATZ\r\n", 5); // init modem && read user prefs
237 m_serial.Read(szTmp, 128); // read OK
238 DbgPrintf(4, _T("SMS send: ATZ sent, got {%hs}"), szTmp);
239 m_serial.Write("ATE0\r\n", 6); // disable echo
240 m_serial.Read(szTmp, 128); // read OK
241 DbgPrintf(4, _T("SMS send: ATE0 sent, got {%hs}"), szTmp);
242 m_serial.Write("AT+CMGF=0\r\n", 11); // =0 - send text in PDU mode
243 m_serial.Read(szTmp, 128); // read OK
244 DbgPrintf(4, _T("SMS send: AT+CMGF=0 sent, got {%hs}"), szTmp);
245
246 m_serial.Write("AT+CSCA?\r\n", 10); // send SMSC query
247 m_serial.Read(szTmp, 128); // read OK
248 DbgPrintf(4, _T("SMS send: AT+CSCA? sent, got {%hs}"), szTmp);
249 if (strlen(szTmp) > 10 && !strncmp(szTmp, "\r\n+CSCA: ", 9))
250 {
251 char szTmp2[128];
252 snprintf(szTmp2, 128, "AT+CSCA=%s\r\n", szTmp + 9);
253 szTmp2[127] = '\0';
254 m_serial.Write(szTmp2, strlen(szTmp2)); // set SMSC
255 m_serial.Read(szTmp, 128); // read OK
256 DbgPrintf(4, _T("SMS send: %hs sent, got {%hs}"), szTmp2, szTmp);
257 }
258
259 char pduBuffer[bufferSize];
260 SMSCreatePDUString(phoneNumber, text, pduBuffer, bufferSize);
261
262 snprintf(szTmp, sizeof(szTmp), "AT+CMGS=%d\r\n", strlen(pduBuffer)/2-1);
263 m_serial.Write(szTmp, (int)strlen(szTmp));
264 DbgPrintf(4, _T("SMS send: %hs sent"), szTmp);
265 snprintf(szTmp, sizeof(szTmp), "%s%c\r\n", pduBuffer, 0x1A);
266 DbgPrintf(4, _T("SMS about to send: %hs sent"), szTmp);
267 m_serial.Write(szTmp, (int)strlen(szTmp)); // send text, end with ^Z
268 m_serial.Read(szTmp, 128); // read +CMGS:ref_num
269 DbgPrintf(4, _T("SMS send: AT+CMGS + message body sent, got {%hs}"), szTmp);
270 }
271
272 return true;
273 }
274
275 extern "C" void EXPORT SMSDriverUnload()
276 {
277 m_serial.Close();
278 }
279
280
281 //
282 // DLL Entry point
283 //
284
285 #ifdef _WIN32
286
287 BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
288 {
289 if (dwReason == DLL_PROCESS_ATTACH)
290 DisableThreadLibraryCalls(hInstance);
291 return TRUE;
292 }
293
294 #endif