20dc6e834e91d50984a4e4344f2f83dd5cd4e521
[public/netxms.git] / src / smsdrv / smseagle / main.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** SMS driver for SMSEagle Hardware SMS Gateway
4 **
5 ** SMSEagle API documentation - https://www.smseagle.eu/api/
6 **
7 ** Copyright (C) 2014-2016 Raden Solutions
8 ** Copyright (C) 2016 TEMPEST a.s.
9 **
10 ** This program is free software; you can redistribute it and/or modify
11 ** it under the terms of the GNU Lesser General Public License as published by
12 ** the Free Software Foundation; either version 3 of the License, or
13 ** (at your option) any later version.
14 **
15 ** This program is distributed in the hope that it will be useful,
16 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ** GNU General Public License for more details.
19 **
20 ** You should have received a copy of the GNU Lesser General Public License
21 ** along with this program; if not, write to the Free Software
22 ** Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
23 **
24 ** File: main.cpp
25 **
26 **/
27
28 #include <nms_common.h>
29 #include <nms_util.h>
30 #include <nxconfig.h>
31 #include <curl/curl.h>
32
33 #ifdef _WIN32
34 #define EXPORT __declspec(dllexport)
35 #else
36 #define EXPORT
37 #endif
38
39 #ifndef CURL_MAX_HTTP_HEADER
40 // workaround for older cURL versions
41 #define CURL_MAX_HTTP_HEADER CURL_MAX_WRITE_SIZE
42 #endif
43
44 /**
45 * Request data for cURL call
46 */
47 struct RequestData
48 {
49 size_t size;
50 size_t allocated;
51 char *data;
52 };
53
54 /**
55 * Configuration
56 */
57 static char s_hostname[128] = "127.0.0.1";
58 static int s_port = 80;
59 static char s_login[128] = "user";
60 static char s_password[128] = "password";
61
62 /**
63 * Init driver
64 */
65 extern "C" bool EXPORT SMSDriverInit(const TCHAR *initArgs, Config *config)
66 {
67 if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK)
68 {
69 nxlog_debug(1, _T("SMSEagle: cURL initialization failed"));
70 return false;
71 }
72
73 nxlog_debug(1, _T("SMSEagle: driver loaded"));
74 nxlog_debug(3, _T("cURL version: %hs"), curl_version());
75 #if defined(_WIN32) || HAVE_DECL_CURL_VERSION_INFO
76 curl_version_info_data *version = curl_version_info(CURLVERSION_NOW);
77 char protocols[1024] = {0};
78 const char * const *p = version->protocols;
79 while (*p != NULL)
80 {
81 strncat(protocols, *p, strlen(protocols) - 1);
82 strncat(protocols, " ", strlen(protocols) - 1);
83 p++;
84 }
85 nxlog_debug(3, _T("cURL supported protocols: %hs"), protocols);
86 #endif
87
88 #ifdef UNICODE
89 char initArgsA[1024];
90 WideCharToMultiByte(CP_ACP, WC_DEFAULTCHAR | WC_COMPOSITECHECK, initArgs, -1, initArgsA, 1024, NULL, NULL);
91 #define realInitArgs initArgsA
92 #else
93 #define realInitArgs initArgs
94 #endif
95
96 ExtractNamedOptionValueA(realInitArgs, "host", s_hostname, 128);
97 s_port = (int)ExtractNamedOptionValueAsIntA(realInitArgs, "port", s_port);
98 ExtractNamedOptionValueA(realInitArgs, "login", s_login, 128);
99 ExtractNamedOptionValueA(realInitArgs, "password", s_password, 128);
100
101 return true;
102 }
103
104 /**
105 * Callback for processing data received from cURL
106 */
107 static size_t OnCurlDataReceived(char *ptr, size_t size, size_t nmemb, void *userdata)
108 {
109 RequestData *data = (RequestData *)userdata;
110 if ((data->allocated - data->size) < (size * nmemb))
111 {
112 char *newData = (char *)realloc(data->data, data->allocated + CURL_MAX_HTTP_HEADER);
113 if (newData == NULL)
114 {
115 return 0;
116 }
117 data->data = newData;
118 data->allocated += CURL_MAX_HTTP_HEADER;
119 }
120
121 memcpy(data->data + data->size, ptr, size * nmemb);
122 data->size += size * nmemb;
123
124 return size * nmemb;
125 }
126
127 /**
128 * Send SMS
129 */
130 extern "C" bool EXPORT SMSDriverSend(const TCHAR *phoneNumber, const TCHAR *text)
131 {
132 bool success = false;
133
134 nxlog_debug(4, _T("SMSEagle: phone/group=\"%s\", text=\"%s\""), phoneNumber, text);
135
136 CURL *curl = curl_easy_init();
137 if (curl != NULL)
138 {
139 #if HAVE_DECL_CURLOPT_NOSIGNAL
140 curl_easy_setopt(curl, CURLOPT_NOSIGNAL, (long)1);
141 #endif
142
143 curl_easy_setopt(curl, CURLOPT_HEADER, (long)0); // do not include header in data
144 curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);
145 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &OnCurlDataReceived);
146
147 RequestData *data = (RequestData *)malloc(sizeof(RequestData));
148 memset(data, 0, sizeof(RequestData));
149 curl_easy_setopt(curl, CURLOPT_WRITEDATA, data);
150
151 bool intlPrefix = (phoneNumber[0] == _T('+')); // this will be used to decide whether it is number or group name
152 #ifdef UNICODE
153 char *mbphone = MBStringFromWideString(phoneNumber);
154 char *mbmsg = MBStringFromWideString(text);
155 char *phone = curl_easy_escape(curl, mbphone, 0);
156 char *msg = curl_easy_escape(curl, mbmsg, 0);
157 free(mbphone);
158 free(mbmsg);
159 #else
160 char *phone = curl_easy_escape(curl, phoneNumber, 0);
161 char *msg = curl_easy_escape(curl, text, 0);
162 #endif
163
164 char url[4096];
165 snprintf(url, 4096,
166 intlPrefix ? "http://%s:%d/index.php/http_api/send_sms?login=%s&pass=%s&to=%s&message=%s" : "http://%s:%d/index.php/http_api/send_togroup?login=%s&pass=%s&groupname=%s&message=%s",
167 s_hostname, s_port, s_login, s_password, phone, msg);
168 nxlog_debug(4, _T("SMSEagle: URL set to \"%hs\""), url);
169
170 curl_free(phone);
171 curl_free(msg);
172
173 if (curl_easy_setopt(curl, CURLOPT_URL, url) == CURLE_OK)
174 {
175 if (curl_easy_perform(curl) == CURLE_OK)
176 {
177 nxlog_debug(4, _T("SMSEagle: %d bytes received"), data->size);
178 if (data->allocated > 0)
179 data->data[data->size] = 0;
180
181 long response = 500;
182 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
183 nxlog_debug(4, _T("SMSEagle: response code %03d"), (int)response);
184 if (response == 200)
185 {
186 success = true;
187 }
188 }
189 else
190 {
191 nxlog_debug(4, _T("SMSEagle: call to curl_easy_perform() failed"));
192 }
193 }
194 else
195 {
196 nxlog_debug(4, _T("SMSEagle: call to curl_easy_setopt(CURLOPT_URL) failed"));
197 }
198 safe_free(data->data);
199 free(data);
200 curl_easy_cleanup(curl);
201 }
202 else
203 {
204 nxlog_debug(4, _T("SMSEagle: call to curl_easy_init() failed"));
205 }
206
207 return success;
208 }
209
210 /**
211 * Unload driver
212 */
213 extern "C" void EXPORT SMSDriverUnload()
214 {
215 }
216
217 #ifdef _WIN32
218
219 /**
220 * DLL Entry point
221 */
222 BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
223 {
224 if (dwReason == DLL_PROCESS_ATTACH)
225 DisableThreadLibraryCalls(hInstance);
226 return TRUE;
227 }
228
229 #endif