#include <winsock2.h>
#include <windows.h>
#include <stdio.h> // sprintf()
#include <string>
#include "\works\h\maelstrom.h" // fnReplace()
#include "client.h"
#include "config.h"
#include "main.h" // fnLog(), fnGetToday()
#include "other\md5.h"
#include "page_sms.h"
#include "page_tuning_private.h"
#include "pages.h"
#include "read_ini.h"
#include "s_date.h"
#include "s_forms.h"
#include "s_services_groups.h"
#include "visit.h"
using namespace std;
using namespace md5;
// ассоциативные массивы
#if defined(__WATCOMC__)
static std::auto_ptr<A_ARRAY> login_days (new A_ARRAY("page_sms.cpp: login_days")); // "имя входа/кол-во дней"
#else
static std::unique_ptr<A_ARRAY> login_days (new A_ARRAY("page_sms.cpp: login_days")); // "имя входа/кол-во дней"
#endif // defined
void fnCheckSms(void)
{
char szToday [11];
int iQty;
int iCycle;
SMS s_sms;
bool bWorkNeed;
fnGetToday(szToday);
iQty = sms->fnGetQty();
// определяем необходимость повышения версии записей
bWorkNeed = false;
for(iCycle = 0; iCycle < iQty; iCycle++)
{
sms->fnPop((char *) &s_sms,iCycle); // неразрушающее чтение
if(s_sms.iVersion != SMS_VERSION)
{
bWorkNeed = true;
break;
}
}
if (bWorkNeed)
{
// здесь производится проверка версии записи и при необходимости
// upgrade (инициализация дополнительных полей)
for(iCycle = 0; iCycle < iQty; iCycle++)
{
sms->fnPop((char *) &s_sms); // разрушающее чтение
if(s_sms.iVersion != SMS_VERSION)
{
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
switch(s_sms.iVersion)
{
case 1:
s_sms.iGate = 0;
case 2:
s_sms.iErrorCode = -1;
case 3:
s_sms.bPaused = true;
}
#pragma GCC diagnostic pop
s_sms.iVersion = SMS_VERSION;
}
// возвращаем запись в кольцо
sms->fnPush((char *) &s_sms,sizeof(SMS));
}
}
// определяем необходимость удаления устаревших записей
bWorkNeed = false;
for(iCycle = 0; iCycle < iQty; iCycle++)
{
sms->fnPop((char *) &s_sms,iCycle); // неразрушающее чтение
if(fnGetDayIndex(s_sms.szDate,szToday) > 28)
{
bWorkNeed = true;
break;
}
}
if (bWorkNeed)
{
// удаление устаревших записей
for(iCycle = 0; iCycle < iQty; iCycle++)
{
sms->fnPop((char *) &s_sms); // разрушающее чтение
// возвращаем запись в кольцо, если не истёк срок её давности
if(fnGetDayIndex(s_sms.szDate,szToday) <= 28)
sms->fnPush((char *) &s_sms,sizeof(SMS));
}
}
}
// *****************************************************************
// * функции поиска федерального номера сотового телефона в строке *
// *****************************************************************
static int fnGetNumsQty(char *szPhone)
{
int iQty = 0;
while (*szPhone)
{
switch (*szPhone++)
{
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
iQty++;
}
}
return iQty;
}
static void fnCopyPhone(char *dst,char *szPhone)
{
*dst = 0;
while (*szPhone)
{
switch (*szPhone++)
{
case '9': strcat(dst,"9"); break;
case '8': strcat(dst,"8"); break;
case '7': strcat(dst,"7"); break;
case '6': strcat(dst,"6"); break;
case '5': strcat(dst,"5"); break;
case '4': strcat(dst,"4"); break;
case '3': strcat(dst,"3"); break;
case '2': strcat(dst,"2"); break;
case '1': strcat(dst,"1"); break;
case '0': strcat(dst,"0");
}
}
}
static bool fnGetPhoneFederal(char *dst,char *szPhone)
{
int iNumsQty = fnGetNumsQty(szPhone);
switch (iNumsQty)
{
case 10: fnCopyPhone(dst +1,szPhone); break;
case 11: fnCopyPhone(dst,szPhone);
}
switch (iNumsQty)
{
case 10:
case 11:
*dst = '7';
if (*(dst +1) != '9') // ошибка: номера сотовых операторов должны начинаться с девятки
return false;
return true;
default: // не федеральный номер
*dst = 0;
return false;
}
}
// копирует в dst найденный в szPhones номер сотового телефона в формате 71234567890
bool fnGetPhone(char *dst,char *szPhones)
{
#if defined(__WATCOMC__)
std::auto_ptr<RING> lexems (new RING("bool fnGetPhone(char *,char *): lexems",INI_MAX_LINE_LEN));
#else
std::unique_ptr<RING> lexems (new RING("bool fnGetPhone(char *,char *): lexems",INI_MAX_LINE_LEN));
#endif // defined
char sz [REG_NAME_LEN +1];
strcpy(sz,szPhones);
fnCharToComma(sz,'.'); // заменяем точки на запятые
// размещаем список телефонов в массив
fnGetLexems(lexems.get(),sz,INI_EXCLUDE_COMMA);
while (lexems->fnGetQty())
{
// проверяем каждый телефонный номер
lexems->fnPop(sz);
if (fnGetPhoneFederal(dst,sz))
return true;
}
return false; // федеральных номеров не найдено
}
// ***************************************************************
// * функции загрузки новых sms-сообщений в очередь для отправки *
// ***************************************************************
static int fnGetNextId(void)
{
int iQty;
int iCycle;
SMS s_sms;
int iNextId = 0;
iQty = sms->fnGetQty();
for (iCycle = 0; iCycle < iQty; iCycle++)
{
sms->fnPop((char *) &s_sms,iCycle);
if (s_sms.iId >= iNextId)
iNextId = s_sms.iId +1;
}
return iNextId;
}
// тест
void fnSendSmsTest(QUERY *query,char *szFederalPhone,char *szText)
{
SMS s_sms;
SYSTEMTIME lt;
// инициализация
memset(&s_sms,0,sizeof (SMS));
s_sms.iVersion = SMS_VERSION;
s_sms.iId = fnGetNextId();
s_sms.iGate = 0;
s_sms.iType = 0; // тестовое SMS-сообщение
if (config.bSmsCreatePausedType0)
s_sms.bPaused = true;
s_sms.iStep = 0;
// время создания записи
GetLocalTime(<);
sprintf(s_sms.szDate,"%02u/%02u/%4u",lt.wDay,lt.wMonth,lt.wYear);
sprintf(s_sms.szTime,"%02u:%02u",lt.wHour,lt.wMinute);
SystemTimeToFileTime(<,&s_sms.ft_create);
strcpy(s_sms.szPrefix,query->szPrefix);
strcpy(s_sms.szPhone,szFederalPhone);
strcpy(s_sms.szText,szText);
// загрузка в очередь отправки
sms->fnPush((char *) &s_sms,sizeof (SMS));
}
// выдача результатов
void fnSendSmsGivingResults(QUERY *query,int iVisitNum)
{
int iVisit;
int iClientNum;
int iClient;
SMS s_sms;
SYSTEMTIME lt;
char szFederalPhone [11 +1];
string s;
char szTmp [20];
iVisit = fnVisitSearchByNum(iVisitNum);
if (iVisit == -1)
return;
iClientNum = visit [iVisit]->fnGetClientNum();
iClient = fnClientSearchByNum(iClientNum);
if (iClient == -1)
return;
// не отправлять SMS, если есть адрес электронной почты клиента
if (config.bSmsNotSendResultsIfEmailExist
&& strstr(client [iClient]->fnGetEmail(),"@"))
return;
if (client [iClient]->fnGetBanOnSMS())
return;
if (! client [iClient]->fnGetConsentToReceiveSMS())
return;
// инициализация
memset(&s_sms,0,sizeof (SMS));
s_sms.iVersion = SMS_VERSION;
s_sms.iId = fnGetNextId();
s_sms.iGate = 0;
s_sms.iType = 1; // SMS-уведомление о готовности результатов
if (config.bSmsCreatePausedType1)
s_sms.bPaused = true;
s_sms.iStep = 0;
// время создания записи
GetLocalTime(<);
sprintf(s_sms.szDate,"%02u/%02u/%4u",lt.wDay,lt.wMonth,lt.wYear);
sprintf(s_sms.szTime,"%02u:%02u",lt.wHour,lt.wMinute);
SystemTimeToFileTime(<,&s_sms.ft_create);
strcpy(s_sms.szPrefix,query->szPrefix);
// сотовый телефон
if (fnGetPhone(szFederalPhone,client [iClient]->fnGetPhoneCell()))
strcpy(s_sms.szPhone,szFederalPhone);
else
return;
// номер и дата оформления документа
s.clear();
// префикс используется и присутствует
if (config.bUseContractPrefix && strlen(visit [iVisit]->fnGetPrefix()))
{
s += visit [iVisit]->fnGetPrefix();
s += "-";
}
sprintf(szTmp,"%i",visit [iVisit]->fnGetContractNum());
s += szTmp;
s += " от ";
s += visit [iVisit]->fnGetContractDate();
// текст сообщения (подставляем номер и дату оформления документа)
fnReplace(s_sms.szText,sizeof (s_sms.szText) -1, // dst_len
config.szSmsGivingResults,"{contract}",s.c_str());
s_sms.iClientNum = visit [iVisit]->fnGetClientNum(); // клиент
s_sms.iContractNum = visit [iVisit]->fnGetContractNum();
strcpy(s_sms.szContractDate,visit [iVisit]->fnGetContractDate());
// загрузка в очередь отправки
sms->fnPush((char *) &s_sms,sizeof (SMS));
}
// поздравление с днём рождения
bool fnSendSmsBirthday(QUERY *query,int iClientNum)
{
int iClient = fnClientSearchByNum(iClientNum);
SMS s_sms;
SYSTEMTIME lt;
char szFederalPhone [11 +1];
if (iClient == -1)
return false;
// инициализация
memset(&s_sms,0,sizeof (SMS));
s_sms.iVersion = SMS_VERSION;
s_sms.iId = fnGetNextId();
s_sms.iGate = 0;
s_sms.iType = 2; // поздравление с днём рождения
if (config.bSmsCreatePausedType2)
s_sms.bPaused = true;
s_sms.iStep = 0;
// время создания записи
GetLocalTime(<);
sprintf(s_sms.szDate,"%02u/%02u/%4u",lt.wDay,lt.wMonth,lt.wYear);
sprintf(s_sms.szTime,"%02u:%02u",lt.wHour,lt.wMinute);
SystemTimeToFileTime(<,&s_sms.ft_create);
strcpy(s_sms.szPrefix,query->szPrefix);
// сотовый телефон
if (fnGetPhone(szFederalPhone,client [iClient]->fnGetPhoneCell()))
strcpy(s_sms.szPhone,szFederalPhone);
else
return false;
// текст сообщения
strcpy(s_sms.szText,config.szSmsBirthday);
s_sms.iClientNum = iClientNum; // клиент
// загрузка в очередь отправки
sms->fnPush((char *) &s_sms,sizeof (SMS));
return true;
}
// информация клиентам
bool fnSendSmsInfo(QUERY *query,int iClientNum,char *szText)
{
int iClient = fnClientSearchByNum(iClientNum);
SMS s_sms;
SYSTEMTIME lt;
char szFederalPhone [11 +1];
if (iClient == -1)
return false;
// инициализация
memset(&s_sms,0,sizeof (SMS));
s_sms.iVersion = SMS_VERSION;
s_sms.iId = fnGetNextId();
s_sms.iGate = 0;
s_sms.iType = 3; // рассылка информации клиентам
if (config.bSmsCreatePausedType3)
s_sms.bPaused = true;
s_sms.iStep = 0;
// время создания записи
GetLocalTime(<);
sprintf(s_sms.szDate,"%02u/%02u/%4u",lt.wDay,lt.wMonth,lt.wYear);
sprintf(s_sms.szTime,"%02u:%02u",lt.wHour,lt.wMinute);
SystemTimeToFileTime(<,&s_sms.ft_create);
strcpy(s_sms.szPrefix,query->szPrefix);
// сотовый телефон
if (fnGetPhone(szFederalPhone,client [iClient]->fnGetPhoneCell()))
strcpy(s_sms.szPhone,szFederalPhone);
else
return false;
// текст сообщения
strcpy(s_sms.szText,szText);
s_sms.iClientNum = iClientNum; // клиент
// загрузка в очередь отправки
sms->fnPush((char *) &s_sms,sizeof (SMS));
return true;
}
// *****************************************
// * функции отправки сообщений из очереди *
// *****************************************
// проверка получения ответа сервера
static bool fnCheckForServerResponse(char *chBuf,unsigned int uiLen)
{
char *chCopyBuf = new char [uiLen +1];
VDL_TEXT *answer = new VDL_TEXT;
int iLinesQty;
bool bReceipt = false;
int iCycle;
int iContentLenMode = 0;
int iContentLen = 0;
int iLineLen;
int iHttpLen = 0;
bool bHttpLenDefined = false;
int iEmptyLineNum = 0;
char szTmp [20];
unsigned int uiChunkLen;
memcpy(chCopyBuf,chBuf,uiLen);
*(chCopyBuf+uiLen) = 0;
answer->fnReceive(chCopyBuf,uiLen);
delete [] chCopyBuf;
iLinesQty = answer->fnGetLinesQty();
if (iLinesQty < 3)
{
delete answer;
return bReceipt;
}
// определяем способ передачи размера посылки
for (iCycle = 0; iCycle < iLinesQty; iCycle++)
{
if (! strnicmp(answer->fnGetLine(iCycle),"Content-Length:",15))
{
iContentLenMode = 1; // с использованием "Content-Length" в заголовке
iContentLen = atoi(answer->fnGetLine(iCycle) +15);
break;
}
if (! strcmpi(answer->fnGetLine(iCycle),"Transfer-Encoding: chunked"))
{
iContentLenMode = 2; // по размерам фрагментов
break;
}
}
if (! iContentLenMode)
{
delete answer;
return bReceipt;
}
// подсчитываем размер заголовка, сохраняем номер пустой строки после заголовка
for (iCycle = 0; iCycle < iLinesQty; iCycle++)
{
iLineLen = answer->fnGetLineLen(iCycle);
iHttpLen += iLineLen +2;
if (! iLineLen) // заголовок принят полностью
{
bHttpLenDefined = true;
iEmptyLineNum = iCycle;
break;
}
}
if (! bHttpLenDefined)
{
delete answer;
return bReceipt;
}
switch (iContentLenMode) // способ передачи размера посылки
{
case 1: // с использованием "Content-Length" в заголовке
if ((unsigned int) (iHttpLen+iContentLen) == uiLen)
bReceipt = true;
break;
case 2: // по размерам фрагментов
for (iCycle = iEmptyLineNum +1; iCycle < iLinesQty; )
{
// длина фрагмента
strcpy(szTmp,"0x");
strcat(szTmp,answer->fnGetLine(iCycle));
sscanf(szTmp,"%x",&uiChunkLen);
iCycle++;
if (iCycle >= iLinesQty)
break;
if (uiChunkLen == 0) // фрагмент нулевой длины
if (iCycle < iLinesQty) // строки не закончились
if (answer->fnGetLineLen(iCycle +1) == 0) // следующая строка пуста
{
bReceipt = true;
break;
}
if (answer->fnGetLineLen(iCycle) != uiChunkLen) // неполный фрагмент
break;
iCycle++;
}
break;
}
delete answer;
return bReceipt;
}
// функция преобразования взята из интернета
static string cp1251_to_utf8(const char *str)
{
static string res;
int result_u,result_c;
result_u = MultiByteToWideChar(1251,
0,
str,
-1,
0,
0);
if (! result_u)
return 0;
wchar_t *ures = new wchar_t [result_u];
if (! MultiByteToWideChar(1251,
0,
str,
-1,
ures,
result_u))
{
delete [] ures;
return 0;
}
result_c = WideCharToMultiByte(
CP_UTF8,
0,
ures,
-1,
0,
0,
0,
0);
if (! result_c)
{
delete [] ures;
return 0;
}
char *cres = new char [result_c];
if (! WideCharToMultiByte(
CP_UTF8,
0,
ures,
-1,
cres,
result_c,
0,
0))
{
delete [] ures;
delete [] cres;
return 0;
}
delete [] ures;
res.clear();
res.append(cres);
delete [] cres;
return res;
}
static string utf8_to_cp1251(const char *str)
{
static string res;
int result_u,result_c;
result_u = MultiByteToWideChar(
CP_UTF8,
0,
str,
-1,
0,
0);
if (! result_u)
return 0;
wchar_t *ures = new wchar_t [result_u];
if(! MultiByteToWideChar(
CP_UTF8,
0,
str,
-1,
ures,
result_u))
{
delete[] ures;
return 0;
}
result_c = WideCharToMultiByte(
1251,
0,
ures,
-1,
0,
0,
0,
0);
if(! result_c)
{
delete [] ures;
return 0;
}
char *cres = new char[result_c];
if(! WideCharToMultiByte(
1251,
0,
ures,
-1,
cres,
result_c,
0,
0))
{
delete[] cres;
return 0;
}
delete[] ures;
res.clear();
res.append(cres);
delete[] cres;
return res;
}
// ****************************************************************************
// * *
// * 1000sms.ru *
// * *
// ****************************************************************************
void fnSmsQueueExecuteSend_1000sms(SMS *s_sms)
{
SOCKET client_socket;
string s;
char szTmp [20];
char *szInfo;
sockaddr_in dest_addr;
hostent *d_addr = NULL;
int iResult;
VDL_TEXT *query;
char szUser [64+3 +1];
string utf8;
int iCycle;
char szSenderName [20 +1];
char *chBuf;
unsigned int uiLen;
VDL_TEXT *in_text;
SYSTEMTIME lt;
RING *lexems;
char sz [XML_MAX_LEXEM_LEN +1];
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
switch (s_sms->iStep)
{
// **********************
// * передача сообщения *
// **********************
case 0:
// создаём сокет
client_socket = socket(AF_INET,SOCK_STREAM,0);
if (client_socket == 0 || client_socket == INVALID_SOCKET)
{
s = "fn=fnSmsQueueExecuteSend_1000sms() code=socket1 msg='socket error' error=";
itoa(WSAGetLastError(),szTmp,10);
s += szTmp;
szInfo = new char [s.length() +1];
strcpy(szInfo,s.c_str());
throw szInfo;
}
// заполнение структуры sockaddr_in
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons((unsigned short) 80);
LeaveCriticalSection(&app_cs);
d_addr = gethostbyname("api.1000sms.ru");
EnterCriticalSection(&app_cs);
if (d_addr == NULL)
{
closesocket(client_socket);
s = "fn=fnSmsQueueExecuteSend_1000sms() code=connect0 msg='host not found'";
szInfo = new char [s.length() +1];
strcpy(szInfo,s.c_str());
throw szInfo;
}
dest_addr.sin_addr.s_addr = *(DWORD* ) d_addr->h_addr_list [0];
LeaveCriticalSection(&app_cs);
iResult = connect(client_socket,(sockaddr *) &dest_addr,sizeof (dest_addr));
EnterCriticalSection(&app_cs);
if (iResult)
{
closesocket(client_socket);
s = "fn=fnSmsQueueExecuteSend_1000sms() code=connect1 msg='connect failed' error=";
itoa(WSAGetLastError(),szTmp,10);
s += szTmp;
szInfo = new char [s.length() +1];
strcpy(szInfo,s.c_str());
throw szInfo;
}
// счётчик попыток
if (config.bSmsBanEnabled)
{
config.iSmsCurrentTryQty++;
bConfigUpdate = true;
if (config.iSmsCurrentTryQty > config.iSmsMaxTryQty)
{
config.bSmsEnabled = false;
config.iSmsCurrentTryQty = 0;
closesocket(client_socket);
s = "fn=fnSmsQueueExecuteSend_1000sms() code=ban msg='max.try counter, SMS disabled'";
szInfo = new char [s.length() +1];
strcpy(szInfo,s.c_str());
throw szInfo;
}
}
// запрос
query = new VDL_TEXT;
s = "GET /?method=push_msg&email=";
fnReplace(szUser,sizeof (szUser) -1,config.szSms1000Email,"@","%40");
s += szUser;
s += "&password=";
s += config.szSms1000Password;
// текст сообщения в кодировке utf8
s += "&text=";
utf8 = cp1251_to_utf8(s_sms->szText);
for (iCycle = 0; iCycle < (int) utf8.length(); iCycle++)
{
s += "%";
sprintf(szTmp,"%02x",(unsigned char) utf8 [iCycle]);
s += szTmp;
}
s += "&phone=";
s += s_sms->szPhone;
// подпись отправителя (регистрируется на сайте)
s += "&sender_name=";
fnReplace(szSenderName,sizeof (szSenderName) -1,config.szSms1000SenderName," ","%20");
s += szSenderName;
s += " HTTP/1.1";
query->fnAddLine(s.c_str());
query->fnAddLine("User-Agent: fnSmsQueueExecuteSend_1000sms()");
query->fnAddLine("Host: api.1000sms.ru");
query->fnAddLine("");
chBuf = new char [WS_MAX_SEND_SIZE +1]; // +1 для завершающего нуля
uiLen = query->fnSend(chBuf,WS_MAX_SEND_SIZE);
delete query;
// передача
LeaveCriticalSection(&app_cs);
iResult = send(client_socket,chBuf,uiLen,0);
EnterCriticalSection(&app_cs);
if (iResult == SOCKET_ERROR)
{
closesocket(client_socket);
delete [] chBuf;
s = "fn=fnSmsQueueExecuteSend_1000sms() code=send msg='send error' error=";
itoa(WSAGetLastError(),szTmp,10);
s += szTmp;
szInfo = new char [s.length() +1];
strcpy(szInfo,s.c_str());
throw szInfo;
}
// сохраняем в лог-файл
*(chBuf+uiLen) = 0;
fnLogSms(chBuf);
// дождаться ответа
LeaveCriticalSection(&app_cs);
uiLen = 0;
do
{
iResult = recv(client_socket,chBuf+uiLen,WS_MAX_SEND_SIZE-uiLen,0);
if (iResult == 0 || iResult == SOCKET_ERROR)
break;
uiLen += iResult;
} while (! fnCheckForServerResponse(chBuf,uiLen));
EnterCriticalSection(&app_cs);
closesocket(client_socket);
// сохраняем в лог-файл
*(chBuf+uiLen) = 0;
fnLogSms(chBuf);
if (iResult == SOCKET_ERROR)
{
delete [] chBuf;
return;
}
// контроль статуса HTTP
in_text = new VDL_TEXT;
in_text->fnReceive(chBuf,uiLen);
// в объекте in_text сейчас содержится полный текст http-ответа, например:
/*
HTTP/1.1 200 OK
Server: nginx
Date: Fri, 22 Mar 2019 09:30:07 GMT
Content-Type: application/xml
Access-Control-Allow-Origin: *
X-Cache: MISS from DNKLAB-ROUTER.workgroup
X-Cache-Lookup: MISS from DNKLAB-ROUTER.workgroup:8080
Transfer-Encoding: chunked
Via: ICAP/1.0 DNKLAB-ROUTER.workgroup (C-ICAP/0.4.2 Antivirus service ), 1.1 DNKLAB-ROUTER.workgroup (squid/3.5.27)
Connection: keep-alive
F0
<?xml version="1.0" encoding="UTF-8"?>
<response><msg><err_code>0</err_code><text>OK</text><type>message</type></msg>
<data><id>47685656</id><credits>2.29</credits><n_raw_sms>1</n_raw_sms>
<sender_name>rekvizit</sender_name></data></response>
0
*/
if (strcmpi(in_text->fnGetLine(0),"HTTP/1.1 200 OK"))
{
s_sms->iGate = SMS_GATE_1000; // приписываем к шлюзу
s_sms->bAction = true;
s_sms->bCompleted = true;
s_sms->bSuccess = false; // неудача
GetLocalTime(<);
sprintf(s_sms->szStepTime,"%02u:%02u",lt.wHour,lt.wMinute);
delete [] chBuf;
delete in_text;
return;
}
lexems = new RING("fnSmsQueueExecuteSend_1000sms: lexems",1024);
lexems->fnLoadXML(in_text);
delete in_text;
for (iCycle = 0; iCycle < lexems->fnGetQty(); iCycle++)
{
lexems->fnPop(sz,iCycle);
if (! strcmpi(sz,"<err_code>"))
{
lexems->fnPop(sz,iCycle +1);
s_sms->iErrorCode = atoi(sz);
continue;
}
if (! strcmpi(sz,"<id>"))
{
lexems->fnPop(sz,iCycle +1);
s_sms->iSmsNum = atoi(sz);
continue;
}
}
delete lexems;
// обновление записи
s_sms->iGate = SMS_GATE_1000; // приписываем к шлюзу
s_sms->iStep = 1;
s_sms->bAction = true;
GetLocalTime(<);
sprintf(s_sms->szStepTime,"%02u:%02u",lt.wHour,lt.wMinute);
// *******************
// * контроль шага 0 *
// *******************
case 1:
// сообщение принято сервисом
if (s_sms->iErrorCode == 0)
{
// обновление записи
s_sms->iStep = 2;
GetLocalTime(<);
sprintf(s_sms->szStepTime,"%02u:%02u",lt.wHour,lt.wMinute);
// счётчик попыток
if (config.bSmsBanEnabled)
{
config.iSmsCurrentTryQty = 0;
bConfigUpdate = true;
}
}
else
{
s_sms->bCompleted = true;
s_sms->bSuccess = false;
}
break;
// **********************************************
// * проверка состояния отправленного сообщения *
// **********************************************
case 2:
// создаём сокет
client_socket = socket(AF_INET,SOCK_STREAM,0);
if (client_socket == 0 || client_socket == INVALID_SOCKET)
{
s = "fn=fnSmsQueueExecuteSend_1000sms() code=socket1 msg='socket error' error=";
itoa(WSAGetLastError(),szTmp,10);
s += szTmp;
szInfo = new char [s.length() +1];
strcpy(szInfo,s.c_str());
throw szInfo;
}
// заполнение структуры sockaddr_in
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons((unsigned short) 80);
LeaveCriticalSection(&app_cs);
d_addr = gethostbyname("api.1000sms.ru");
EnterCriticalSection(&app_cs);
if (d_addr == NULL)
{
closesocket(client_socket);
s = "fn=fnSmsQueueExecuteSend_1000sms() code=connect0 msg='host not found'";
szInfo = new char [s.length() +1];
strcpy(szInfo,s.c_str());
throw szInfo;
}
dest_addr.sin_addr.s_addr = *(DWORD* ) d_addr->h_addr_list [0];
LeaveCriticalSection(&app_cs);
iResult = connect(client_socket,(sockaddr *) &dest_addr,sizeof (dest_addr));
EnterCriticalSection(&app_cs);
if (iResult)
{
closesocket(client_socket);
s = "fn=fnSmsQueueExecuteSend_1000sms() code=connect1 msg='connect failed' error=";
itoa(WSAGetLastError(),szTmp,10);
s += szTmp;
szInfo = new char [s.length() +1];
strcpy(szInfo,s.c_str());
throw szInfo;
}
// запрос
query = new VDL_TEXT;
s = "GET /?method=get_msg_report&email=";
fnReplace(szUser,sizeof (szUser) -1,config.szSms1000Email,"@","%40");
s += szUser;
s += "&password=";
s += config.szSms1000Password;
s += "&id=";
sprintf(szTmp,"%i",s_sms->iSmsNum);
s += szTmp;
s += " HTTP/1.1";
query->fnAddLine(s.c_str());
query->fnAddLine("User-Agent: fnSmsQueueExecuteSend_1000sms()");
query->fnAddLine("Host: api.1000sms.ru");
query->fnAddLine("");
chBuf = new char [WS_MAX_SEND_SIZE +1]; // +1 для завершающего нуля
uiLen = query->fnSend(chBuf,WS_MAX_SEND_SIZE);
delete query;
// передача
LeaveCriticalSection(&app_cs);
iResult = send(client_socket,chBuf,uiLen,0);
EnterCriticalSection(&app_cs);
if (iResult == SOCKET_ERROR)
{
closesocket(client_socket);
delete [] chBuf;
s = "fn=fnSmsQueueExecuteSend_1000sms() code=send msg='send error' error=";
itoa(WSAGetLastError(),szTmp,10);
s += szTmp;
szInfo = new char [s.length() +1];
strcpy(szInfo,s.c_str());
throw szInfo;
}
// сохраняем в лог-файл
*(chBuf+uiLen) = 0;
fnLogSms(chBuf);
// дождаться ответа
LeaveCriticalSection(&app_cs);
uiLen = 0;
do
{
iResult = recv(client_socket,chBuf+uiLen,WS_MAX_SEND_SIZE-uiLen,0);
if (iResult == 0 || iResult == SOCKET_ERROR)
break;
uiLen += iResult;
} while (! fnCheckForServerResponse(chBuf,uiLen));
EnterCriticalSection(&app_cs);
closesocket(client_socket);
// сохраняем в лог-файл
*(chBuf+uiLen) = 0;
fnLogSms(chBuf);
if (iResult == SOCKET_ERROR)
{
delete [] chBuf;
return;
}
// контроль статуса HTTP
in_text = new VDL_TEXT;
in_text->fnReceive(chBuf,uiLen);
// в объекте in_text сейчас содержится полный текст http-ответа, например:
/*
HTTP/1.1 200 OK
Server: nginx
Date: Fri, 22 Mar 2019 09:34:16 GMT
Content-Type: application/xml
Access-Control-Allow-Origin: *
X-Cache: MISS from DNKLAB-ROUTER.workgroup
X-Cache-Lookup: MISS from DNKLAB-ROUTER.workgroup:8080
Transfer-Encoding: chunked
Via: ICAP/1.0 DNKLAB-ROUTER.workgroup (C-ICAP/0.4.2 Antivirus service ), 1.1 DNKLAB-ROUTER.workgroup (squid/3.5.27)
Connection: keep-alive
22F
<?xml version="1.0" encoding="UTF-8"?>
<response><msg><err_code>0</err_code><text>OK</text><type>message</type></msg>
<data><id>47685656</id><sender_name>rekvizit</sender_name><text>магистра</text>
<phone>79831853847</phone><type>1</type><n_raw_sms>1</n_raw_sms>
<start_time>2019-03-22 12:30:07</start_time><last_update>2019-03-22 12:30:00</last_update>
<dlr_mask></dlr_mask><dlr_url></dlr_url><sms_validity></sms_validity>
<state>1</state><smpp_msgdata></smpp_msgdata><credits>2.290</credits>
<state_text>Доставлено</state_text></data></response>
0
*/
if (strcmpi(in_text->fnGetLine(0),"HTTP/1.1 200 OK"))
{
s_sms->iGate = SMS_GATE_1000; // приписываем к шлюзу
s_sms->bCompleted = true;
s_sms->bSuccess = false; // неудача
GetLocalTime(<);
sprintf(s_sms->szStepTime,"%02u:%02u",lt.wHour,lt.wMinute);
delete [] chBuf;
delete in_text;
return;
}
lexems = new RING("fnSmsQueueExecuteSend_1000sms: lexems",1024);
lexems->fnLoadXML(in_text);
delete in_text;
for (iCycle = 0; iCycle < lexems->fnGetQty(); iCycle++)
{
lexems->fnPop(sz,iCycle);
if (! strcmpi(sz,"<state_text>"))
{
lexems->fnPop(sz,iCycle +1);
s = utf8_to_cp1251(sz);
strcpy(s_sms->szServiceAnswer,s.c_str());
}
}
delete lexems;
// обновление записи
s_sms->iStep = 3;
GetLocalTime(<);
sprintf(s_sms->szStepTime,"%02u:%02u",lt.wHour,lt.wMinute);
// *******************
// * контроль шага 2 *
// *******************
case 3:
do
{
if (! strcmp(s_sms->szServiceAnswer,"Доставлено"))
{
s_sms->bSuccess = true;
s_sms->bCompleted = true;
s_sms->iStep = 4;
continue;
}
if (! strcmp(s_sms->szServiceAnswer,"Не доставлено"))
{
s_sms->bSuccess = false;
s_sms->bCompleted = true;
s_sms->iStep = 4;
continue;
}
if (! strcmp(s_sms->szServiceAnswer,"Отправлено"))
{
s_sms->bPaused = true;
s_sms->iStep = 2;
continue;
}
s_sms->iStep = 2; // переходим к повторной проверке состояния
} while (false);
// обновление записи
GetLocalTime(<);
sprintf(s_sms->szStepTime,"%02u:%02u",lt.wHour,lt.wMinute);
break;
} // end of switch
#pragma GCC diagnostic pop
// обновление метки времени
GetLocalTime(<);
SystemTimeToFileTime(<,&s_sms->ft_action);
} // end of fnSmsQueueExecuteSend_1000sms()
// ****************************************************************************
// * *
// * smsaero.ru *
// * *
// ****************************************************************************
void fnSmsQueueExecuteSend_smsaero(SMS *s_sms)
{
SOCKET client_socket;
sockaddr_in dest_addr;
VDL_TEXT *query;
string s;
md5_context ctx;
int iCycle;
char szTmp [20];
unsigned char digest [16];
string utf8;
int iResult;
char *chBuf;
unsigned int uiLen;
VDL_TEXT *in_text;
SYSTEMTIME lt;
hostent *d_addr = NULL;
char szUser [64+3 +1];
char szSenderName [20 +1];
char *szInfo;
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough"
switch (s_sms->iStep)
{
// **********************
// * передача сообщения *
// **********************
case 0:
// создаём сокет
client_socket = socket(AF_INET,SOCK_STREAM,0);
if (client_socket == 0 || client_socket == INVALID_SOCKET)
{
s = "fn=fnSmsQueueExecuteSend_smsaero() code=socket1 msg='socket error' error=";
itoa(WSAGetLastError(),szTmp,10);
s += szTmp;
szInfo = new char [s.length() +1];
strcpy(szInfo,s.c_str());
throw szInfo;
}
// заполнение структуры sockaddr_in
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons((unsigned short) 80);
LeaveCriticalSection(&app_cs);
d_addr = gethostbyname("gate.smsaero.ru");
EnterCriticalSection(&app_cs);
if (d_addr == NULL)
{
closesocket(client_socket);
s = "fn=fnSmsQueueExecuteSend_smsaero() code=connect0 msg='host not found'";
szInfo = new char [s.length() +1];
strcpy(szInfo,s.c_str());
throw szInfo;
}
dest_addr.sin_addr.s_addr = *(DWORD* ) d_addr->h_addr_list [0];
LeaveCriticalSection(&app_cs);
iResult = connect(client_socket,(sockaddr *) &dest_addr,sizeof (dest_addr));
EnterCriticalSection(&app_cs);
if (iResult)
{
closesocket(client_socket);
s = "fnSmsQueueExecuteSend_smsaero() code=connect1 msg='connect failed' error=";
itoa(WSAGetLastError(),szTmp,10);
s += szTmp;
szInfo = new char [s.length() +1];
strcpy(szInfo,s.c_str());
throw szInfo;
}
// счётчик попыток
if (config.bSmsBanEnabled)
{
config.iSmsCurrentTryQty++;
bConfigUpdate = true;
if (config.iSmsCurrentTryQty > config.iSmsMaxTryQty)
{
config.bSmsEnabled = false;
config.iSmsCurrentTryQty = 0;
closesocket(client_socket);
s = "fn=fnSmsQueueExecuteSend_smsaero() code=ban msg='max.try counter, SMS disabled'";
szInfo = new char [s.length() +1];
strcpy(szInfo,s.c_str());
throw szInfo;
}
}
// запрос
query = new VDL_TEXT;
s = "GET /send/?user=";
fnReplace(szUser,sizeof (szUser) -1,config.szSmsAeroEmail,"@","%40");
s += szUser;
s += "&password=";
// формируем хэш пароля (md5)
md5_starts(&ctx);
md5_update(&ctx,(unsigned char *) config.szSmsAeroPassword,strlen(config.szSmsAeroPassword));
md5_finish(&ctx,digest);
for (iCycle = 0; iCycle < 16; iCycle++)
{
sprintf(szTmp,"%02x",digest [iCycle]);
s += szTmp;
}
s += "&to=";
s += s_sms->szPhone;
s += "&text=";
// текст сообщения в кодировке utf8
utf8 = cp1251_to_utf8(s_sms->szText);
for (iCycle = 0; iCycle < (int) utf8.length(); iCycle++)
{
s += "%";
sprintf(szTmp,"%02x",(unsigned char) utf8 [iCycle]);
s += szTmp;
}
// подпись отправителя (регистрируется на сайте)
s += "&from=";
fnReplace(szSenderName,sizeof (szSenderName) -1,config.szSmsAeroSenderName," ","%20");
s += szSenderName;
s += " HTTP/1.1";
query->fnAddLine(s.c_str());
query->fnAddLine("User-Agent: fnSmsQueueExecuteSend_smsaero()");
query->fnAddLine("Host: gate.smsaero.ru");
query->fnAddLine("");
chBuf = new char [WS_MAX_SEND_SIZE +1]; // +1 для завершающего нуля
uiLen = query->fnSend(chBuf,WS_MAX_SEND_SIZE);
delete query;
// передача
LeaveCriticalSection(&app_cs);
iResult = send(client_socket,chBuf,uiLen,0);
EnterCriticalSection(&app_cs);
if (iResult == SOCKET_ERROR)
{
closesocket(client_socket);
delete [] chBuf;
s = "fn=fnSmsQueueExecuteSend_smsaero() code=send msg='send error' error=";
itoa(WSAGetLastError(),szTmp,10);
s += szTmp;
szInfo = new char [s.length() +1];
strcpy(szInfo,s.c_str());
throw szInfo;
}
// сохраняем в лог-файл
*(chBuf+uiLen) = 0;
fnLogSms(chBuf);
// дождаться ответа
LeaveCriticalSection(&app_cs);
uiLen = 0;
do
{
iResult = recv(client_socket,chBuf+uiLen,WS_MAX_SEND_SIZE-uiLen,0);
if (iResult == 0 || iResult == SOCKET_ERROR)
break;
uiLen += iResult;
} while (! fnCheckForServerResponse(chBuf,uiLen));
EnterCriticalSection(&app_cs);
closesocket(client_socket);
// сохраняем в лог-файл
*(chBuf+uiLen) = 0;
fnLogSms(chBuf);
if (iResult == SOCKET_ERROR)
{
delete [] chBuf;
return;
}
// копируем ответ сервиса
in_text = new VDL_TEXT;
in_text->fnReceive(chBuf,uiLen);
// контроль статуса HTTP
if (strcmpi(in_text->fnGetLine(0),"HTTP/1.1 200 OK"))
{
s_sms->iGate = SMS_GATE_AERO; // приписываем к шлюзу
s_sms->bAction = true;
s_sms->bCompleted = true;
s_sms->bSuccess = false;
GetLocalTime (<);
sprintf(s_sms->szStepTime,"%02u:%02u",lt.wHour,lt.wMinute);
delete [] chBuf;
delete in_text;
return;
}
// контроль длины ответа сервера
if (in_text->fnGetLineLen(in_text->fnGetLinesQty() -1) > 64)
{
s_sms->iGate = SMS_GATE_AERO; // приписываем к шлюзу
s_sms->bAction = true;
s_sms->bCompleted = true;
s_sms->bSuccess = false;
GetLocalTime(<);
sprintf(s_sms->szStepTime,"%02u:%02u",lt.wHour,lt.wMinute);
delete [] chBuf;
delete in_text;
return;
}
delete [] chBuf;
strcpy(s_sms->szServiceAnswer,in_text->fnGetLine(in_text->fnGetLinesQty() -1));
delete in_text;
// обновление записи
s_sms->iGate = SMS_GATE_AERO; // приписываем к шлюзу
s_sms->iStep = 1;
s_sms->bAction = true;
GetLocalTime(<);
sprintf(s_sms->szStepTime,"%02u:%02u",lt.wHour,lt.wMinute);
// *******************
// * контроль шага 1 *
// *******************
case 1:
// сообщение принято сервисом ("2664302=accepted")
if (strstr(s_sms->szServiceAnswer,"accepted"))
{
s_sms->iSmsNum = atoi(s_sms->szServiceAnswer);
// обновление записи
s_sms->iStep = 2;
GetLocalTime(<);
sprintf(s_sms->szStepTime,"%02u:%02u",lt.wHour,lt.wMinute);
// счётчик попыток
if (config.bSmsBanEnabled)
{
config.iSmsCurrentTryQty = 0;
bConfigUpdate = true;
}
break;
}
// не все обязательные поля заполнены ("empty field. reject.")
if (strstr(s_sms->szServiceAnswer,"empty"))
{
s_sms->bCompleted = true;
s_sms->bSuccess = false;
break;
}
// ошибка авторизации ("incorrect user or password. reject")
if (strstr(s_sms->szServiceAnswer,"password"))
{
s_sms->bError = true;
s_sms->iStep = 0; // предыдущий шаг
GetLocalTime(<);
sprintf(s_sms->szStepTime,"%02u:%02u",lt.wHour,lt.wMinute);
break;
}
// недостаточно sms на балансе ("no credits")
if (strstr(s_sms->szServiceAnswer,"credits"))
{
s_sms->bError = true;
s_sms->iStep = 0; // предыдущий шаг
GetLocalTime(<);
sprintf(s_sms->szStepTime,"%02u:%02u",lt.wHour,lt.wMinute);
break;
}
// неверная (незарегистрированная) подпись отправителя
// ("incorrect sender name. reject")
if (strstr(s_sms->szServiceAnswer,"sender"))
{
s_sms->bError = true;
s_sms->iStep = 0; // предыдущий шаг
GetLocalTime(<);
sprintf(s_sms->szStepTime,"%02u:%02u",lt.wHour,lt.wMinute);
break;
}
// неверно задан номер телефона (формат 71234567890)
// ("incorrect destination adress. reject")
if (strstr(s_sms->szServiceAnswer,"destination"))
{
s_sms->bCompleted = true;
s_sms->bSuccess = false;
break;
}
// неправильный формат даты ("incorrect date. reject")
if (strstr(s_sms->szServiceAnswer,"date"))
{
s_sms->bCompleted = true;
s_sms->bSuccess = false;
break;
}
break;
// **********************************************
// * проверка состояния отправленного сообщения *
// **********************************************
case 2:
// создаём сокет
client_socket = socket(AF_INET,SOCK_STREAM,0);
if (client_socket == 0 || client_socket == INVALID_SOCKET)
{
s = "fn=fnSmsQueueExecuteSend_smsaero() code=socket1 msg='socket error' error=";
itoa (WSAGetLastError(),szTmp,10);
s += szTmp;
szInfo = new char [s.length() +1];
strcpy(szInfo,s.c_str());
throw szInfo;
}
// заполнение структуры sockaddr_in
dest_addr.sin_family = AF_INET;
dest_addr.sin_port = htons((unsigned short) 80);
LeaveCriticalSection(&app_cs);
d_addr = gethostbyname("gate.smsaero.ru");
EnterCriticalSection(&app_cs);
if (d_addr == NULL)
{
closesocket(client_socket);
s = "fn=fnSmsQueueExecuteSend_smsaero() code=connect0 msg='host not found'";
szInfo = new char [s.length() +1];
strcpy(szInfo,s.c_str());
throw szInfo;
}
dest_addr.sin_addr.s_addr = *(DWORD* ) d_addr->h_addr_list [0];
LeaveCriticalSection(&app_cs);
iResult = connect(client_socket,(sockaddr *) &dest_addr,sizeof (dest_addr));
EnterCriticalSection(&app_cs);
if (iResult)
{
closesocket(client_socket);
s = "fn=fnSmsQueueExecuteSend_smsaero() code=connect1 msg='connect failed' error=";
itoa(WSAGetLastError(),szTmp,10);
s += szTmp;
szInfo = new char [s.length() +1];
strcpy (szInfo,s.c_str());
throw szInfo;
}
// запрос
query = new VDL_TEXT;
s = "GET /status/?user=";
fnReplace(szUser,sizeof (szUser) -1,config.szSmsAeroEmail,"@","%40");
s += szUser;
s += "&password=";
// формируем хэш пароля (md5)
md5_starts(&ctx);
md5_update(&ctx,(unsigned char *) config.szSmsAeroPassword,strlen(config.szSmsAeroPassword));
md5_finish(&ctx,digest);
for (iCycle = 0; iCycle < 16; iCycle++)
{
sprintf(szTmp,"%02x",digest [iCycle]);
s += szTmp;
}
s += "&id=";
sprintf(szTmp,"%u",s_sms->iSmsNum);
s += szTmp;
s += " HTTP/1.1";
query->fnAddLine(s.c_str ());
query->fnAddLine("User-Agent: fnSmsQueueExecuteSend_smsaero()");
query->fnAddLine("Host: gate.smsaero.ru");
query->fnAddLine("");
chBuf = new char [WS_MAX_SEND_SIZE +1]; // +1 для завершающего нуля
uiLen = query->fnSend(chBuf,WS_MAX_SEND_SIZE);
delete query;
// передача
LeaveCriticalSection(&app_cs);
iResult = send(client_socket,chBuf,uiLen,0);
EnterCriticalSection(&app_cs);
if (iResult == SOCKET_ERROR)
{
closesocket(client_socket);
delete [] chBuf;
s = "fn=fnSmsQueueExecuteSend_smsaero() code=send msg='send error' error=";
itoa(WSAGetLastError(),szTmp,10);
s += szTmp;
szInfo = new char [s.length() +1];
strcpy(szInfo,s.c_str());
throw szInfo;
}
// сохраняем в лог-файл
*(chBuf+uiLen) = 0;
fnLogSms(chBuf);
// дождаться ответа
LeaveCriticalSection(&app_cs);
uiLen = 0;
do
{
iResult = recv(client_socket,chBuf+uiLen,WS_MAX_SEND_SIZE-uiLen,0);
if (iResult == 0 || iResult == SOCKET_ERROR)
break;
uiLen += iResult;
} while (! fnCheckForServerResponse(chBuf,uiLen));
EnterCriticalSection(&app_cs);
closesocket(client_socket);
// сохраняем в лог-файл
*(chBuf+uiLen) = 0;
fnLogSms(chBuf);
if (iResult == SOCKET_ERROR)
{
delete [] chBuf;
return;
}
// копируем ответ сервиса
in_text = new VDL_TEXT;
in_text->fnReceive(chBuf,uiLen);
// контроль статуса HTTP
if (strcmpi(in_text->fnGetLine(0),"HTTP/1.1 200 OK"))
{
s_sms->bCompleted = true;
s_sms->bSuccess = false;
GetLocalTime(<);
sprintf(s_sms->szStepTime,"%02u:%02u",lt.wHour,lt.wMinute);
delete [] chBuf;
delete in_text;
return;
}
// контроль длины ответа сервера
if (in_text->fnGetLineLen(in_text->fnGetLinesQty () -1) > 64)
{
s_sms->bCompleted = true;
s_sms->bSuccess = false;
GetLocalTime(<);
sprintf(s_sms->szStepTime,"%02u:%02u",lt.wHour,lt.wMinute);
delete [] chBuf;
delete in_text;
return;
}
delete [] chBuf;
strcpy(s_sms->szServiceAnswer,in_text->fnGetLine(in_text->fnGetLinesQty() -1));
delete in_text;
// обновление записи
s_sms->iStep = 3;
GetLocalTime(<);
sprintf(s_sms->szStepTime,"%02u:%02u",lt.wHour,lt.wMinute);
// *******************
// * контроль шага 2 *
// *******************
case 3:
// сообщение доставлено ("2664302=delivery success")
if (strstr(s_sms->szServiceAnswer,"success"))
{
s_sms->bCompleted = true;
s_sms->bSuccess = true;
// обновление записи
s_sms->iStep = 4;
GetLocalTime(<);
sprintf(s_sms->szStepTime,"%02u:%02u",lt.wHour,lt.wMinute);
break;
}
// ошибка доставки SMS (абонент в течение времени доставки находился
// вне зоны действия сети или номер абонента заблокирован)
// ("2664302=delivery failure")
if (strstr(s_sms->szServiceAnswer,"failure"))
{
s_sms->bCompleted = true;
s_sms->bSuccess = false;
// обновление записи
s_sms->iStep = 4;
GetLocalTime(<);
sprintf(s_sms->szStepTime,"%02u:%02u",lt.wHour,lt.wMinute);
break;
}
// сообщение доставлено в SMSC ("2664302=smsc submit")
if (strstr(s_sms->szServiceAnswer,"smsc submit"))
{
s_sms->bError = true;
s_sms->iStep = 2; // предыдущий шаг
GetLocalTime(<);
sprintf(s_sms->szStepTime,"%02u:%02u",lt.wHour,lt.wMinute);
break;
}
// отвергнуто SMSC ("2664302=smsc reject")
if (strstr(s_sms->szServiceAnswer,"smsc reject"))
{
s_sms->bCompleted = true;
s_sms->bSuccess = false;
// обновление записи
s_sms->iStep = 4;
GetLocalTime(<);
sprintf(s_sms->szStepTime,"%02u:%02u",lt.wHour,lt.wMinute);
break;
}
// ожидает отправки ("2664302=queue")
if (strstr(s_sms->szServiceAnswer,"queue"))
{
s_sms->bError = true;
s_sms->iStep = 2; // предыдущий шаг
GetLocalTime(<);
sprintf(s_sms->szStepTime,"%02u:%02u",lt.wHour,lt.wMinute);
break;
}
// ожидание статуса (запросите позднее) ("2664302=wait status")
if (strstr(s_sms->szServiceAnswer,"status"))
{
s_sms->bError = true;
s_sms->iStep = 2; // предыдущий шаг
GetLocalTime(<);
sprintf(s_sms->szStepTime,"%02u:%02u",lt.wHour,lt.wMinute);
break;
}
// неверный идентификатор сообщения ("2664302=incorrect id. reject")
if (strstr(s_sms->szServiceAnswer,"incorrect id"))
{
s_sms->bCompleted = true;
s_sms->bSuccess = false;
GetLocalTime(<);
sprintf(s_sms->szStepTime,"%02u:%02u",lt.wHour,lt.wMinute);
break;
}
// не все обязательные поля заполнены ("empty field. reject.")
if (strstr(s_sms->szServiceAnswer,"empty"))
{
s_sms->bCompleted = true;
s_sms->bSuccess = false;
GetLocalTime(<);
sprintf(s_sms->szStepTime,"%02u:%02u",lt.wHour,lt.wMinute);
break;
}
// ошибка авторизации ("incorrect user or password. reject")
if (strstr(s_sms->szServiceAnswer,"password"))
{
s_sms->bError = true;
s_sms->iStep = 2; // предыдущий шаг
GetLocalTime(<);
sprintf(s_sms->szStepTime,"%02u:%02u",lt.wHour,lt.wMinute);
break;
}
} // end of switch
#pragma GCC diagnostic pop
// обновление метки времени
GetLocalTime(<);
SystemTimeToFileTime(<,&s_sms->ft_action);
} // end of fnSmsQueueExecuteSend_smsaero()
void fnSmsQueueScan(void)
{
SYSTEMTIME lt;
union
{
FILETIME ft;
__int64 time64_current;
};
int iQty;
int iCycle;
SMS s_sms;
string s;
char szToday [11];
// текущее время
GetLocalTime(<);
SystemTimeToFileTime(<,&ft);
// текущая дата
fnGetToday(szToday);
// сканирование очереди
iQty = sms->fnGetQty();
for (iCycle = 0; iCycle < iQty; iCycle++)
{
sms->fnPop((char *) &s_sms,iCycle);
if (s_sms.bCompleted) // обработка завершена
continue;
if (s_sms.bAction)
{
int iElapsedTime;
iElapsedTime = (int) ((time64_current-s_sms.time64_action)/10000000);
if (iElapsedTime < config.iSmsStatusTime*60)
continue;
// пауза после ошибки
if (s_sms.bError
&& (iElapsedTime < config.iSmsErrorTime*60))
continue;
}
if (s_sms.bPaused)
continue;
if (fnGetDayIndex(s_sms.szDate,szToday) > config.iSmsMaxAge)
continue;
try
{
if (config.bSmsEnabled)
{
switch (config.iSmsGate)
{
// **************
// * 1000sms.ru *
// **************
case SMS_GATE_1000:
// SMS-сообщение приписано к другому шлюзу
if (s_sms.iGate && (s_sms.iGate != SMS_GATE_1000))
break;
// вызов соответствующей функции обработки
fnSmsQueueExecuteSend_1000sms(&s_sms);
// обновляем запись в очереди
sms->fnReplace((char *) &s_sms,iCycle,sizeof (SMS));
break;
// **************
// * smsaero.ru *
// **************
case SMS_GATE_AERO:
// SMS-сообщение приписано к другому шлюзу
if (s_sms.iGate && (s_sms.iGate != SMS_GATE_AERO))
break;
// вызов соответствующей функции обработки
fnSmsQueueExecuteSend_smsaero(&s_sms);
// обновляем запись в очереди
sms->fnReplace((char *) &s_sms,iCycle,sizeof (SMS));
break;
// другие шлюзы
}
}
}
catch (char *szExceptionInfo)
{
s = "Исключение:\r\n";
s += szExceptionInfo;
fnLog(s.c_str());
// delete [] szExceptionInfo;
}
break;
}
}
// ***********************************************
// * визуальный контроль состояния sms-сообщений *
// ***********************************************
void fnAppSms(QUERY *query)
{
string s;
char szTmp [20];
char szDate1 [11];
char szToday [11]; // сегодня
int iQty;
int iCycle;
SMS s_sms;
int iAction;
int iClient;
char szClientFIO [100]; // для вывода FIO
// параметры фильтра - значения по умолчанию
int iDays = 7;
int iTuningIconSize = fnGetTuningIconSize(query);
// загружаем параметры фильтра
// кол-во дней
if (login_days->fnGetValue(szTmp,query->szLogin))
iDays = atoi (szTmp);
else // параметр не найден
{
sprintf(szTmp,"%i",iDays);
login_days->fnAdd(query->szLogin,szTmp);
}
// подготавливаем диапазон дат
fnGetToday(szToday); // сегодня
fnCreateDate(szDate1,szToday,-1*(iDays -1));
fnFormContent(query);
query->dst->fnAddLine("<p>SMS-сообщения</p>");
s = "<p class=\"help\">Таблица отображает SMS-сообщения за период, который охватывает \
указанное кол-во дней — заканчивая сегодняшним днём.</p>";
query->dst->fnAddLine(s.c_str());
// выбор периода
s = "<p><form action=\"/sms_filter_accept\" method=post>";
s += "Период времени: <select name=days><option";
if (iDays == 7)
s += " selected";
s += " value=\"7\">7 дней<option";
if (iDays == 14)
s += " selected";
s += " value=\"14\">14 дней<option";
if (iDays == 28)
s += " selected";
s += " value=\"28\">28 дней</select>";
s += " <input type=submit value=\"Применить\"></form></p>";
// список sms-сообщений
s += "<table width=\"100%\" border=1><tr>";
s += "<td>№</td>";
s += "<td>Дата</td>";
s += "<td>Время</td>";
s += "<td>Тип</td>";
s += "<td>Шаг</td>";
s += "<td>Префикс</td>";
s += "<td>Клиент</td>";
s += "<td>Тел.номер</td>";
s += "<td>Текст сообщения</td>";
s += "<td>Ответ сервиса</td>";
s += "<td> </td>";
s += "<td>№</td>";
s += "<td></td></tr>";
query->dst->fnAddLine(s.c_str());
// формирование
iQty = sms->fnGetQty();
for (iCycle = 0; iCycle < iQty; iCycle++)
{
sms->fnPop((char *) &s_sms,iCycle);
if (! fnCheckDateRange(szDate1,s_sms.szDate,szToday))
continue;
s = "<tr";
// серебряный фон, если запись слишком старая для обработки
if (fnGetDayIndex(s_sms.szDate,szToday) > config.iSmsMaxAge)
{
s += " bgcolor=\"";
s += szColorSilver;
s += "\"";
}
s += ">";
// №
s += "<td valign=top align=right>";
sprintf(szTmp,"%i",s_sms.iId);
s += szTmp;
s += "</td>";
// дата
s += "<td valign=top>";
s += s_sms.szDate;
s += "</td>";
// время
s += "<td valign=top>";
s += s_sms.szTime;
s += "</td>";
// тип
s += "<td valign=top>";
switch (s_sms.iType)
{
case 0: // тест
if (iTuningIconSize == 16)
s += "<img src=\"/images/16x16/appointment-soon.png\" title=\"Тестовое SMS-сообщение\" border=0>";
else
s += "<img src=\"/images/24x24/appointment-soon.png\" title=\"Тестовое SMS-сообщение\" border=0>";
break;
case 1: // выдача результатов
if (iTuningIconSize == 16)
s += "<img src=\"/images/16x16/edit-paste.png\" title=\"Выдача результатов\" border=0>";
else
s += "<img src=\"/images/24x24/edit-paste.png\" title=\"Выдача результатов\" border=0>";
break;
case 2: // поздравление с днём рождения
if (iTuningIconSize == 16)
s += "<img src=\"/images/16x16/face-smile.png\" title=\"Поздравление с днём рождения\" border=0>";
else
s += "<img src=\"/images/24x24/face-smile.png\" title=\"Поздравление с днём рождения\" border=0>";
break;
case 3: // информация клиентам
if (iTuningIconSize == 16)
s += "<img src=\"/images/16x16/attach.png\" title=\"Информация клиентам\" border=0>";
else
s += "<img src=\"/images/24x24/attach.png\" title=\"Информация клиентам\" border=0>";
break;
}
s += "</td>";
// шаг
s += "<td valign=top><nobr>";
sprintf(szTmp,"%i",s_sms.iStep);
s += szTmp;
if (s_sms.iStep)
{
s += " / ";
s += s_sms.szStepTime;
}
s += "</nobr></td>";
// префикс
s += "<td valign=top>";
s += s_sms.szPrefix;
s += " </td>";
// клиент
s += "<td valign=top style=\"font-size: 8pt\">";
switch (s_sms.iType)
{
case 1:
case 2:
case 3:
iClient = fnClientSearchByNum(s_sms.iClientNum);
if (iClient == -1)
continue;
sprintf(szClientFIO,"%s %s %s",
client [iClient]->fnGetFamily(),
client [iClient]->fnGetName(),
client [iClient]->fnGetName2());
s += szClientFIO;
break;
default: s += " ";
}
s += "</td>";
// номер телефона получателя
s += "<td valign=top>";
switch (s_sms.iType)
{
case 0:
case 1:
case 2:
case 3:
s += s_sms.szPhone;
break;
default: s += " ";
}
s += "</td>";
// текст сообщения
s += "<td valign=top style=\"font-size: 8pt\">";
switch (s_sms.iType)
{
case 0:
case 1:
case 2:
case 3:
s += s_sms.szText;
break;
default: s += " ";
}
s += "</td>";
// ответ сервиса
s += "<td valign=top style=\"font-size: 8pt\">";
if (s_sms.bAction)
{
switch (s_sms.iGate)
{
case SMS_GATE_1000:
case SMS_GATE_AERO:
s += s_sms.szServiceAnswer;
break;
}
}
s += "</td>";
// статус
s += "<td valign=top>";
if (s_sms.bPaused)
{
if (iTuningIconSize == 16)
s += "<img src=\"/images/16x16/agt_resume.png\" border=0>";
else
s += "<img src=\"/images/24x24/agt_resume.png\" border=0>";
}
if (s_sms.bCompleted)
{
if (s_sms.bSuccess)
{
if (iTuningIconSize == 16)
s += "<img src=\"/images/16x16/agt_action_success.png\" border=0>";
else
s += "<img src=\"/images/24x24/agt_action_success.png\" border=0>";
}
else
{
if (iTuningIconSize == 16)
s += "<img src=\"/images/16x16/agt_action_fail.png\" border=0>";
else
s += "<img src=\"/images/24x24/agt_action_fail.png\" border=0>";
}
}
s += "</td>";
// №
s += "<td valign=top align=right>";
sprintf(szTmp,"%i",s_sms.iId);
s += szTmp;
s += "</td>";
// ссылка на вкладку редактирования
s += "<td valign=top><a href=\"/sms_edit?sms_id=";
// sprintf (szTmp,"%i",s_sms.iId);
s += szTmp;
s += "\">";
if (iTuningIconSize == 16)
s += "<img src=\"/images/16x16/gtk-edit.png\" border=1 title=\"Редактировать\">";
else
s += "<img src=\"/images/24x24/gtk-edit.png\" border=1 title=\"Редактировать\">";
s += "</a></td></tr>";
query->dst->fnAddLine(s.c_str());
}
query->dst->fnAddLine("</table>");
// *******************
// * список действий *
// *******************
s = "<form action=\"/sms_action_accept\" method=post>";
s += "<p>Действие: <select name=sms_action>";
s += "<option value=\"0\">Выберите действие";
// раздел "Групповые операции обработки"
s += "<optgroup label=\"Групповые операции обработки\" class=\"no_select\"></optgroup>";
s += "<option value=\"9\">Поставить на паузу SMS-сообщения с шагом доставки 0";
s += "<option value=\"1\">Снять паузу с SMS-сообщений типа 0 (тестовые сообщения)";
s += "<option value=\"2\">Снять паузу с SMS-сообщений типа 1 (сообщения планировщика выдачи результатов)";
s += "<option value=\"3\">Снять паузу с SMS-сообщений типа 2 (поздравления с днём рождения)";
s += "<option value=\"4\">Снять паузу с SMS-сообщений типа 3 (информационные сообщения)";
// раздел "Групповые операции удаления"
s += "<optgroup label=\"Групповые операции удаления\" class=\"no_select\"></optgroup>";
s += "<option value=\"5\">Удалить отправленные SMS-сообщения";
s += "<option value=\"6\">Удалить неотправленные SMS-сообщения";
s += "<option value=\"10\">Удалить SMS-сообщения типа 0 (тестовые сообщения), с шагом доставки 0";
s += "<option value=\"11\">Удалить SMS-сообщения типа 1 (сообщения планировщика выдачи результатов), с шагом доставки 0";
s += "<option value=\"12\">Удалить SMS-сообщения типа 2 (поздравления с днём рождения), с шагом доставки 0";
s += "<option value=\"13\">Удалить SMS-сообщения типа 3 (информационные сообщения), с шагом доставки 0";
s += "<option value=\"7\">Удалить SMS-сообщения, обработка которых завершена";
s += "<option value=\"8\">Удалить все SMS-сообщения";
s += "</select>";
// получаем номер транзакции и передаём его в скрытых параметрах
iAction = actions->fnAdd();
s += "<input type=hidden name=action value=\"";
sprintf(szTmp,"%i",iAction);
s += szTmp;
s += "\">";
s += " <input type=submit value=\"Применить\"></p>";
s += "</form>";
query->dst->fnAddLine (s.c_str ());
// ************************************************
// * таблица с формами для создания SMS-сообщений *
// ************************************************
s = "<p>Таблица с формами для создания SMS-сообщений";
s += "<table border=1><tr>";
s += "<td>№</td>";
s += "<td>Тип</td>";
s += "<td>Статус</td>";
s += "<td>Форма</td>";
s += "</tr>";
// **************************
// * тестовое SMS-сообщение *
// **************************
s += "<tr>";
// №
s += "<td>0</td>";
// тип
s += "<td>";
if (iTuningIconSize == 16)
s += "<img src=\"/images/16x16/appointment-soon.png\" title=\"Тестовое SMS-сообщение\" border=0>";
else
s += "<img src=\"/images/24x24/appointment-soon.png\" title=\"Тестовое SMS-сообщение\" border=0>";
s += "</td>";
// статус
s += "<td>";
if (config.bSmsCreatePausedType0)
{
if (iTuningIconSize == 16)
s += "<img src=\"/images/16x16/agt_resume.png\" title=\"Пауза при создании\" border=0>";
else
s += "<img src=\"/images/24x24/agt_resume.png\" title=\"Пауза при создании\" border=0>";
}
s += "</td>";
// форма
s += "<td><form action=\"/sms_test_accept\" method=post>";
s += "Тестовое SMS-сообщение, номер: <input type=text name=sms_phone size=20 maxlength=20 value=\"\">";
s += ", <nobr>текст: <input type=text name=sms_text size=40 maxlength=256 value=\"\">";
// получаем номер транзакции и передаём его в скрытых параметрах
iAction = actions->fnAdd();
s += "<input type=hidden name=action value=\"";
sprintf(szTmp,"%i",iAction);
s += szTmp;
s += "\">";
s += " <input type=submit value=\"Отправить\"></nobr></form></td>";
s += "</tr>";
// **********************
// * выдача результатов *
// **********************
s += "<tr>";
// №
s += "<td>1</td>";
// тип
s += "<td>";
if (iTuningIconSize == 16)
s += "<img src=\"/images/16x16/edit-paste.png\" title=\"Выдача результатов\" border=0>";
else
s += "<img src=\"/images/24x24/edit-paste.png\" title=\"Выдача результатов\" border=0>";
s += "</td>";
// статус
s += "<td>";
if (config.bSmsCreatePausedType1)
{
if (iTuningIconSize == 16)
s += "<img src=\"/images/16x16/agt_resume.png\" title=\"Пауза при создании\" border=0>";
else
s += "<img src=\"/images/24x24/agt_resume.png\" title=\"Пауза при создании\" border=0>";
}
s += "</td>";
// форма
s += "<td>";
s += "<div>Форма для создания SMS-сообщений о готовности результатов не существует. \
Такие сообщения создаются автоматически планировщиком выдачи результатов.</div>";
s += "<div>Текст сообщения планировщика выдачи результатов (текущий):</div>";
s += "<div><i>";
s += config.szSmsGivingResults;
s += "</i></div>";
s += "</td>";
s += "</tr>";
// *****************************************
// * рассылка поздравлений с днём рождения *
// *****************************************
s += "<tr>";
// №
s += "<td>2</td>";
// тип
s += "<td>";
if (iTuningIconSize == 16)
s += "<img src=\"/images/16x16/face-smile.png\" title=\"Поздравление с днём рождения\" border=0>";
else
s += "<img src=\"/images/24x24/face-smile.png\" title=\"Поздравление с днём рождения\" border=0>";
s += "</td>";
// статус
s += "<td>";
if (config.bSmsCreatePausedType2)
{
if (iTuningIconSize == 16)
s += "<img src=\"/images/16x16/agt_resume.png\" title=\"Пауза при создании\" border=0>";
else
s += "<img src=\"/images/24x24/agt_resume.png\" title=\"Пауза при создании\" border=0>";
}
s += "</td>";
// форма
s += "<td>";
s += "<div><form action=\"/sms_birthday_accept\" method=post>";
s += "Поздравления с днём рождения:";
query->dst->fnAddLine(s.c_str());
fnSelectDate(query,0,szToday);
// получаем номер транзакции и передаём его в скрытых параметрах
iAction = actions->fnAdd();
s += "<input type=hidden name=action value=\"";
sprintf(szTmp,"%i",iAction);
s += szTmp;
s += "\">";
s = "<input type=submit value=\"Разослать\"></form></div>";
s += "<div>Текст поздравления с днём рождения (текущий):</div>";
s += "<div><i>";
s += config.szSmsBirthday;
s += "</i></div>";
s += "</td>";
s += "</tr>";
// ***********************
// * информация клиентам *
// ***********************
s += "<tr>";
// №
s += "<td>3</td>";
// тип
s += "<td>";
if (iTuningIconSize == 16)
s += "<img src=\"/images/16x16/attach.png\" title=\"Информация клиентам\" border=0>";
else
s += "<img src=\"/images/24x24/attach.png\" title=\"Информация клиентам\" border=0>";
s += "</td>";
// статус
s += "<td>";
if (config.bSmsCreatePausedType3)
{
if (iTuningIconSize == 16)
s += "<img src=\"/images/16x16/agt_resume.png\" title=\"Пауза при создании\" border=0>";
else
s += "<img src=\"/images/24x24/agt_resume.png\" title=\"Пауза при создании\" border=0>";
}
s += "</td>";
// форма
s += "<td><form action=\"/sms_info_accept\" method=post>";
s += "Рассылка информации клиентам: период с";
query->dst->fnAddLine(s.c_str());
// дата 1
fnSelectDate(query,"from_",szToday);
query->dst->fnAddLine("по");
// дата 2
fnSelectDate(query,"to_",szToday);
query->dst->fnAddLine(", <nobr>группа");
fnServicesGroupsSelectFilter(query,-1);
s = "</nobr>, <nobr>текст: <input type=text name=sms_text size=40 maxlength=256 value=\"\">";
// получаем номер транзакции и передаём его в скрытых параметрах
iAction = actions->fnAdd();
s += "<input type=hidden name=action value=\"";
sprintf(szTmp,"%i",iAction);
s += szTmp;
s += "\">";
s += " <input type=submit value=\"Разослать\"></nobr></form></td>";
s += "</tr>";
s += "</table></p>";
query->dst->fnAddLine(s.c_str());
fnFormEnd(query);
}
void fnAppSmsActionAccept(QUERY *query)
{
#if defined(__WATCOMC__)
std::auto_ptr<ARGS_CHECK> check (new ARGS_CHECK("fnAppSmsActionAccept"));
#else
std::unique_ptr<ARGS_CHECK> check (new ARGS_CHECK("fnAppSmsActionAccept"));
#endif // defined
ARG_OPTIONS s_arg_options;
string s;
RING *args = query->args;
char sz [INI_MAX_LEXEM_LEN +1];
int iAction = 0;
int iSmsAction = 0;
int iQty;
int iCycle;
SMS s_sms;
bool bDelete;
int iCounter = 0;
char szTmp [20];
// action
check->fnSetArg(&s_arg_options,"action",true);
check->fnSetValueLen(&s_arg_options,1,8);
check->fnSetValueValidChars(&s_arg_options,ARG_DIGITS);
check->fnAdd(&s_arg_options);
// sms_action
check->fnSetArg(&s_arg_options,"sms_action",true);
check->fnSetValueLen(&s_arg_options,1,2);
check->fnSetValueValidChars(&s_arg_options,ARG_DIGITS);
check->fnAdd(&s_arg_options);
switch(check->fnCheckDebug(s,args)) // контроль аргументов
{
case ARGS_CHECK_RESULT_ERROR_CRITICAL:
// fnAppErrorArgument(query,s.c_str());
return;
case ARGS_CHECK_RESULT_ERROR:
case ARGS_CHECK_RESULT_MESSAGE:
break;
}
while (args->fnGetQty())
{
args->fnPop(sz);
if (! strcmp(sz,"action"))
{
args->fnPop(sz);
iAction = atoi(sz);
continue;
}
if (! strcmp(sz,"sms_action"))
{
args->fnPop(sz);
iSmsAction = atoi(sz);
continue;
}
}
// проверяем, выполнена ли транзакция
if (actions->fnCheck(iAction))
return;
switch (iSmsAction)
{
// *****************************************
// * раздел "Групповые операции обработки" *
// *****************************************
case 1: // снять паузу с SMS-сообщений типа 0 (тестовые сообщения)
iQty = sms->fnGetQty();
for (iCycle = 0; iCycle < iQty; iCycle++)
{
sms->fnPop((char *) &s_sms,iCycle); // неразрушающее чтение
if (s_sms.iType != 0)
continue;
if (s_sms.bPaused == false)
continue;
s_sms.bPaused = false;
sms->fnReplace((char *) &s_sms,iCycle,sizeof (SMS)); // заменяем запись в кольце
iCounter++;
}
s = "Снятие паузы с SMS-сообщений типа 0 (тестовые сообщения). Снято с паузы";
sprintf(szTmp,": %i.",iCounter);
s += szTmp;
fnCreateErrorMessage(query,2,3,s.c_str());
break;
case 2: // снять паузу с SMS-сообщений типа 1 (сообщения планировщика выдачи результатов)
iQty = sms->fnGetQty();
for (iCycle = 0; iCycle < iQty; iCycle++)
{
sms->fnPop((char *) &s_sms,iCycle); // неразрушающее чтение
if (s_sms.iType != 1)
continue;
if (s_sms.bPaused == false)
continue;
s_sms.bPaused = false;
sms->fnReplace((char *) &s_sms,iCycle,sizeof (SMS)); // заменяем запись в кольце
iCounter++;
}
s = "Снятие паузы с SMS-сообщений типа 1 (сообщения планировщка выдачи результатов). Снято с паузы";
sprintf(szTmp,": %i.",iCounter);
s += szTmp;
fnCreateErrorMessage(query,2,3,s.c_str());
break;
case 3: // снять паузу с SMS-сообщений типа 2 (поздравления с днём рождения)
iQty = sms->fnGetQty();
for (iCycle = 0; iCycle < iQty; iCycle++)
{
sms->fnPop((char *) &s_sms,iCycle); // неразрушающее чтение
if (s_sms.iType != 2)
continue;
if (s_sms.bPaused == false)
continue;
s_sms.bPaused = false;
sms->fnReplace((char *) &s_sms,iCycle,sizeof (SMS)); // заменяем запись в кольце
iCounter++;
}
s = "Снятие паузы с SMS-сообщений типа 2 (поздравления с днём рождения). Снято с паузы";
sprintf(szTmp,": %i.",iCounter);
s += szTmp;
fnCreateErrorMessage(query,2,3,s.c_str());
break;
case 4: // снять паузу с SMS-сообщений типа 3 (информационные сообщения)
iQty = sms->fnGetQty();
for (iCycle = 0; iCycle < iQty; iCycle++)
{
sms->fnPop((char *) &s_sms,iCycle); // неразрушающее чтение
if (s_sms.iType != 3)
continue;
if (s_sms.bPaused == false)
continue;
s_sms.bPaused = false;
sms->fnReplace((char *) &s_sms,iCycle,sizeof (SMS)); // заменяем запись в кольце
iCounter++;
}
s = "Снятие паузы с SMS-сообщений типа 3 (информационные сообщения). Снято с паузы";
sprintf(szTmp,": %i.",iCounter);
s += szTmp;
fnCreateErrorMessage(query,2,3,s.c_str());
break;
case 9: // поставить на паузу SMS-сообщения с шагом доставки 0
iQty = sms->fnGetQty();
for (iCycle = 0; iCycle < iQty; iCycle++)
{
sms->fnPop((char *) &s_sms,iCycle); // неразрушающее чтение
if (s_sms.iStep != 0)
continue;
if (s_sms.bPaused == true)
continue;
s_sms.bPaused = true;
sms->fnReplace((char *) &s_sms,iCycle,sizeof (SMS)); // заменяем запись в кольце
iCounter++;
}
s = "Постановка на паузу SMS-сообщений с шагом доставки 0. Поставлено на паузу";
sprintf(szTmp,": %i.",iCounter);
s += szTmp;
fnCreateErrorMessage(query,2,3,s.c_str());
break;
// ****************************************
// * раздел "Групповые операции удаления" *
// ****************************************
case 5: // удалить отправленные SMS-сообщения
iQty = sms->fnGetQty();
for (iCycle = 0; iCycle < iQty; iCycle++)
{
sms->fnPop((char *) &s_sms); // разрушающее чтение
if (s_sms.bSuccess == false)
sms->fnPush((char *) &s_sms,sizeof (SMS)); // возвращаем запись в кольцо
else
iCounter++;
}
s = "Удаление отправленных SMS-сообщений. Удалено";
sprintf(szTmp,": %i.",iCounter);
s += szTmp;
fnCreateErrorMessage(query,2,3,s.c_str());
break;
case 6: // удалить неотправленные SMS-сообщения
iQty = sms->fnGetQty();
for (iCycle = 0; iCycle < iQty; iCycle++)
{
sms->fnPop((char *) &s_sms); // разрушающее чтение
if (s_sms.bSuccess == true)
sms->fnPush((char *) &s_sms,sizeof (SMS)); // возвращаем запись в кольцо
else
iCounter++;
}
s = "Удаление неотправленных SMS-сообщений. Удалено";
sprintf(szTmp,": %i.",iCounter);
s += szTmp;
fnCreateErrorMessage(query,2,3,s.c_str());
break;
case 7: // удалить SMS-сообщения, обработка которых завершена
iQty = sms->fnGetQty();
for (iCycle = 0; iCycle < iQty; iCycle++)
{
sms->fnPop((char *) &s_sms); // разрушающее чтение
if (s_sms.bCompleted == false)
sms->fnPush((char *) &s_sms,sizeof (SMS)); // возвращаем запись в кольцо
else
iCounter++;
}
s = "Удаление SMS-сообщений, обработка которых завершена. Удалено";
sprintf(szTmp,": %i.",iCounter);
s += szTmp;
fnCreateErrorMessage(query,2,3,s.c_str());
break;
case 8: // удалить все SMS-сообщения
iCounter = sms->fnGetQty();
sms->fnClear();
s = "Удаление всех SMS-сообщений. Удалено";
sprintf(szTmp,": %i.",iCounter);
s += szTmp;
fnCreateErrorMessage(query,2,3,s.c_str());
break;
case 10: // удалить SMS-сообщения типа 0 (тестовые сообщения), с шагом доставки 0
iQty = sms->fnGetQty();
for (iCycle = 0; iCycle < iQty; iCycle++)
{
sms->fnPop((char *) &s_sms); // разрушающее чтение
bDelete = false;
do
{
if (s_sms.iType != 0)
continue;
if (s_sms.iStep != 0)
continue;
bDelete = true;
} while (false);
if (! bDelete)
sms->fnPush((char *) &s_sms,sizeof (SMS)); // возвращаем запись в кольцо
else
iCounter++;
}
s = "Удаление SMS-сообщений типа 0 (тестовые сообщения), с шагом доставки 0. Удалено";
sprintf(szTmp,": %i.",iCounter);
s += szTmp;
fnCreateErrorMessage(query,2,3,s.c_str());
break;
case 11: // удалить SMS-сообщения типа 1 (сообщения планировщика выдачи результатов), с шагом доставки 0
iQty = sms->fnGetQty();
for (iCycle = 0; iCycle < iQty; iCycle++)
{
sms->fnPop((char *) &s_sms); // разрушающее чтение
bDelete = false;
do
{
if (s_sms.iType != 1)
continue;
if (s_sms.iStep != 0)
continue;
bDelete = true;
} while (false);
if (! bDelete)
sms->fnPush((char *) &s_sms,sizeof (SMS)); // возвращаем запись в кольцо
else
iCounter++;
}
s = "Удаление SMS-сообщений типа 1 (сообщения планировщика выдачи результатов), с шагом доставки 0. Удалено";
sprintf(szTmp,": %i.",iCounter);
s += szTmp;
fnCreateErrorMessage(query,2,3,s.c_str());
break;
case 12: // удалить SMS-сообщения типа 2 (поздравления с днём рождения), с шагом доставки 0
iQty = sms->fnGetQty();
for (iCycle = 0; iCycle < iQty; iCycle++)
{
sms->fnPop((char *) &s_sms); // разрушающее чтение
bDelete = false;
do
{
if (s_sms.iType != 2)
continue;
if (s_sms.iStep != 0)
continue;
bDelete = true;
} while (false);
if (! bDelete)
sms->fnPush((char *) &s_sms,sizeof (SMS)); // возвращаем запись в кольцо
else
iCounter++;
}
s = "Удаление SMS-сообщений типа 2 (поздравления с днём рождения), с шагом доставки 0. Удалено";
sprintf(szTmp,": %i.",iCounter);
s += szTmp;
fnCreateErrorMessage(query,2,3,s.c_str());
break;
case 13: // удалить SMS-сообщения типа 3 (информационные сообщения), с шагом доставки 0
iQty = sms->fnGetQty();
for (iCycle = 0; iCycle < iQty; iCycle++)
{
sms->fnPop((char *) &s_sms); // разрушающее чтение
bDelete = false;
do
{
if (s_sms.iType != 3)
continue;
if (s_sms.iStep != 0)
continue;
bDelete = true;
} while (false);
if (! bDelete)
sms->fnPush((char *) &s_sms,sizeof (SMS)); // возвращаем запись в кольцо
else
iCounter++;
}
s = "Удаление SMS-сообщений типа 3 (информационные сообщения), с шагом доставки 0. Удалено";
sprintf(szTmp,": %i.",iCounter);
s += szTmp;
fnCreateErrorMessage(query,2,3,s.c_str());
break;
}
}
/*
const int SMS_VERSION = 4;
struct SMS
{
int iVersion;
int iId; // идентификатор
// тип:
// 0 - тест
// 1 - выдача результатов
// 2 - поздравление с днём рождения
// 3 - рассылка информации клиентам
int iType;
int iStep; // шаг обработки
// время создания записи
union
{
FILETIME ft_create;
__int64 time64_create;
};
char szDate [11]; // дата создания
char szTime [5 +1]; // время создания
char szPrefix [WS_MAX_NAME_LEN +1]; // префикс отправителя
char szPhone [11 +1]; // номер телефона получателя в формате 71234567890
char szText [256 +1]; // текст сообщения в кодировке 1251
int iClientNum; // тип 1,2,3; уникальный номер клиента
int iContractNum; // тип 1: номер документа
char szContractDate [11]; // тип 1: дата оформления документа
bool bAction; // обработка начата
// время последней обработки
union
{
FILETIME ft_action;
__int64 time64_action;
};
char szStepTime [5 +1];
// ответ сервиса
char szServiceAnswer [64 +1];
int iSmsNum; // идентификатор сообщения
bool bError; // ошибка, ожидание
bool bCompleted; // операции завершены
bool bSuccess; // успешно
int iGate; // используемый шлюз (0 - не выбран)
int iErrorCode; // 1000sms.ru
bool bPaused; // пауза в обработке сообщения
};
*/
static bool fnSearchBirthdaySms(int iClientNum)
{
int iQty;
int iCycle;
SMS s_sms;
iQty = sms->fnGetQty();
for (iCycle = 0; iCycle < iQty; iCycle++)
{
sms->fnPop((char *) &s_sms,iCycle);
if ((s_sms.iType == 2) // поздравление с днём рождения
&& (s_sms.iClientNum == iClientNum))
return true;
}
return false;
}
void fnAppSmsBirthdayAccept(QUERY *query)
{
#if defined(__WATCOMC__)
std::auto_ptr<ARGS_CHECK> check (new ARGS_CHECK("fnAppSmsBirthdayAccept"));
#else
std::unique_ptr<ARGS_CHECK> check (new ARGS_CHECK("fnAppSmsBirthdayAccept"));
#endif // defined
ARG_OPTIONS s_arg_options;
string s;
RING *args = query->args;
char sz [INI_MAX_LEXEM_LEN +1];
int iAction = 0;
int iDay = 0;
int iMonth = 0;
int iCycle;
int iClientNum;
int iCounter;
char szTmp [20];
// action
check->fnSetArg(&s_arg_options,"action",true);
check->fnSetValueLen(&s_arg_options,1,8);
check->fnSetValueValidChars(&s_arg_options,ARG_DIGITS);
check->fnAdd(&s_arg_options);
// day
check->fnSetArg(&s_arg_options,"day",true);
check->fnSetValueLen(&s_arg_options,1,2);
check->fnSetValueValidChars(&s_arg_options,ARG_DIGITS);
check->fnAdd(&s_arg_options);
// month
check->fnSetArg(&s_arg_options,"month",true);
check->fnSetValueLen(&s_arg_options,1,2);
check->fnSetValueValidChars(&s_arg_options,ARG_DIGITS);
check->fnAdd(&s_arg_options);
// year
check->fnSetArg(&s_arg_options,"year",true);
check->fnSetValueLen(&s_arg_options,4,4);
check->fnSetValueValidChars(&s_arg_options,ARG_DIGITS);
check->fnAdd(&s_arg_options);
switch(check->fnCheckDebug(s,args)) // контроль аргументов
{
case ARGS_CHECK_RESULT_ERROR_CRITICAL:
// fnAppErrorArgument(query,s.c_str());
return;
case ARGS_CHECK_RESULT_ERROR:
case ARGS_CHECK_RESULT_MESSAGE:
break;
}
while (args->fnGetQty())
{
args->fnPop(sz);
if (! strcmp(sz,"action"))
{
args->fnPop(sz);
iAction = atoi(sz);
continue;
}
if (! strcmp(sz,"day"))
{
args->fnPop(sz);
iDay = atoi(sz);
continue;
}
if (! strcmp(sz,"month"))
{
args->fnPop(sz);
iMonth = atoi(sz);
continue;
}
if (! strcmp(sz,"year"))
{
args->fnPop(sz);
// не используется, поэтому не сохраняем
continue;
}
}
// проверяем, выполнена ли транзакция
if (actions->fnCheck(iAction))
return;
// цикл с единицы, т.к. нулевой клиент - Анонимный
for (iCycle = 1; iCycle < iClientsQty; iCycle++)
{
// пропускаем удалённые записи
if (client [iCycle]->fnGetDelete())
continue;
if (client [iCycle]->fnGetBanOnSMS())
continue;
// if (! client [iCycle]->fnGetConsentToReceiveSMS())
// continue;
// пропускаем клиентов с некорректной датой рождения
if (! fnCheckDate(client [iCycle]->fnGetBirthday()))
continue;
// пропускаем клиентов, которые родились в другой день
if ((fnGetDay(client [iCycle]->fnGetBirthday()) != iDay)
|| (fnGetMonth(client [iCycle]->fnGetBirthday()) != iMonth))
continue;
iClientNum = client [iCycle]->fnGetNum();
// пропускаем клиентов, для которых есть поздравления в базе sms-сообщений
if (fnSearchBirthdaySms(iClientNum))
continue;
// пытаемся отправить sms
if (fnSendSmsBirthday(query,iClientNum))
iCounter++;
}
s = "Рассылка поздравлений с днём рождения. Сообщений";
sprintf(szTmp,": %i.",iCounter);
s += szTmp;
fnCreateErrorMessage(query,2,4,s.c_str());
}
void fnAppSmsEdit(QUERY *query)
{
#if defined(__WATCOMC__)
std::auto_ptr<ARGS_CHECK> check (new ARGS_CHECK("fnAppSmsEdit"));
#else
std::unique_ptr<ARGS_CHECK> check (new ARGS_CHECK("fnAppSmsEdit"));
#endif // defined
ARG_OPTIONS s_arg_options;
string s;
RING *args = query->args;
char sz [INI_MAX_LEXEM_LEN +1];
int iSmsId = 0;
int iQty;
int iCycle;
SMS s_sms;
bool bFound = false;
char szTmp [20];
int iClient;
char szClientFIO [100]; // для вывода FIO
// sms_id
check->fnSetArg(&s_arg_options,"sms_id",true);
check->fnSetValueLen(&s_arg_options,1,6);
check->fnSetValueValidChars(&s_arg_options,ARG_DIGITS);
check->fnAdd(&s_arg_options);
switch(check->fnCheckDebug(s,args)) // контроль аргументов
{
case ARGS_CHECK_RESULT_ERROR_CRITICAL:
fnAppErrorArgument(query,s.c_str());
return;
case ARGS_CHECK_RESULT_ERROR:
case ARGS_CHECK_RESULT_MESSAGE:
break;
}
while (args->fnGetQty())
{
args->fnPop(sz);
if (! strcmp(sz,"sms_id"))
{
args->fnPop(sz);
iSmsId = atoi(sz);
continue;
}
}
// поиск SMS-сообщения
iQty = sms->fnGetQty();
for (iCycle = 0; iCycle < iQty; iCycle++)
{
sms->fnPop((char *) &s_sms,iCycle);
if (s_sms.iId == iSmsId)
{
bFound = true;
break;
}
}
if (! bFound)
return;
fnFormContent(query);
query->dst->fnAddLine("<p>Редактирование SMS-сообщения</p>");
s = "<form action=\"/sms_edit_accept\" method=post><table border=0>";
// id
s += "<tr><td>id:</td><td>";
sprintf(szTmp,"%i",s_sms.iId);
s += szTmp;
s += "</td></tr>";
// тип
s += "<tr><td>Тип:</td><td>";
switch (s_sms.iType)
{
case 0: s += "Тестовое SMS-сообщение"; break;
case 1: s += "Выдача результатов"; break;
case 2: s += "Поздравление с днём рождения"; break;
}
s += "</td></tr>";
// пауза
s += "<tr><td>Пауза:</td><td><input type=checkbox name=paused value=\"1\"";
if (s_sms.bPaused)
s += " checked";
s += "></td></tr>";
// используемый шлюз
s += "<tr><td>Используемый шлюз:</td><td>";
switch (s_sms.iGate)
{
case SMS_GATE_1000: s += "1000sms.ru"; break;
case SMS_GATE_AERO: s += "smsaero.ru"; break;
default:
sprintf(szTmp,"%i",s_sms.iGate);
s += szTmp;
}
s += "</td></tr>";
// шаг обработки
s += "<tr><td>Шаг обработки:</td><td>";
sprintf(szTmp,"%i",s_sms.iStep);
s += szTmp;
s += "</td></tr>";
// повторить обработку
s += "<tr><td>Повторить обработку:</td><td><input type=checkbox name=restart value=\"1\"></td></tr>";
// дата
s += "<tr><td>Дата:</td><td>";
s += s_sms.szDate;
s += "</td></tr>";
// время
s += "<tr><td>Время:</td><td>";
s += s_sms.szTime;
s += "</td></tr>";
// префикс отправителя
s += "<tr><td>Префикс отправителя:</td><td>";
s += s_sms.szPrefix;
s += "</td></tr>";
// клиент
switch (s_sms.iType)
{
case 1:
case 2:
case 3:
s += "<tr><td>Клиент:</td><td>";
iClient = fnClientSearchByNum(s_sms.iClientNum);
if (iClient == -1)
{
fnAppErrorArgument(query);
return;
}
sprintf(szClientFIO,"%s %s %s",
client [iClient]->fnGetFamily(),
client [iClient]->fnGetName(),
client [iClient]->fnGetName2());
s += szClientFIO;
s += "</td></tr>";
}
// номер телефона получателя
s += "<tr><td>Номер телефона:</td><td>";
s += s_sms.szPhone;
s += "</td></tr>";
// текст сообщения
s += "<tr><td>Текст сообщения:</td><td>";
s += s_sms.szText;
s += "</td></tr>";
// отменить обработку
s += "<tr><td>Отменить обработку:</td><td><input type=checkbox name=stop value=\"1\"></td></tr>";
// операции завершены
s += "<tr><td>Операции завершены:</td><td>";
if (s_sms.bCompleted)
s += "Да";
s += "</td></tr>";
// результат
s += "<tr><td>Успешно:</td><td>";
if (s_sms.bSuccess)
s += "Да";
else
s += "Нет";
s += "</td></tr>";
// код ошибки iErrorCode
do
{
if (s_sms.iGate == SMS_GATE_AERO)
continue;
s += "<tr><td>Код ошибки:</td><td>";
sprintf(szTmp,"%i",s_sms.iErrorCode);
s += szTmp;
s += "</td></tr>";
} while (false);
// в скрытых параметрах id
s += "<tr><td><input type=hidden name=sms_id value=\"";
sprintf(szTmp,"%i",s_sms.iId);
s += szTmp;
s += "\"></td><td><input type=submit value=\"Применить\"></td></tr>";
s += "</table></form>";
query->dst->fnAddLine(s.c_str ());
fnFormEnd(query);
}
void fnAppSmsEditAccept(QUERY *query)
{
#if defined(__WATCOMC__)
std::auto_ptr<ARGS_CHECK> check (new ARGS_CHECK("fnAppSmsEditAccept"));
#else
std::unique_ptr<ARGS_CHECK> check (new ARGS_CHECK("fnAppSmsEditAccept"));
#endif // defined
ARG_OPTIONS s_arg_options;
string s;
RING *args = query->args;
char sz [INI_MAX_LEXEM_LEN +1];
bool bPaused = false;
bool bRestart = false;
int iSmsId = 0;
bool bStop = false;
int iQty;
int iCycle;
SMS s_sms;
bool bReplace = false;
// paused
check->fnSetArg(&s_arg_options,"paused",false);
check->fnSetValueLen(&s_arg_options,1,1);
check->fnSetValueValidChars(&s_arg_options,0,"1");
check->fnAdd(&s_arg_options);
// restart
check->fnSetArg(&s_arg_options,"restart",false);
check->fnSetValueLen(&s_arg_options,1,1);
check->fnSetValueValidChars(&s_arg_options,0,"1");
check->fnAdd(&s_arg_options);
// sms_id
check->fnSetArg(&s_arg_options,"sms_id",true);
check->fnSetValueLen(&s_arg_options,1,6);
check->fnSetValueValidChars(&s_arg_options,ARG_DIGITS);
check->fnAdd(&s_arg_options);
// stop
check->fnSetArg(&s_arg_options,"stop",false);
check->fnSetValueLen(&s_arg_options,1,1);
check->fnSetValueValidChars(&s_arg_options,0,"1");
check->fnAdd(&s_arg_options);
switch(check->fnCheckDebug(s,args)) // контроль аргументов
{
case ARGS_CHECK_RESULT_ERROR_CRITICAL:
// fnAppErrorArgument(query,s.c_str());
return;
case ARGS_CHECK_RESULT_ERROR:
case ARGS_CHECK_RESULT_MESSAGE:
break;
}
while (args->fnGetQty())
{
args->fnPop(sz);
if (! strcmp(sz,"paused"))
{
args->fnPop(sz);
bPaused = true;
continue;
}
if (! strcmp(sz,"restart"))
{
args->fnPop(sz);
bRestart = true;
continue;
}
if (! strcmp(sz,"sms_id"))
{
args->fnPop(sz);
iSmsId = atoi(sz);
continue;
}
if (! strcmp(sz,"stop"))
{
args->fnPop(sz);
bStop = true;
continue;
}
}
iQty = sms->fnGetQty();
for (iCycle = 0; iCycle < iQty; iCycle++)
{
sms->fnPop((char *) &s_sms,iCycle);
if (s_sms.iId == iSmsId)
{
if (s_sms.bPaused != bPaused)
{
bReplace = true;
s_sms.bPaused = bPaused;
}
if (bRestart)
{
bReplace = true;
s_sms.iStep = 0;
s_sms.bAction = false;
*s_sms.szServiceAnswer = 0;
s_sms.iSmsNum = 0;
s_sms.bError = false;
s_sms.bCompleted = false;
s_sms.bSuccess = false;
s_sms.iGate = 0;
}
if (bStop)
{
bReplace = true;
s_sms.bCompleted = true;
}
if (bReplace)
sms->fnReplace((char *) &s_sms,iCycle,sizeof (SMS));
break;
}
}
}
void fnAppSmsFilterAccept(QUERY *query)
{
#if defined(__WATCOMC__)
std::auto_ptr<ARGS_CHECK> check (new ARGS_CHECK("fnAppSmsFilterAccept"));
#else
std::unique_ptr<ARGS_CHECK> check (new ARGS_CHECK("fnAppSmsFilterAccept"));
#endif // defined
ARG_OPTIONS s_arg_options;
string s;
RING *args = query->args;
char sz [INI_MAX_LEXEM_LEN +1];
int iDays = 7;
char szTmp [20];
// days
check->fnSetArg(&s_arg_options,"days",true);
check->fnSetValueLen(&s_arg_options,1,2);
check->fnSetValueValidChars(&s_arg_options,ARG_DIGITS);
check->fnAdd(&s_arg_options);
switch(check->fnCheckDebug(s,args)) // контроль аргументов
{
case ARGS_CHECK_RESULT_ERROR_CRITICAL:
// fnAppErrorArgument(query,s.c_str());
return;
case ARGS_CHECK_RESULT_ERROR:
case ARGS_CHECK_RESULT_MESSAGE:
break;
}
while (args->fnGetQty())
{
args->fnPop(sz);
if (! strcmp(sz,"days"))
{
args->fnPop(sz);
iDays = atoi(sz);
continue;
}
}
// загружаем параметры фильтра в ассоциативный массив
sprintf(szTmp,"%i",iDays);
login_days->fnAdd(query->szLogin,szTmp);
}
void fnAppSmsInfoAccept(QUERY *query)
{
#if defined(__WATCOMC__)
std::auto_ptr<ARGS_CHECK> check (new ARGS_CHECK("fnAppSmsInfoAccept"));
#else
std::unique_ptr<ARGS_CHECK> check (new ARGS_CHECK("fnAppSmsInfoAccept"));
#endif // defined
ARG_OPTIONS s_arg_options;
string s;
RING *args = query->args;
char sz [INI_MAX_LEXEM_LEN +1];
int iAction = 0;
int iDay1 = 0;
int iMonth1 = 0;
int iYear1 = 0;
char szGroupId [2 +1];
char szText [256 +1] = "";
int iDay2 = 0;
int iMonth2 = 0;
int iYear2 = 0;
int iGroupId = 0;
char szDate1 [11];
char szDate2 [11];
int iCycle;
int iClientNum;
#if defined(__WATCOMC__)
std::auto_ptr<A_KEY_INT> clients_nums (new A_KEY_INT("fnAppSmsInfoAccept(QUERY *): clients_nums",16*1024));
#else
std::unique_ptr<A_KEY_INT> clients_nums (new A_KEY_INT("fnAppSmsInfoAccept(QUERY *): clients_nums",16*1024));
#endif // defined
int iQty;
int iCounter = 0;
char szTmp [20];
// action
check->fnSetArg(&s_arg_options,"action",true);
check->fnSetValueLen(&s_arg_options,1,8);
check->fnSetValueValidChars(&s_arg_options,ARG_DIGITS);
check->fnAdd(&s_arg_options);
// from_day
check->fnSetArg(&s_arg_options,"from_day",true);
check->fnSetValueLen(&s_arg_options,1,2);
check->fnSetValueValidChars(&s_arg_options,ARG_DIGITS);
check->fnAdd(&s_arg_options);
// from_month
check->fnSetArg(&s_arg_options,"from_month",true);
check->fnSetValueLen(&s_arg_options,1,2);
check->fnSetValueValidChars(&s_arg_options,ARG_DIGITS);
check->fnAdd(&s_arg_options);
// from_year
check->fnSetArg(&s_arg_options,"from_year",true);
check->fnSetValueLen(&s_arg_options,4,4);
check->fnSetValueValidChars(&s_arg_options,ARG_DIGITS);
check->fnAdd(&s_arg_options);
// group
check->fnSetArg(&s_arg_options,"group",true);
check->fnSetValueLen(&s_arg_options,1,2);
check->fnSetValueValidChars(&s_arg_options,ARG_DIGITS);
check->fnAdd(&s_arg_options);
// sms_text
check->fnSetArg(&s_arg_options,"sms_text",true);
check->fnSetValueLen(&s_arg_options,0,256);
check->fnAdd(&s_arg_options);
// to_day
check->fnSetArg(&s_arg_options,"to_day",true);
check->fnSetValueLen(&s_arg_options,1,2);
check->fnSetValueValidChars(&s_arg_options,ARG_DIGITS);
check->fnAdd(&s_arg_options);
// to_month
check->fnSetArg(&s_arg_options,"to_month",true);
check->fnSetValueLen(&s_arg_options,1,2);
check->fnSetValueValidChars(&s_arg_options,ARG_DIGITS);
check->fnAdd(&s_arg_options);
// to_year
check->fnSetArg(&s_arg_options,"to_year",true);
check->fnSetValueLen(&s_arg_options,4,4);
check->fnSetValueValidChars(&s_arg_options,ARG_DIGITS);
check->fnAdd(&s_arg_options);
switch(check->fnCheckDebug(s,args)) // контроль аргументов
{
case ARGS_CHECK_RESULT_ERROR_CRITICAL:
// fnAppErrorArgument(query,s.c_str());
return;
case ARGS_CHECK_RESULT_ERROR:
case ARGS_CHECK_RESULT_MESSAGE:
break;
}
while (args->fnGetQty())
{
args->fnPop(sz);
if (! strcmp(sz,"action"))
{
args->fnPop(sz);
iAction = atoi(sz);
continue;
}
if (! strcmp(sz,"from_day"))
{
args->fnPop(sz);
iDay1 = atoi(sz);
continue;
}
if (! strcmp(sz,"from_month"))
{
args->fnPop(sz);
iMonth1 = atoi(sz);
continue;
}
if (! strcmp(sz,"from_year"))
{
args->fnPop(sz);
iYear1 = atoi(sz);
continue;
}
if (! strcmp(sz,"group"))
{
args->fnPop(szGroupId);
iGroupId = atoi(szGroupId);
continue;
}
if (! strcmp(sz,"sms_text"))
{
args->fnPop(szText);
continue;
}
if (! strcmp(sz,"to_day"))
{
args->fnPop(sz);
iDay2 = atoi(sz);
continue;
}
if (! strcmp(sz,"to_month"))
{
args->fnPop(sz);
iMonth2 = atoi(sz);
continue;
}
if (! strcmp(sz,"to_year"))
{
args->fnPop(sz);
iYear2 = atoi(sz);
continue;
}
}
sprintf(szDate1,"%02u/%02u/%04u",iDay1,iMonth1,iYear1);
sprintf(szDate2,"%02u/%02u/%04u",iDay2,iMonth2,iYear2);
fnNormalizeDate(szDate1);
fnNormalizeDate(szDate2);
// проверяем, выполнена ли транзакция
if (actions->fnCheck(iAction))
return;
if (fnCompareDate(szDate1,szDate2) > 0)
return;
if (! strlen(szText))
return;
// выбираем актуальные посещения
for (iCycle = 0; iCycle < iVisitsQty; iCycle++)
{
if (visit [iCycle]->fnGetDelete())
continue;
if (visit [iCycle]->fnGetPlannedTreatmentOnly())
continue;
if (! visit [iCycle]->fnGetClientNum()) // анонимный клиент
continue;
if (! fnCheckDateRange(szDate1,visit [iCycle]->fnGetDate (),szDate2))
continue;
if (visit [iCycle]->fnGetPreEntry())
continue;
// группа
if (iGroupId >= 0)
if (! fnServicesGroupsGetMember(visit [iCycle]->fnGetServiceType(),iGroupId))
continue;
// добавляем уникальный номер клиента в массив clients_found
iClientNum = visit [iCycle]->fnGetClientNum();
if (! clients_nums->fnCheck(iClientNum))
clients_nums->fnAdd(iClientNum);
}
iQty = clients_nums->fnGetQty();
if (iQty)
{
RING *buf;
int iClientNum;
int iClient;
buf = new RING("fnAppSmsInfoAccept(QUERY *): buf",16*1024);
clients_nums->fnCopyBuf(buf);
for (iCycle = 0; iCycle < iQty; iCycle++)
{
buf->fnPop((char *) &iClientNum,iCycle);
iClient = fnClientSearchByNum(iClientNum);
if (iClient == -1)
continue;
// пропускаем удалённые записи
if (client [iClient]->fnGetDelete())
continue;
if (client [iClient]->fnGetBanOnSMS())
continue;
if (! client [iClient]->fnGetConsentToReceiveSMS())
continue;
// помещаем SMS-сообщение в очередь для отправки
if (fnSendSmsInfo(query,iClientNum,szText))
iCounter++;
}
delete buf;
}
s = "Рассылка информации клиентам. Сообщений";
sprintf(szTmp,": %i.",iCounter);
s += szTmp;
fnCreateErrorMessage(query,2,5,s.c_str());
}
void fnAppSmsTestAccept(QUERY *query)
{
#if defined(__WATCOMC__)
std::auto_ptr<ARGS_CHECK> check (new ARGS_CHECK("fnAppSmsTestAccept"));
#else
std::unique_ptr<ARGS_CHECK> check (new ARGS_CHECK("fnAppSmsTestAccept"));
#endif // defined
ARG_OPTIONS s_arg_options;
string s;
RING *args = query->args;
char sz [INI_MAX_LEXEM_LEN +1];
int iAction = 0;
char szFederalPhone [11 +1];
bool bPhoneChecked = false;
char szText [256 +1] = "";
// action
check->fnSetArg(&s_arg_options,"action",true);
check->fnSetValueLen(&s_arg_options,1,8);
check->fnSetValueValidChars(&s_arg_options,ARG_DIGITS);
check->fnAdd(&s_arg_options);
// sms_phone
check->fnSetArg(&s_arg_options,"sms_phone",true);
check->fnSetValueLen(&s_arg_options,0,20);
check->fnSetValueValidChars(&s_arg_options,ARG_DIGITS);
check->fnAdd(&s_arg_options);
// sms_text
check->fnSetArg(&s_arg_options,"sms_text",true);
check->fnSetValueLen(&s_arg_options,0,256);
check->fnAdd(&s_arg_options);
switch(check->fnCheckDebug(s,args)) // контроль аргументов
{
case ARGS_CHECK_RESULT_ERROR_CRITICAL:
// fnAppErrorArgument(query,s.c_str());
return;
case ARGS_CHECK_RESULT_ERROR:
case ARGS_CHECK_RESULT_MESSAGE:
break;
}
while (args->fnGetQty())
{
args->fnPop(sz);
if (! strcmp(sz,"action"))
{
args->fnPop(sz);
iAction = atoi(sz);
continue;
}
if (! strcmp(sz,"sms_phone"))
{
args->fnPop(sz);
bPhoneChecked = fnGetPhone(szFederalPhone,sz);
continue;
}
if (! strcmp(sz,"sms_text"))
{
args->fnPop(szText);
continue;
}
}
// проверяем, выполнена ли транзакция
if (actions->fnCheck(iAction))
return;
if (! bPhoneChecked)
return;
if (! strlen(szText))
return;
// помещаем SMS-сообщение в очередь для отправки
fnSendSmsTest(query,szFederalPhone,szText);
}
|