changes in SMS drivers and module API (added pointer to server config object in init...
[public/netxms.git] / src / server / smsdrv / text2reach / main.cpp
1 /*
2 ** NetXMS - Network Management System
3 ** SMS driver for Text2Reach.com service
4 ** Copyright (C) 2014-2016 Raden Solutions
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 <nms_common.h>
25 #include <nxsrvapi.h>
26 #include <nms_util.h>
27 #include <curl/curl.h>
28
29 #ifdef _WIN32
30 #define EXPORT __declspec(dllexport)
31 #else
32 #define EXPORT
33 #endif
34
35 #ifndef CURL_MAX_HTTP_HEADER
36 // workaround for older cURL versions
37 #define CURL_MAX_HTTP_HEADER CURL_MAX_WRITE_SIZE
38 #endif
39
40 /**
41 * Request data for cURL call
42 */
43 struct RequestData
44 {
45 size_t size;
46 size_t allocated;
47 char *data;
48 };
49
50 /**
51 * Configuration
52 */
53 static char s_apikey[128] = "apikey";
54 static char s_from[128] = "from";
55
56 /**
57 * Init driver
58 */
59 extern "C" bool EXPORT SMSDriverInit(const TCHAR *initArgs, Config *config)
60 {
61 if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK)
62 {
63 DbgPrintf(1, _T("Text2Reach: cURL initialization failed"));
64 return false;
65 }
66
67 DbgPrintf(1, _T("Text2Reach: driver loaded"));
68 DbgPrintf(3, _T("cURL version: %hs"), curl_version());
69 #if defined(_WIN32) || HAVE_DECL_CURL_VERSION_INFO
70 curl_version_info_data *version = curl_version_info(CURLVERSION_NOW);
71 char protocols[1024] = {0};
72 const char * const *p = version->protocols;
73 while (*p != NULL)
74 {
75 strncat(protocols, *p, strlen(protocols) - 1);
76 strncat(protocols, " ", strlen(protocols) - 1);
77 p++;
78 }
79 DbgPrintf(3, _T("cURL supported protocols: %hs"), protocols);
80 #endif
81
82 #ifdef UNICODE
83 WCHAR buffer[128];
84
85 ExtractNamedOptionValue(initArgs, _T("apikey"), buffer, 128);
86 WideCharToMultiByte(CP_ACP, WC_DEFAULTCHAR | WC_COMPOSITECHECK, buffer, -1, s_apikey, 128, NULL, NULL);
87
88 ExtractNamedOptionValue(initArgs, _T("from"), buffer, 128);
89 WideCharToMultiByte(CP_ACP, WC_DEFAULTCHAR | WC_COMPOSITECHECK, buffer, -1, s_from, 128, NULL, NULL);
90 #else
91 ExtractNamedOptionValue(initArgs, _T("apikey"), s_apikey, 128);
92 ExtractNamedOptionValue(initArgs, _T("from"), s_from, 128);
93 #endif
94
95 return true;
96 }
97
98 /**
99 * Callback for processing data received from cURL
100 */
101 static size_t OnCurlDataReceived(char *ptr, size_t size, size_t nmemb, void *userdata)
102 {
103 RequestData *data = (RequestData *)userdata;
104 if ((data->allocated - data->size) < (size * nmemb))
105 {
106 char *newData = (char *)realloc(data->data, data->allocated + CURL_MAX_HTTP_HEADER);
107 if (newData == NULL)
108 {
109 return 0;
110 }
111 data->data = newData;
112 data->allocated += CURL_MAX_HTTP_HEADER;
113 }
114
115 memcpy(data->data + data->size, ptr, size * nmemb);
116 data->size += size * nmemb;
117
118 return size * nmemb;
119 }
120
121 /**
122 * Send SMS
123 */
124 extern "C" bool EXPORT SMSDriverSend(const TCHAR *phoneNumber, const TCHAR *text)
125 {
126 bool success = false;
127
128 DbgPrintf(4, _T("Text2Reach: phone=\"%s\", text=\"%s\""), phoneNumber, text);
129
130 char errorBuffer[CURL_ERROR_SIZE];
131 CURL *curl = curl_easy_init();
132 if (curl != NULL)
133 {
134 curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, errorBuffer);
135 curl_easy_setopt(curl, CURLOPT_HEADER, (long)0); // do not include header in data
136 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &OnCurlDataReceived);
137 curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, (long)0);
138
139 RequestData *data = (RequestData *)malloc(sizeof(RequestData));
140 memset(data, 0, sizeof(RequestData));
141 curl_easy_setopt(curl, CURLOPT_WRITEDATA, data);
142
143 #ifdef UNICODE
144 char *mbphone = MBStringFromWideString(phoneNumber);
145 char *mbmsg = MBStringFromWideString(text);
146 char *phone = curl_easy_escape(curl, mbphone, 0);
147 char *msg = curl_easy_escape(curl, mbmsg, 0);
148 free(mbphone);
149 free(mbmsg);
150 #else
151 char *phone = curl_easy_escape(curl, phoneNumber, 0);
152 char *msg = curl_easy_escape(curl, text, 0);
153 #endif
154
155 char url[4096];
156 snprintf(url, 4096, "http://www.text2reach.com/api/1.1/sms/bulk/?api_key=%s&phone=%s&from=%s&message=%s", s_apikey, phone, s_from, msg);
157 DbgPrintf(4, _T("Text2Reach: URL set to \"%hs\""), url);
158
159 curl_free(phone);
160 curl_free(msg);
161
162 if (curl_easy_setopt(curl, CURLOPT_URL, url) == CURLE_OK)
163 {
164 if (curl_easy_perform(curl) == CURLE_OK)
165 {
166 long response = 500;
167 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
168 if (response == 200)
169 {
170 DbgPrintf(4, _T("Text2Reach: SMS successfully sent"));
171 success = true;
172 }
173 else
174 {
175 DbgPrintf(4, _T("Text2Reach: request cannot be fulfilled, HTTP response code %03d"), response);
176 }
177 }
178 else
179 {
180 DbgPrintf(4, _T("Text2Reach: call to curl_easy_perform() failed"));
181 }
182 }
183 else
184 {
185 DbgPrintf(4, _T("Text2Reach: call to curl_easy_setopt(CURLOPT_URL) failed: %s"), errorBuffer);
186 }
187 safe_free(data->data);
188 free(data);
189 curl_easy_cleanup(curl);
190 }
191 else
192 {
193 DbgPrintf(4, _T("Text2Reach: call to curl_easy_init() failed"));
194 }
195
196 return success;
197 }
198
199 /**
200 * Unload driver
201 */
202 extern "C" void EXPORT SMSDriverUnload()
203 {
204 }
205
206 #ifdef _WIN32
207
208 /**
209 * DLL Entry point
210 */
211 BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
212 {
213 if (dwReason == DLL_PROCESS_ATTACH)
214 DisableThreadLibraryCalls(hInstance);
215 return TRUE;
216 }
217
218 #endif