#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" // fnGetToday ()
#include "other\md5.h"
#include "page_sms.h"
#include "page_tuning.h"
#include "pages.h"
#include "read_ini.h"
#include "s_date.h"
#include "s_forms.h"
#include "s_group.h"
#include "visit.h"
using namespace std;
using namespace md5;
// ассоциативные массивы
static std::auto_ptr<A_ARRAY> login_days (new A_ARRAY); // "имя входа/кол-во дней"
void fnCheckSms (void)
{
char szToday [11];
int iQty;
int iCycle;
SMS s_sms;
iQty = sms->fnGetQty ();
if (iQty)
fnGetToday (szToday);
for (iCycle = 0; iCycle < iQty; iCycle++)
{
sms->fnPop ((char *) &s_sms); // разрушающее чтение
// здесь производится проверка версии записи и при необходимости
// upgrade (инициализация дополнительных полей)
if (s_sms.iVersion != SMS_VERSION)
{
switch (s_sms.iVersion)
{
case 1:
s_sms.iGate = 0;
}
s_sms.iVersion = SMS_VERSION;
}
// возвращаем запись в кольцо, если не истёк срок её давности
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';
return true;
default: // не федеральный номер
*dst = 0;
return false;
}
}
// копирует в dst найденный в szPhones номер сотового телефона в формате 71234567890
bool fnGetPhone (char *dst,char *szPhones)
{
std::auto_ptr<RING> lexems (new RING (INI_MAX_LINE_LEN));
char sz [REG_NAME_LEN +1];
strcpy (sz,szPhones);
fnCharToComma (sz,'.'); // заменяем точки на запятые
// размещаем список телефонов в массив
fnGetLexems (lexems.get (),sz,0);
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-сообщение
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;
// инициализация
memset (&s_sms,0,sizeof (SMS));
s_sms.iVersion = SMS_VERSION;
s_sms.iId = fnGetNextId ();
s_sms.iGate = 0;
s_sms.iType = 1; // SMS-уведомление о готовности результатов
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));
}
// поздравление с днём рождения
void fnSendSmsBirthday (QUERY *query,int iClientNum)
{
int iClient = fnClientSearchByNum (iClientNum);
SMS s_sms;
SYSTEMTIME lt;
char szFederalPhone [11 +1];
if (iClient == -1)
return;
// инициализация
memset (&s_sms,0,sizeof (SMS));
s_sms.iVersion = SMS_VERSION;
s_sms.iId = fnGetNextId ();
s_sms.iGate = 0;
s_sms.iType = 2; // поздравление с днём рождения
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;
// текст сообщения
strcpy (s_sms.szText,config.szSmsBirthday);
s_sms.iClientNum = iClientNum; // клиент
// загрузка в очередь отправки
sms->fnPush ((char *) &s_sms,sizeof (SMS));
}
// информация клиентам
void fnSendSmsInfo (QUERY *query,int iClientNum,char *szText)
{
int iClient = fnClientSearchByNum (iClientNum);
SMS s_sms;
SYSTEMTIME lt;
char szFederalPhone [11 +1];
if (iClient == -1)
return;
// инициализация
memset (&s_sms,0,sizeof (SMS));
s_sms.iVersion = SMS_VERSION;
s_sms.iId = fnGetNextId ();
s_sms.iGate = 0;
s_sms.iType = 3; // рассылка информации клиентам
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;
// текст сообщения
strcpy (s_sms.szText,szText);
s_sms.iClientNum = iClientNum; // клиент
// загрузка в очередь отправки
sms->fnPush ((char *) &s_sms,sizeof (SMS));
}
/*
const int SMS_VERSION = 2;
struct SMS
{
int iVersion;
int iId; // идентификатор
// тип (0 - тест, 1 - выдача результатов, 2 - поздравление с днём
// рождения)
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]; // типы 0,1,2; номер телефона получателя в формате 71234567890
char szText [256 +1]; // типы 0,1,2; текст сообщения в кодировке 1251
int iClientNum; // тип 1,2; уникальный номер клиента
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; // типы 0,1,2; идентификатор сообщения
bool bError; // ошибка, ожидание
bool bCompleted; // операции завершены
bool bSuccess; // успешно
int iGate; // используемый шлюз (0 - не выбран)
};
extern std::auto_ptr<RING> sms;
*/
// *****************************************
// * функции отправки сообщений из очереди *
// *****************************************
// проверка получения
static bool fnCheckReceipt (char *chBuf,unsigned int uiLen)
{
char *chCopyBuf = new char [uiLen +1];
VDL_TEXT *answer = new VDL_TEXT;
bool bReceipt = false;
int iLinesQty;
int iCycle;
int iContentLen = 0;
bool bContentLenDefined = false;
int iLineLen;
int iHttpLen = 0;
bool bHttpLenDefined = false;
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))
{
bContentLenDefined = true;
iContentLen = atoi (answer->fnGetLine (iCycle)+15);
break;
}
if (! bContentLenDefined)
{
delete answer;
return bReceipt;
}
// подсчитываем размер заголовка
for (iCycle = 0; iCycle < iLinesQty; iCycle++)
{
iLineLen = answer->fnGetLineLen (iCycle);
iHttpLen += iLineLen +2;
if (! iLineLen) // заголовок принят полностью
{
bHttpLenDefined = true;
break;
}
}
delete answer;
if (! bHttpLenDefined)
return bReceipt;
if ((unsigned int) (iHttpLen+iContentLen) == uiLen)
bReceipt = true;
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;
}
void fnSmsAeroQueueExecuteSend (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 szSmsAeroUser [64+3 +1];
char szSmsAeroSenderName [20 +1];
char *szInfo;
switch (s_sms->iStep)
{
// **********************
// * передача сообщения *
// **********************
case 0:
// создаём сокет
client_socket = socket (AF_INET,SOCK_STREAM,0);
if (client_socket == 0 || client_socket == INVALID_SOCKET)
{
itoa (WSAGetLastError (),szTmp,10);
s = "fn=fnSmsAeroQueueExecuteSend() code=socket1 msg='socket error' error=";
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);
ReleaseSemaphore (hAppSem,1,NULL);
d_addr = gethostbyname ("gate.smsaero.ru");
// EnterCriticalSection (&app_cs);
WaitForSingleObject (hAppSem,INFINITE);
if (d_addr == NULL)
{
closesocket (client_socket);
s = "fn=fnSmsAeroQueueExecuteSend() 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);
ReleaseSemaphore (hAppSem,1,NULL);
iResult = connect (client_socket,(sockaddr *) &dest_addr,sizeof (dest_addr));
// EnterCriticalSection (&app_cs);
WaitForSingleObject (hAppSem,INFINITE);
if (iResult)
{
closesocket (client_socket);
itoa (WSAGetLastError (),szTmp,10);
s = "fn=fnSmsAeroQueueExecuteSend() code=connect1 msg='connect failed' error=";
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=fnSmsAeroQueueExecuteSend() 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 (szSmsAeroUser,sizeof (szSmsAeroUser) -1,
config.szSmsAeroEmail,"@","%40");
s += szSmsAeroUser;
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 (szSmsAeroSenderName,sizeof (szSmsAeroSenderName) -1,
config.szSmsAeroSenderName," ","%20");
s += szSmsAeroSenderName;
s += " HTTP/1.1";
query->fnAddLine (s.c_str ());
query->fnAddLine ("User-Agent: fnSmsAeroQueueExecuteSend() (Maelstrom WS)");
query->fnAddLine ("Host: gate.smsaero.ru");
query->fnAddLine ("");
chBuf = new char [WS_MAX_BUF_SIZE +1]; // +1 для завершающего нуля
uiLen = query->fnSend (chBuf,WS_MAX_SEND_SIZE);
delete query;
// передача
// LeaveCriticalSection (&app_cs);
ReleaseSemaphore (hAppSem,1,NULL);
iResult = send (client_socket,chBuf,uiLen,0);
// EnterCriticalSection (&app_cs);
WaitForSingleObject (hAppSem,INFINITE);
if (iResult == SOCKET_ERROR)
{
closesocket (client_socket);
delete [] chBuf;
itoa (WSAGetLastError (),szTmp,10);
s = "fn=fnSmsAeroQueueExecuteSend() code=send msg='send error' error=";
s += szTmp;
szInfo = new char [s.length () +1];
strcpy (szInfo,s.c_str ());
throw szInfo;
}
// сохраняем в лог-файл
*(chBuf+uiLen) = 0;
fnLogSms (chBuf);
// дождаться ответа
// LeaveCriticalSection (&app_cs);
ReleaseSemaphore (hAppSem,1,NULL);
uiLen = 0;
do
{
iResult = recv (client_socket,chBuf+uiLen,WS_MAX_BUF_SIZE-uiLen,0);
if (iResult == 0 || iResult == SOCKET_ERROR)
break;
uiLen += iResult;
} while (! fnCheckReceipt (chBuf,uiLen));
// EnterCriticalSection (&app_cs);
WaitForSingleObject (hAppSem,INFINITE);
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)
{
itoa (WSAGetLastError (),szTmp,10);
s = "fn=fnSmsAeroQueueExecuteSend() code=socket1 msg='socket error' error=";
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);
ReleaseSemaphore (hAppSem,1,NULL);
d_addr = gethostbyname ("gate.smsaero.ru");
// EnterCriticalSection (&app_cs);
WaitForSingleObject (hAppSem,INFINITE);
if (d_addr == NULL)
{
closesocket (client_socket);
s = "fn=fnSmsAeroQueueExecuteSend() 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);
ReleaseSemaphore (hAppSem,1,NULL);
iResult = connect (client_socket,(sockaddr *) &dest_addr,sizeof (dest_addr));
// EnterCriticalSection (&app_cs);
WaitForSingleObject (hAppSem,INFINITE);
if (iResult)
{
closesocket (client_socket);
itoa (WSAGetLastError (),szTmp,10);
s = "fn=fnSmsAeroQueueExecuteSend() code=connect1 msg='connect failed' error=";
s += szTmp;
szInfo = new char [s.length () +1];
strcpy (szInfo,s.c_str ());
throw szInfo;
}
// запрос
query = new VDL_TEXT;
s = "GET /status/?user=";
fnReplace (szSmsAeroUser,sizeof (szSmsAeroUser) -1,
config.szSmsAeroEmail,"@","%40");
s += szSmsAeroUser;
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: fnSmsAeroQueueExecuteSend() (Maelstrom WS)");
query->fnAddLine ("Host: gate.smsaero.ru");
query->fnAddLine ("");
chBuf = new char [WS_MAX_BUF_SIZE +1]; // +1 для завершающего нуля
uiLen = query->fnSend (chBuf,WS_MAX_SEND_SIZE);
delete query;
// передача
// LeaveCriticalSection (&app_cs);
ReleaseSemaphore (hAppSem,1,NULL);
iResult = send (client_socket,chBuf,uiLen,0);
// EnterCriticalSection (&app_cs);
WaitForSingleObject (hAppSem,INFINITE);
if (iResult == SOCKET_ERROR)
{
closesocket (client_socket);
delete [] chBuf;
itoa (WSAGetLastError (),szTmp,10);
s = "fn=fnSmsAeroQueueExecuteSend() code=send msg='send error' error=";
s += szTmp;
szInfo = new char [s.length () +1];
strcpy (szInfo,s.c_str ());
throw szInfo;
}
// сохраняем в лог-файл
*(chBuf+uiLen) = 0;
fnLogSms (chBuf);
// дождаться ответа
// LeaveCriticalSection (&app_cs);
ReleaseSemaphore (hAppSem,1,NULL);
uiLen = 0;
do
{
iResult = recv (client_socket,chBuf+uiLen,WS_MAX_BUF_SIZE-uiLen,0);
if (iResult == 0 || iResult == SOCKET_ERROR)
break;
uiLen += iResult;
} while (! fnCheckReceipt (chBuf,uiLen));
// EnterCriticalSection (&app_cs);
WaitForSingleObject (hAppSem,INFINITE);
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);
// *******************
// * контроль шага 3 *
// *******************
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
// обновление метки времени
GetLocalTime (<);
SystemTimeToFileTime (<,&s_sms->ft_action);
}
void fnSmsQueueScan (void)
{
SYSTEMTIME lt;
union
{
FILETIME ft;
__int64 time64_current;
};
int iQty;
int iCycle;
SMS s_sms;
string s;
// текущее время
GetLocalTime (<);
SystemTimeToFileTime (<,&ft);
// сканирование очереди
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;
}
try
{
if (config.bSmsEnabled)
{
switch (config.iSmsGate)
{
// ************
// * SMS Aero *
// ************
case SMS_GATE_AERO:
// SMS-сообщение приписано к другому шлюзу
if (s_sms.iGate && (s_sms.iGate != SMS_GATE_AERO))
break;
// вызов соответствующей функции обработки
switch (s_sms.iType)
{
case 0:
case 1:
case 2:
case 3:
fnSmsAeroQueueExecuteSend (&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 szDate2 [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 (szDate2); // сегодня
fnCreateDate (szDate1,szDate2,-1*(iDays -1));
fnFormContent (query);
query->dst->fnAddLine ("<p>SMS-сообщения</p>");
query->dst->fnLoad ("templates/app_help_sms.tpl");
// выбор периода
s = "<p><form action=\"/sms_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>\
<td>№</td>\
<td>Дата</td>\
<td>Время</td>\
<td>Тип</td>\
<td>Шаг</td>\
<td>Префикс</td>\
<td>Клиент</td>\
<td>Тел.номер</td>\
<td>Текст сообщения</td>\
<td>Ответ сервиса</td>\
<td> </td>\
<td>№</td>\
<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,szDate2))
continue;
// №
s = "<tr><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/stock_id.png\" title=\"Выдача результатов\" border=0>";
else
s += "<img src=\"/images/24x24/stock_id.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;
default:
s += " ";
}
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)
s += s_sms.szServiceAnswer;
else
s += " ";
s += "</td>";
// статус
s += "<td valign=top>";
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>";
}
}
else
s += " ";
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 = "<p><table border=0>";
// **************************
// * тестовое SMS-сообщение *
// **************************
s += "<tr><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></tr>";
// *****************************************
// * рассылка поздравлений с днём рождения *
// *****************************************
s += "<tr><td><form action=\"/sms_birthday_accept\" method=post>";
s += "Поздравления с днём рождения:";
query->dst->fnAddLine (s.c_str ());
fnSelectDate (query,0,szDate2);
s = "<input type=submit value=\"Разослать\"></form></td></tr>";
// ********************************
// * рассылка информации клиентам *
// ********************************
s += "<tr><td><form action=\"/sms_info_accept\" method=post>";
s += "Рассылка информации клиентам: период с";
query->dst->fnAddLine (s.c_str ());
// дата 1
fnSelectDate (query,"from_",szDate2);
query->dst->fnAddLine ("по");
// дата 2
fnSelectDate (query,"to_",szDate2);
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></tr>";
s += "</table></p>";
query->dst->fnAddLine (s.c_str ());
fnFormEnd (query);
}
void fnAppSmsAccept (QUERY *query)
{
RING *args = query->args;
char sz [INI_MAX_LEXEM_LEN +1];
int iDays = 7;
char szTmp [20];
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 fnAppSmsEdit (QUERY *query)
{
RING *args = query->args;
char sz [INI_MAX_LEXEM_LEN +1];
int iSmsId = 0;
int iQty;
int iCycle;
SMS s_sms;
bool bFound = false;
string s;
char szTmp [20];
int iClient;
char szClientFIO [100]; // для вывода FIO
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>";
// №
s += "<tr><td>№:</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>";
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:
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>";
// в скрытых параметрах 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)
{
RING *args = query->args;
char sz [INI_MAX_LEXEM_LEN +1];
bool bRestart = false;
bool bStop = false;
bool bNothingToDo = true; // нечего делать
int iSmsId = 0;
int iQty;
int iCycle;
SMS s_sms;
while (args->fnGetQty ())
{
args->fnPop (sz);
if (! strcmp (sz,"restart"))
{
args->fnPop (sz);
bRestart = true;
bNothingToDo = false;
continue;
}
if (! strcmp (sz,"stop"))
{
args->fnPop (sz);
bStop = true;
bNothingToDo = false;
continue;
}
if (! strcmp (sz,"sms_id"))
{
args->fnPop (sz);
iSmsId = atoi (sz);
continue;
}
}
if (bNothingToDo)
return;
iQty = sms->fnGetQty ();
for (iCycle = 0; iCycle < iQty; iCycle++)
{
sms->fnPop ((char *) &s_sms,iCycle);
if (s_sms.iId == iSmsId)
{
if (bRestart)
{
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)
{
s_sms.bCompleted = true;
}
sms->fnReplace ((char *) &s_sms,iCycle,sizeof (SMS));
break;
}
}
}
void fnAppSmsTestAccept (QUERY *query)
{
RING *args = query->args;
char sz [INI_MAX_LEXEM_LEN +1];
char szFederalPhone [11 +1];
bool bPhoneChecked = false;
char szText [256 +1] = "";
int iAction = 0;
while (args->fnGetQty ())
{
args->fnPop (sz);
if (! strcmp (sz,"sms_phone"))
{
args->fnPop (sz);
bPhoneChecked = fnGetPhone (szFederalPhone,sz);
continue;
}
if (! strcmp (sz,"sms_text"))
{
args->fnPop (szText);
continue;
}
if (! strcmp (sz,"action"))
{
args->fnPop (sz);
iAction = atoi (sz);
continue;
}
}
// проверяем, выполнена ли транзакция
if (actions->fnCheck (iAction))
return;
if (! bPhoneChecked)
return;
if (! strlen (szText))
return;
// помещаем SMS-сообщение в очередь для отправки
fnSendSmsTest (query,szFederalPhone,szText);
}
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)
{
char sz [INI_MAX_LEXEM_LEN +1];
int iDay = 0;
int iMonth = 0;
RING *args = query->args;
int iCycle;
int iClientNum;
while (args->fnGetQty ())
{
args->fnPop (sz);
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;
}
}
// цикл с единицы, т.к. нулевой клиент - Анонимный
for (iCycle = 1; iCycle < iClientsQty; iCycle++)
{
// пропускаем удалённые записи
if (client [iCycle]->fnGetDelete ())
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
fnSendSmsBirthday (query,iClientNum);
}
}
void fnAppSmsInfoAccept (QUERY *query)
{
RING *args = query->args;
char sz [INI_MAX_LEXEM_LEN +1];
int iDay1 = 0;
int iMonth1 = 0;
int iYear1 = 0;
int iDay2 = 0;
int iMonth2 = 0;
int iYear2 = 0;
char szDate1 [11];
char szDate2 [11];
char szGroupId [2 +1];
int iGroupId = 0;
char szText [256 +1] = "";
int iAction = 0;
int iCycle;
int iClientNum;
std::auto_ptr<A_KEY_INT> clients_nums (new A_KEY_INT (16 kb));
int iQty;
while (args->fnGetQty ())
{
args->fnPop (sz);
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,"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;
}
if (! strcmp (sz,"group"))
{
args->fnPop (szGroupId);
iGroupId = atoi (szGroupId);
continue;
}
if (! strcmp (sz,"sms_text"))
{
args->fnPop (szText);
continue;
}
if (! strcmp (sz,"action"))
{
args->fnPop (sz);
iAction = 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]->fnGetClientNum()) // анонимный клиент
continue;
if (! fnCheckDateRange (szDate1,visit [iCycle]->fnGetDate (),szDate2))
continue;
if (visit [iCycle]->fnGetPreEntry ())
continue;
// группа
if (iGroupId >= 0)
if (! fnServicesGroupsGetMember (visit [iCycle]->fnGetType (),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 (16 kb);
clients_nums->fnCopyBuf (buf);
for (iCycle = 0; iCycle < iQty; iCycle++)
{
buf->fnPop((char *) &iClientNum,iCycle);
iClient = fnClientSearchByNum(iClientNum);
if (iClient == -1)
continue;
// пропускаем удалённые записи
if (client [iCycle]->fnGetDelete ())
continue;
// помещаем SMS-сообщение в очередь для отправки
fnSendSmsInfo(query,iClientNum,szText);
}
delete buf;
}
}
|