/* BILLING.SMSTRAF.RU cLib smsc API v. 0.0.2 (03.07.2019) */ #include #include #include #include #ifndef SMSC_API_H #define SMSC_API_H #define UNICODE // Константы с параметрами отправки static char* const SMSC_LOGIN = "login";// логин клиента static char* const SMSC_PASSWORD = "password";// пароль static char const SMSC_HTTPS = 1;// использовать протокол HTTPS static char SMSC_POST = 0;// использовать метод POST static char* const SMSC_CHARSET = #if defined _UNICODE || defined UNICODE "utf-8"; #else "windows-1251"; #endif // кодировка сообщения (utf-8 или koi8-r), по умолчанию используется windows-1251 static char const SMSC_DEBUG = 1; // флаг отладки // Константы для отправки SMS по SMTP static char* const SMTP_FROM = "api@billing.smstraf.ru"; // e-mail адрес отправителя static char* const SMTP_SERVER = "send.billing.smstraf.ru"; // адрес smtp сервера static char* const SMTP_LOGIN = ""; // логин для smtp сервера static char* const SMTP_PASSWORD = ""; // пароль для smtp сервера typedef char* string_t; // Функция отправки SMS // // обязательные параметры: // // phones - список телефонов через запятую или точку с запятой // message - отправляемое сообщение // // необязательные параметры: // // translit - переводить или нет в транслит (1,2 или 0) // 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&tz=2") // files - массив путей к файлам для отправки mms или e-mail сообщений // // возвращает , <количество sms>, <стоимость>, <баланс> в случае успешной отправки // либо , -<код ошибки> в случае ошибки string_t send_sms (string_t phones, string_t message, int translit, string_t time, int id, int format, string_t sender, string_t query, string_t files); // SMTP версия метода отправки SMS void send_sms_mail(string_t phones, string_t mes, int translit, string_t time, int id, int format, string_t sender); // Получение стоимости 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, -<код ошибки> в случае ошибки string_t get_sms_cost(string_t phones, string_t mes, int translit, int format, string_t sender, string_t query); // Проверка статуса отправленного SMS или HLR-запроса // // id - ID cообщения или список ID через запятую // phone - номер телефона или список номеров через запятую // all - вернуть все данные отправленного SMS, включая текст сообщения (0,1 или 2) // // // для одиночного SMS-сообщения: // <статус>, <время изменения>, <код ошибки доставки> // // для HLR-запроса: // <статус>, <время изменения>, <код ошибки sms>, <код IMSI SIM-карты>, <номер сервис-центра>, <код страны регистрации>, <код оператора>, // <название страны регистрации>, <название оператора>, <название роуминговой страны>, <название роумингового оператора> // // при all = 1 дополнительно возвращаются элементы: // <время отправки>, <номер телефона>, <стоимость>, , <название статуса>, <текст сообщения> // // при all = 2 дополнительно возвращаются элементы <страна>, <оператор> и <регион> // // если all = 0, то для каждого сообщения или HLR-запроса дополнительно возвращается и <номер телефона> // // если all = 1 или all = 2, то в ответ добавляется // // либо 0, -<код ошибки> в случае ошибки string_t get_status(string_t id, string_t phone, int all); // Получение баланса // // без параметров // // возвращает баланс в виде строки или пустую строку в случае ошибки string_t get_balance(void); void _print_debug(string_t str); string_t _urlencode(string_t str); string_t _urldecode(string_t str); string_t _smsc_send_cmd(string_t cmd, string_t arg, string_t files); #endif /* SMSC_API_H */ string_t send_sms (string_t phones, string_t message, int translit, string_t time, int id, int format, string_t sender, string_t query, string_t files) { string_t res=NULL, arg=NULL; char formats[][11] = {"&flash=1", "&push=1", "&hlr=1", "&bin=1", "&bin=2", "&ping=1", "&mms=1", "&mail=1", "&call=1", "&viber=1", "&soc=1"}; asprintf(&arg, "cost=3&phones=%s%s%s&translit=%d&id=%d%s%s%s%s%s%s%s", _urlencode(phones), message ? "&mes=" : "", message ? _urlencode(message) : "", translit, id, format > 0 ? formats[format - 1] : "", sender ? "&sender=" : "", sender ? _urlencode(sender) : "", time ? "&time=" : "", time ? _urlencode(time) : "", query ? "&" : "", query ? query : ""); if (SMSC_DEBUG) printf("%s\n",arg); res = _smsc_send_cmd("send", arg, files); free(arg); return res; } void send_sms_mail(string_t phones, string_t mes, int translit, string_t time, int id, int format, string_t sender) { CURL *curl; CURLcode res = CURLE_OK; struct curl_slist *recipients = NULL; curl = curl_easy_init(); string_t mail_body; asprintf(&mail_body,"%s:%s:%d:%s:%d,%d,%s:%s:%s", SMSC_LOGIN, SMSC_PASSWORD, id, time, translit, format, sender, phones, mes); if (SMSC_DEBUG) printf("%s\n",mail_body); if (curl) { curl_easy_setopt(curl, CURLOPT_URL, SMTP_SERVER); recipients = curl_slist_append(recipients, SMTP_FROM); curl_easy_setopt(curl, CURLOPT_MAIL_RCPT, recipients); res = curl_easy_perform(curl); if (res != CURLE_OK) fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); curl_slist_free_all(recipients); curl_easy_cleanup(curl); } } string_t get_sms_cost(string_t phones, string_t mes, int translit, int format, string_t sender, string_t query) { string_t res, arg; char formats[][11] = {"&flash=1", "&push=1", "&hlr=1", "&bin=1", "&bin=2", "&ping=1", "&mms=1", "&mail=1", "&call=1", "&viber=1", "&soc=1"}; asprintf(&arg, "cost=1&phones=%s&mes=%s&translit=%d%s%s%s%s%s", _urlencode(phones), _urlencode(mes), translit, format>0 ? formats[format-1] : "", sender ? "&sender=" : "", sender ? _urlencode(sender) : "", query ? "&query=" : "", query ? _urlencode(query) : ""); if (SMSC_DEBUG) printf("%s\n",arg); res = _smsc_send_cmd("send", arg, NULL); free(arg); return res; } string_t get_balance(void) { return _smsc_send_cmd("balance", "", NULL); // (balance) или (0, -error) } string_t get_status(string_t id, string_t phone, int all) { string_t arg; asprintf(&arg, "phone=%s&id=%s&all=%d", _urlencode(phone),_urlencode(id), all); return _smsc_send_cmd("status", arg, NULL); } //============================================================================== struct MemoryStruct { char *memory; size_t size; }; static size_t WriteMemoryCallback(void *contents, size_t size, size_t nmemb, void *userp) { size_t realsize = size * nmemb; struct MemoryStruct *mem = (struct MemoryStruct *) userp; mem->memory = realloc(mem->memory, mem->size + realsize + 1); // printf("%d", mem->memory); if (mem->memory == NULL) { /* out of memory! */ printf("not enough memory (realloc returned NULL)\n"); return 0; } memcpy(&(mem->memory[mem->size]), contents, realsize); mem->size += realsize; mem->memory[mem->size] = 0; return realsize; } //============================================================================== string_t _smsc_send_cmd(string_t cmd, string_t arg, string_t files) { CURL *curl; CURLcode res; struct curl_slist *list = NULL; struct curl_httppost* cpost = NULL; struct curl_httppost* clast = NULL; string_t _arg, url, istr, dstr; char post, i=0; struct MemoryStruct chunk; chunk.memory = malloc(1); // will be grown as needed by the realloc above chunk.memory[0] = 0; chunk.size = 0; // no data at this point curl_global_init(CURL_GLOBAL_ALL); curl = curl_easy_init(); if (curl) { curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback); curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *) &chunk); asprintf(&_arg, "login=%s&psw=%s&fmt=1&charset=%s&%s", _urlencode(SMSC_LOGIN), _urlencode(SMSC_PASSWORD), SMSC_CHARSET, arg); post = SMSC_POST || files || (strlen(_arg) > 2000); do { asprintf(&url, "billing.smstraf.ru/sys/%s.php", cmd); if (i++) asprintf(&url, "%s://www%d.%s", SMSC_HTTPS ? "https" : "http", i, url); else asprintf(&url, "%s://%s", SMSC_HTTPS ? "https" : "http", url); if (post) { // разбираем строку параметров istr = strtok(_arg,"=&"); while (istr != NULL) { asprintf(&dstr,"%s", istr); istr = strtok (NULL, "=&"); // printf("%s=%s\n", dstr, istr); curl_formadd(&cpost, &clast, CURLFORM_COPYNAME, dstr, CURLFORM_COPYCONTENTS, _urldecode(istr), CURLFORM_END); istr = strtok (NULL, "=&"); } if (files) { res = curl_formadd(&cpost, &clast, CURLFORM_COPYNAME, "pictures", CURLFORM_FILE, files, CURLFORM_END); if (res != CURLE_OK) fprintf(stderr, "curl_easy_formadd() formfile failed: %s\n", curl_easy_strerror(res)); } curl_easy_setopt(curl, CURLOPT_HTTPPOST, cpost); } else asprintf(&url, "%s?%s",url, _arg); if (SMSC_DEBUG) printf("%s\n%s\n", url, _arg); curl_easy_setopt(curl, CURLOPT_URL, url); res = curl_easy_perform(curl); if (res != CURLE_OK) fprintf(stderr, "curl_easy_perform() failed: %s\n", curl_easy_strerror(res)); else if (SMSC_DEBUG) printf("%lu bytes retrieved\n%s\n", (long)chunk.size, chunk.memory); } while ((i < 5) && (res != CURLE_OK)); curl_easy_cleanup(curl); free(_arg); free(url); free(dstr); } return(chunk.memory); } // кодирование параметра в http-запросе string_t _urlencode(string_t str) { string_t output; CURL *curl; if (str) { curl = curl_easy_init(); if (curl) { string_t output = curl_easy_escape(curl, str, 0); curl_easy_cleanup(curl); return (output); } return(NULL); } return(NULL); } // декодирование параметра в http-запросе string_t _urldecode(string_t str) { string_t output; CURL *curl; if (str) { curl = curl_easy_init(); if (curl) { string_t output = curl_easy_unescape(curl, str, 0, NULL); curl_easy_cleanup(curl); return (output); } return(NULL); } return(NULL); } // вывод отладочной информации void _print_debug(string_t str) { printf("%s\n", str); }