// SMSC.RU API для Microsoft Visual C++ (smsc.ru) версия 1.3 (03.07.2019) #define _AFXDLL #include #include #include #include using namespace std; // Константы с параметрами отправки const CString SMSC_LOGIN = "login"; // логин клиента const CString SMSC_PASSWORD = "password"; // пароль const bool SMSC_HTTPS = false; // использовать протокол HTTPS const bool SMSC_POST = false; // использовать метод POST const CString SMSC_CHARSET = #if defined _UNICODE || defined UNICODE "utf-8"; #else "windows-1251"; #endif // кодировка сообщения (utf-8 или koi8-r), по умолчанию используется windows-1251 const bool SMSC_DEBUG = false; // флаг отладки class SMSC { public: // Общедоступные методы класса SMSС // // Метод отправки SMS // // обязательные параметры: // // phones - список телефонов через запятую или точку с запятой // message - отправляемое сообщение // // необязательные параметры: // // translit - переводить или нет в транслит // time - необходимое время доставки в виде строки (DDMMYYhhmm, h1-h2, 0ts, +m) // id - идентификатор сообщения. Представляет собой 32-битное число в диапазоне от 1 до 2147483647. // format - формат сообщения (0 - обычное sms, 1 - flash-sms, 2 - wap-push, 3 - hlr, 4 - bin, 5 - bin-hex, 6 - ping-sms, 7 - mms, 8 - mail, 9 - call, 10 - viber, 11 - soc) // sender - имя отправителя (Sender ID). // query - строка дополнительных параметров, добавляемая в URL-запрос ("valid=01:00&maxsms=3") // // возвращает массив (, <количество sms>, <стоимость>, <баланс>) в случае успешной отправки // либо (, -<код ошибки>) в случае ошибки vector send_sms(CString phones, CString message, int translit = 0, CString time = "", int id = 0, int format = 0, CString sender = "", CString query = "") { CString tt, ir; CString formats[11] = {"flash=1", "push=1", "hlr=1", "bin=1", "bin=2", "ping=1", "mms=1", "mail=1", "call=1", "viber=1", "soc=1"}; ir.Format((CString)"%i", id); tt.Format((CString)"%i", translit); vector m = _smsc_send_cmd("send", "cost=3&phones=" + (CString)_urlencode(phones) + "&mes=" + (CString)_urlencode(message) + "&id=" + ir + "&translit=" + tt + (format > 0 ? "&" + formats[format - 1] : "") + (sender != "" ? "&sender=" + (CString)_urlencode(sender) : "") + (time != "" ? "&time=" + (CString)_urlencode(time) : "") + (query != "" ? "&" + query : "")); // (id, cnt, cost, balance) или (id, -error) if (SMSC_DEBUG) if (m[1] > "0") _print_debug("Сообщение отправлено успешно. ID: " + m[0] + ", всего SMS: " + m[1] + ", стоимость: " + m[2] + ", баланс: " + m[3]); else _print_debug("Ошибка №" + m[1].Mid(1, 1) + ", ID: " + m[0]); return m; }; // Метод получения стоимости SMS // // обязательные параметры: // // phones - список телефонов через запятую или точку с запятой // message - отправляемое сообщение // // необязательные параметры: // // translit - переводить или нет в транслит // format - формат сообщения (0 - обычное sms, 1 - flash-sms, 2 - wap-push, 3 - hlr, 4 - bin, 5 - bin-hex, 6 - ping-sms, 7 - mms, 8 - mail, 9 - call, 10 - viber, 11 - soc) // sender - имя отправителя (Sender ID) // query - строка дополнительных параметров, добавляемая в URL-запрос ("list=79999999999:Ваш пароль: 123\n78888888888:Ваш пароль: 456") // // возвращает массив (<стоимость>, <количество sms>) либо (0, -<код ошибки>) в случае ошибки vector get_sms_cost(CString phones, CString message, int translit = 0, int format = 0, CString sender = "", CString query = "") { CString tt; CString formats[11] = {"flash=1", "push=1", "hlr=1", "bin=1", "bin=2", "ping=1", "mms=1", "mail=1", "call=1", "viber=1", "soc=1"}; tt.Format((CString)"%i", translit); vector m = _smsc_send_cmd("send", "cost=1&phones=" + (CString)_urlencode(phones) + "&mes=" + (CString)_urlencode(message) + "&translit=" + tt + (format > 0 ? "&" + formats[format-1] : "") + (sender != "" ? "&sender=" + (CString)_urlencode(sender) : "") + (query != "" ? "&" + query : "")); // (cost, cnt) или (0, -error) if (SMSC_DEBUG) if (m[1] > "0") _print_debug("Стоимость рассылки: " + m[0] + ". Всего SMS: " + m[1]); else _print_debug("Ошибка №" + m[1].Mid(1, 1)); return m; }; // Метод проверки статуса отправленного SMS или HLR-запроса // // id - ID cообщения // phone - номер телефона // // возвращает массив: // для отправленного SMS (<статус>, <время изменения>, <код ошибки sms>) // для HLR-запроса (<статус>, <время изменения>, <код ошибки sms>, <код IMSI SIM-карты>, <номер сервис-центра>, <код страны регистрации>, // <код оператора абонента>, <название страны регистрации>, <название оператора абонента>, <название роуминговой страны>, // <название роумингового оператора>) // // При all = 1 дополнительно возвращаются элементы в конце массива: // (<время отправки>, <номер телефона>, <стоимость>, , <название статуса>, <текст сообщения>) // // либо (0, -<код ошибки>) в случае ошибки vector get_status(int id, CString phone, int all = 0) { CString ans, ir, tr; int i; ir.Format((CString)"%i", id); tr.Format((CString)"%i", all); vector m = _smsc_send_cmd("status", "phone=" + (CString)_urlencode(phone) + "&id=" + ir + (all > 0 ? "&all=" + tr : "")); // (status, time, err) или (0, -error) if (SMSC_DEBUG) if ((m[1] != "") && (m[1] >= "0")) { time_t tm = _ttoi(m[1]); struct tm ltm; TCHAR st[100] = {0}; localtime_s(<m, &tm); _stprintf_s(st, 100, (CString)"%2d.%2d.%d %2d:%2d:%2d", ltm.tm_mday, (ltm.tm_mon) + 1, (ltm.tm_year) + 1900, ltm.tm_hour, ltm.tm_min, ltm.tm_sec); _print_debug( "Статус SMS = " + m[0] + ", время изменения статуса - " + st); } else _print_debug("Ошибка №" + m[1].Mid(1, 1)); if (all == 1 && m.size() > 9 && (m.size() < 14 || m[14] != "HLR")) { ans = m[0]; for (i = 1; i < (int)m.size(); i++) ans += "," + m[i]; m.clear(); int cp = 0; for (i = 0; i < 8; i++) m.push_back(ans.Tokenize((CString)",", cp)); m.push_back(ans.Mid(cp)); } return m; }; // Метод получения баланса // // без параметров // // возвращает баланс в виде строки или пустую строку в случае ошибки CString get_balance(void) { vector m = _smsc_send_cmd("balance", ""); // (balance) или (0, -error) if (SMSC_DEBUG) if (m.size() == 1) _print_debug("Сумма на счете: " + m[0]); else _print_debug("Ошибка №" + m[1].Mid(1, 1)); return m.size() == 1 ? m[0] : ""; }; private: // Приватные методы класса SMSС // // Метод вызова запроса. Формирует URL и делает 3 попытки чтения vector _smsc_send_cmd(CString cmd, CString arg) { vector m; int cnt = 0; CString url, _url; arg = "login=" + (CString)_urlencode(SMSC_LOGIN) + "&psw=" + (CString)_urlencode(SMSC_PASSWORD) + "&fmt=1&charset=" + SMSC_CHARSET + "&" + arg; url = _url = (SMSC_HTTPS ? "https" : "http") + (CString)"://smsc.ru/sys/" + cmd + ".php"; CString sr, ot, res, strcnt; INTERNET_PORT pt; DWORD st; char sz[1024] = {0}; CInternetSession ses((CString)"Visual C++", PRE_CONFIG_INTERNET_ACCESS); CHttpConnection *ds; AfxParseURL(url + '?' + arg, st, sr, ot, pt); ds = ses.GetHttpConnection(sr, NULL, pt); do { if (cnt++) { strcnt.Format((CString)"%i", cnt); url = _url; url.Replace((CString)"smsc.ru/", (CString)"www" + strcnt + ".smsc.ru/"); AfxParseURL(url + '?' + arg, st, sr, ot, pt); ds = ses.GetHttpConnection(sr, NULL, pt); } CHttpFile *pc; try { if (SMSC_POST || arg.GetLength() > 2000) { pc = ds->OpenRequest(0, "/sys/" + cmd + ".php", NULL, 1, NULL, NULL, SMSC_HTTPS ? INTERNET_FLAG_SECURE : INTERNET_FLAG_EXISTING_CONNECT); pc->SendRequest((CString)"Content-Type: application/x-www-form-urlencoded", (LPVOID)(LPCSTR)(CStringA)arg, arg.GetLength()); } else { pc = ds->OpenRequest(1, ot, NULL, 1, NULL, NULL, SMSC_HTTPS ? INTERNET_FLAG_SECURE : INTERNET_FLAG_EXISTING_CONNECT); pc->SendRequest(); } pc->Read(sz, 1024); } catch (CInternetException* e) { } res = sz; pc->Close(); } while ((res == "") && (cnt < 5)); if (res == "") { if (SMSC_DEBUG) _print_debug("Ошибка чтения адреса: " + url + "?" + arg); res = ","; // фиктивный ответ } ds->Close(); ses.Close(); return _explode(res); }; // кодирование параметра в http-запросе CStringA _urlencode(CString s_in) { #if defined _UNICODE || defined UNICODE const WCHAR *pt_utf16 = s_in; const size_t cch_utf16m = INT_MAX - 1; size_t cch_utf16; ::StringCchLengthW(pt_utf16, cch_utf16m, &cch_utf16); ++cch_utf16; int cb_utf8 = ::WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, pt_utf16, static_cast(cch_utf16), NULL, 0, NULL, NULL); CStringA s_utf8; CHAR *pt_utf8 = s_utf8.GetBuffer(cb_utf8); ::WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, pt_utf16, static_cast(cch_utf16), pt_utf8, cb_utf8, NULL, NULL); s_utf8.ReleaseBuffer(); return _encode(s_utf8); #else return _encode(s_in); #endif }; CStringA _encode(CStringA s_in) { CStringA s_out; for (int i = 0; i < s_in.GetLength(); i++) { CHAR ch = s_in[i]; if ((ch >= '0' && ch <= '9') || (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z')) s_out.AppendChar(ch); else { BYTE ccv = static_cast(ch); CHAR eb[4]; sprintf_s(eb, sizeof(eb), "%%%02X", ccv); s_out.Append(eb); } } return s_out; }; // вывод отладочной информации void _print_debug(CString str) { MessageBox(NULL, str, NULL, MB_OK); }; // разделение строки, возвращаемой сервером, на массив строк vector _explode(CString str) { int cp = 0; vector m; do { m.push_back(str.Tokenize((CString)",", cp)); } while (m.back() != ""); m.pop_back(); return m; }; }; // Examples: // SMSC *sms = new SMSC(); // СString balance; // vector ret; // // ret = sms->send_sms("79999999999", "Ваш пароль: 123", 1); // ret = sms->send_sms("79999999999", "http://smsc.ru\nSMSC.RU", 0, "", 0, 0, "", "maxsms=3"); // ret = sms->send_sms("79999999999", "0605040B8423F0DC0601AE02056A0045C60C036D79736974652E72750001036D7973697465000101", 0, "", 0, 5); // ret = sms->send_sms("79999999999", "", 0, "", 0, 3); // ret = sms->get_sms_cost("79999999999", "Вы успешно зарегистрированы!"); // ret = sms->get_status(12345, "79999999999"); // balance = sms->get_balance(); // // delete sms;