// ===============================================
// Расширение ISAPI isform.c
// Обработка данных, полученных от формы,
// при помощи расширения ISAPI
//
// (C) Фролов А.В., 1997
// E-mail: frolov@glas.apc.org
// WWW:    http://www.glasnet.ru/~frolov
//         или
//         http://www.dials.ccas.ru/frolov
// ===============================================

#include <windows.h>
#include <httpext.h>

// Прототипы функций перекодировки
void DecodeStr(char *szString);
char DecodeHex(char *str);

// =============================================================
// Функция GetExtensionVersion
// Запись версии интерфейса ISAPI и
// строки описания расширения
// =============================================================
BOOL WINAPI GetExtensionVersion(HSE_VERSION_INFO *pVer)
{
  // Записываем версию интерфейса ISAPI
  pVer->dwExtensionVersion = 
    MAKELONG(HSE_VERSION_MINOR,HSE_VERSION_MAJOR );

  // Записываем строку описания расширения
  lstrcpyn(pVer->lpszExtensionDesc,
    "Form Parser ISAPI DLL", HSE_MAX_EXT_DLL_NAME_LEN);

  return TRUE;
}

// =============================================================
// Функция HttpExtensionProc
// =============================================================
DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK *lpECB)
{
  CHAR  szBuff[4096];
  CHAR  szTempBuf[4096];
  char * szPtr;
  char * szParam;
  
  // Нулевой код состояния - признак успешного выполнения
  lpECB->dwHttpStatusCode = 0;

  // Записываем в буфер заголовок HTTP и начальный
  // фрагмент формируемого динамически документа HTML
  wsprintf(szBuff,
    "Content-Type: text/html\r\n\r\n"
    "<HTML><HEAD><TITLE>Simple ISAPI Extension</TITLE></HEAD>\n"
    "<BODY BGCOLOR=#FFFFFF><H2>Information from ECB</H2>\n");

  // Добавляем версию интерфейса ISAPI
  wsprintf(szTempBuf, "<P>Extension Version: %d.%d", 
    HIWORD(lpECB->dwVersion), LOWORD(lpECB->dwVersion));
  strcat(szBuff, szTempBuf);
  
  // Название метода передачи данных
  wsprintf(szTempBuf, "<BR>Method: %s", lpECB->lpszMethod);
  strcat(szBuff, szTempBuf);
  
  // Строка параметров запуска расширения ISAPI
  wsprintf(szTempBuf, "<BR>QueryString: %s", 
    lpECB->lpszQueryString);
  strcat(szBuff, szTempBuf);
  
  // Физический путь к программному файлу расширения ISAPI
  wsprintf(szTempBuf, "<BR>PathTranslated: %s", 
    lpECB->lpszPathTranslated);
  strcat(szBuff, szTempBuf);

  // Полный размер данных, которые нужно получить
  wsprintf(szTempBuf, "<BR>TotalBytes: %d", 
    lpECB->cbTotalBytes);
  strcat(szBuff, szTempBuf);

  // Сколько доступно предварительно прочитанных данных
  wsprintf(szTempBuf, "<BR>Available: %d", 
    lpECB->cbAvailable);
  strcat(szBuff, szTempBuf);

  // Тип данных
  wsprintf(szTempBuf, "<BR>ContentType: %s", 
    lpECB->lpszContentType);
  strcat(szBuff, szTempBuf);

  lstrcpyn(szTempBuf, lpECB->lpbData, lpECB->cbAvailable + 1);
  szTempBuf[lpECB->cbAvailable + 1] = '\0';
  
  strcat(szBuff, "<H2>Принятые данные</H2>");
  strcat(szBuff, szTempBuf);

  // Перекодируем данные и отображаем результат
  // перекодировки
  DecodeStr(szTempBuf);

  strcat(szBuff, "<H2>Данные после перекодировки</H2>");
  strcat(szBuff, szTempBuf);

  // Выводим в документ список значений полей формы
  strcat(szBuff, "<H2>Список значений полей</H2>");

  szTempBuf[lpECB->cbAvailable] = '&';
  szTempBuf[lpECB->cbAvailable + 1] = '\0';
  
  for(szParam = szTempBuf;;)
  {
      szPtr = strchr(szParam, '&');
      if(szPtr != NULL)
      {
        *szPtr = '\0';
        DecodeStr(szParam);
        strcat(szBuff, szParam);
        strcat(szBuff, "<BR>");

        szParam = szPtr + 1;
        if(szParam >= (szTempBuf + lpECB->cbAvailable))
          break;
      }
      else
        break;
    }


  // Конечный фрагмент документа HTML
  strcat(szBuff, "</BODY></HTML>");  

  // Посылаем содержимое буфера удаленному пользователю
  if(!lpECB->ServerSupportFunction(lpECB->ConnID,
    HSE_REQ_SEND_RESPONSE_HEADER, NULL, NULL, 
    (LPDWORD)szBuff))
  {
    // Если послать данные не удалось, 
    // завершаем работу нашего расширения ISAPI 
    // с кодом ошибки
    return HSE_STATUS_ERROR;
  }

  // Записываем код успешного завершения
  lpECB->dwHttpStatusCode = 200;
  
  // Возвращаем принак успешного завершения  
  return HSE_STATUS_SUCCESS;
}

// ------------------------------------------------
// Функция DecodeStr
// Раскодирование строки из кодировки URL
// ------------------------------------------------
void DecodeStr(char *szString)
{
  int src;
  int dst;
  char ch;

  // Цикл по строке
  for(src=0, dst=0; szString[src]; src++, dst++)
  {
    // Получаем очередной символ перекодируемой строки
    ch = szString[src];

    // Заменяем символ "+" на пробел
    ch = (ch == '+') ? ' ' : ch;
    
    // Сохраняем результат
    szString[dst] = ch;
    
    // Обработка шестнадцатеричных кодов вида "%xx"
    if(ch == '%')
    {
      // Выполняем преобразование строки "%xx"
      // в код символа
      szString[dst] = DecodeHex(&szString[src + 1]);
      src += 2;
    }
  }
  
  // Закрываем строку двоичным нулем
  szString[dst] = '\0';
}

// ------------------------------------------------
// Функция DecodeHex
// Раскодирование строки "%xx"
// ------------------------------------------------
char DecodeHex(char *str)
{
  char ch;

  // Обрабатываем старший разряд
  if(str[0] >= 'A')
    ch = ((str[0] & 0xdf) - 'A') + 10;
  else
    ch = str[0] - '0';

  // Сдвигаем его влево на 4 бита
  ch <<= 4;

  // Обрабатываем младший разряд и складываем
  // его со старшим
  if(str[1] >= 'A')
    ch += ((str[1] & 0xdf) - 'A') + 10;
  else
    ch += str[1] - '0';

  // Возвращаем результат перекодировки
  return ch;
}
