kannel SMS driver correctly handles phone numbers with + sign
[public/netxms.git] / src / smsdrv / kannel / main.cpp
CommitLineData
e47404b3
VK
1/*
2** NetXMS - Network Management System
3** SMS driver for Kannel gateway
f19168bd 4** Copyright (C) 2014-2016 Raden Solutions
e47404b3
VK
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>
e47404b3 25#include <nms_util.h>
623e2f0e 26#include <nxconfig.h>
e47404b3
VK
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 */
43struct RequestData
44{
45 size_t size;
46 size_t allocated;
47 char *data;
48};
49
50/**
51 * Configuration
52 */
53static char s_hostname[128] = "127.0.0.1";
54static int s_port = 13001;
55static char s_login[128] = "user";
56static char s_password[128] = "password";
57
58/**
59 * Init driver
60 */
f19168bd 61extern "C" bool EXPORT SMSDriverInit(const TCHAR *initArgs, Config *config)
e47404b3
VK
62{
63 if (curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK)
64 {
623e2f0e 65 nxlog_debug(1, _T("Kannel: cURL initialization failed"));
f19168bd 66 return false;
e47404b3
VK
67 }
68
623e2f0e
VK
69 nxlog_debug(1, _T("Kannel: driver loaded"));
70 nxlog_debug(3, _T("cURL version: %hs"), curl_version());
e47404b3
VK
71#if defined(_WIN32) || HAVE_DECL_CURL_VERSION_INFO
72 curl_version_info_data *version = curl_version_info(CURLVERSION_NOW);
73 char protocols[1024] = {0};
74 const char * const *p = version->protocols;
75 while (*p != NULL)
76 {
77 strncat(protocols, *p, strlen(protocols) - 1);
78 strncat(protocols, " ", strlen(protocols) - 1);
79 p++;
80 }
623e2f0e 81 nxlog_debug(3, _T("cURL supported protocols: %hs"), protocols);
e47404b3
VK
82#endif
83
84#ifdef UNICODE
85 char initArgsA[1024];
86 WideCharToMultiByte(CP_ACP, WC_DEFAULTCHAR | WC_COMPOSITECHECK, initArgs, -1, initArgsA, 1024, NULL, NULL);
87#define realInitArgs initArgsA
88#else
89#define realInitArgs initArgs
90#endif
91
92 ExtractNamedOptionValueA(realInitArgs, "host", s_hostname, 128);
93 s_port = (int)ExtractNamedOptionValueAsIntA(realInitArgs, "port", s_port);
94 ExtractNamedOptionValueA(realInitArgs, "login", s_login, 128);
95 ExtractNamedOptionValueA(realInitArgs, "password", s_password, 128);
96
f19168bd 97 return true;
e47404b3
VK
98}
99
100/**
101 * Callback for processing data received from cURL
102 */
103static size_t OnCurlDataReceived(char *ptr, size_t size, size_t nmemb, void *userdata)
104{
105 RequestData *data = (RequestData *)userdata;
106 if ((data->allocated - data->size) < (size * nmemb))
107 {
108 char *newData = (char *)realloc(data->data, data->allocated + CURL_MAX_HTTP_HEADER);
109 if (newData == NULL)
110 {
111 return 0;
112 }
113 data->data = newData;
114 data->allocated += CURL_MAX_HTTP_HEADER;
115 }
116
117 memcpy(data->data + data->size, ptr, size * nmemb);
118 data->size += size * nmemb;
119
120 return size * nmemb;
121}
122
123/**
124 * Send SMS
125 */
f19168bd 126extern "C" bool EXPORT SMSDriverSend(const TCHAR *phoneNumber, const TCHAR *text)
e47404b3 127{
f19168bd 128 bool success = false;
e47404b3 129
623e2f0e 130 nxlog_debug(4, _T("Kannel: phone=\"%s\", text=\"%s\""), phoneNumber, text);
e47404b3
VK
131
132 CURL *curl = curl_easy_init();
133 if (curl != NULL)
134 {
135#if HAVE_DECL_CURLOPT_NOSIGNAL
136 curl_easy_setopt(curl, CURLOPT_NOSIGNAL, (long)1);
137#endif
138
139 curl_easy_setopt(curl, CURLOPT_HEADER, (long)0); // do not include header in data
140 curl_easy_setopt(curl, CURLOPT_TIMEOUT, 10);
141 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &OnCurlDataReceived);
142
143 RequestData *data = (RequestData *)malloc(sizeof(RequestData));
144 memset(data, 0, sizeof(RequestData));
145 curl_easy_setopt(curl, CURLOPT_WRITEDATA, data);
146
b9217de5 147 bool intlPrefix = (phoneNumber[0] == _T('+'));
e47404b3 148#ifdef UNICODE
b9217de5 149 char *mbphone = MBStringFromWideString(intlPrefix ? &phoneNumber[1] : phoneNumber);
e47404b3
VK
150 char *mbmsg = MBStringFromWideString(text);
151 char *phone = curl_easy_escape(curl, mbphone, 0);
152 char *msg = curl_easy_escape(curl, mbmsg, 0);
153 free(mbphone);
154 free(mbmsg);
155#else
b9217de5 156 char *phone = curl_easy_escape(curl, intlPrefix ? &phoneNumber[1] : phoneNumber, 0);
e47404b3
VK
157 char *msg = curl_easy_escape(curl, text, 0);
158#endif
159
160 char url[4096];
b9217de5
VK
161 snprintf(url, 4096, "http://%s:%d/cgi-bin/sendsms?username=%s&password=%s&to=%s%s&text=%s",
162 s_hostname, s_port, s_login, s_password, intlPrefix ? "00" : "", phone, msg);
623e2f0e 163 nxlog_debug(4, _T("Kannel: URL set to \"%hs\""), url);
e47404b3
VK
164
165 curl_free(phone);
166 curl_free(msg);
167
168 if (curl_easy_setopt(curl, CURLOPT_URL, url) == CURLE_OK)
169 {
170 if (curl_easy_perform(curl) == CURLE_OK)
171 {
623e2f0e 172 nxlog_debug(4, _T("Kannel: %d bytes received"), data->size);
e47404b3
VK
173 if (data->allocated > 0)
174 data->data[data->size] = 0;
175
176 long response = 500;
177 curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &response);
623e2f0e 178 nxlog_debug(4, _T("Kannel: response code %03d"), (int)response);
e47404b3
VK
179 if (response == 202)
180 {
f19168bd 181 success = true;
e47404b3
VK
182 }
183 }
184 else
185 {
623e2f0e 186 nxlog_debug(4, _T("Kannel: call to curl_easy_perform() failed"));
e47404b3
VK
187 }
188 }
189 else
190 {
623e2f0e 191 nxlog_debug(4, _T("Kannel: call to curl_easy_setopt(CURLOPT_URL) failed"));
e47404b3
VK
192 }
193 safe_free(data->data);
194 free(data);
195 curl_easy_cleanup(curl);
196 }
197 else
198 {
623e2f0e 199 nxlog_debug(4, _T("Kannel: call to curl_easy_init() failed"));
e47404b3
VK
200 }
201
202 return success;
203}
204
205/**
206 * Unload driver
207 */
208extern "C" void EXPORT SMSDriverUnload()
209{
210}
211
212#ifdef _WIN32
213
214/**
215 * DLL Entry point
216 */
217BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
218{
219 if (dwReason == DLL_PROCESS_ATTACH)
220 DisableThreadLibraryCalls(hInstance);
221 return TRUE;
222}
223
224#endif