// ===============================================
// Расширение ISAPI xbmcnt.c
// Счетчик посещений страниц
//
// (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>
#include <stdio.h>
#include <string.h>

// Ширина символа
#define char_width 8

// Высота символа
#define char_height 16

// Массив растровых изображений цифровых символов
static unsigned char char_bits[10][char_height] = 
{
	// Изображение цифры 0
  {
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x3C, 0x42, 0x42, 0x42, 0x42, 0x42, 
    0x42, 0x42, 0x42, 0x3C 
  },
	
	// Изображение цифры 1
  { 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x10, 0x18, 0x14, 0x10,	0x10, 0x10, 
    0x10, 0x10, 0x10, 0x7C 
  },

	// Изображение цифры 2
	{ 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x3E, 0x22, 0x20, 0x20, 0x10, 0x08, 
    0x04, 0x02, 0x22, 0x3F 
  },

	// Изображение цифры 3
	{ 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x3E, 0x22, 0x40, 0x40, 0x3C, 0x40, 
    0x40, 0x40, 0x22, 0x3E 
  },

	// Изображение цифры 4
	{ 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x10, 0x18, 0x14, 0x12, 0x12, 0x3E, 
    0x10, 0x10, 0x10, 0x38 
  },

	// Изображение цифры 5
	{ 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x3E, 0x02, 0x02, 0x02, 0x3E, 0x20, 
    0x20, 0x20, 0x22, 0x2C 
  },

	// Изображение цифры 6
	{ 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x1C, 0x06, 0x02, 0x02, 0x1E, 0x22, 
    0x22, 0x22, 0x22, 0x1C 
  },

	// Изображение цифры 7
	{ 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x3E, 0x22, 0x20, 0x20, 0x10, 0x08, 
    0x08, 0x08, 0x08, 0x08 
  },

	// Изображение цифры 8
	{ 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x1C, 0x22, 0x22, 0x22, 0x1C, 0x22, 
    0x22, 0x22, 0x22, 0x1C 
  },

	// Изображение цифры 9
	{ 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x1C, 0x22, 0x22, 0x22, 0x3C, 0x20, 
    0x20, 0x20, 0x20, 0x1C 
  },
};

void PrintCounter(LPSTR szCounter, LPSTR szBuffer);

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

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

  return TRUE;
}

// =============================================================
// Функция HttpExtensionProc
// =============================================================
DWORD WINAPI HttpExtensionProc(EXTENSION_CONTROL_BLOCK *lpECB)
{
  // Рабочий буфер
  CHAR  szBuff[4096];

  // Идентификатор файла счетчика
  HANDLE hCounterFile;

  // Количество прочитанных байт
  DWORD dwBytesRead;

  // Количество записанных байт
  DWORD dwBytesWritten;

  // Результат выполнения операции
  BOOL bResult;

  // Временный буфер для работы со счетчиком
  CHAR  szBuf[20];

  // Текущее значение счетчика
  INT   nCounter;

  // Нулевой код состояния - признак успешного выполнения
  lpECB->dwHttpStatusCode = 0;

  // -----------------------------------------------
  // Увеличиваем значение счетчика в файле
  // -----------------------------------------------

  // Открываем файл счетчика для чтения
  hCounterFile = CreateFile("CNTDAT.DAT", 
    GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
    FILE_FLAG_SEQUENTIAL_SCAN, NULL);

  // Читаем из файла строку значения счетчика
  bResult = ReadFile(hCounterFile, szBuf, 7, 
    &dwBytesRead, NULL);

  // Закрываем файл счетчика
  CloseHandle(hCounterFile);
  
  // Преобразуем значение счетчика из текстовой
  // строки в численную величину
  sscanf(szBuf, "%d", &nCounter);
  
  // Увеличиваем значение счетчика
  nCounter++;
  
  // Записываем в буфер szBuf пять цифр нового
  // значения счетчика
  sprintf(szBuf, "%05.5ld", nCounter);

  // Сохраняем новое значение счетчика в файле
  hCounterFile = CreateFile("CNTDAT.DAT", 
    GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
    FILE_FLAG_SEQUENTIAL_SCAN, NULL);

  WriteFile(hCounterFile, szBuf, strlen(szBuf),
    &dwBytesWritten, NULL);

  CloseHandle(hCounterFile);
  
  // Записываем в буфер заголовок HTTP
  wsprintf(szBuff, "Content-type: image/x-xbitmap\r\n\r\n");

  // Выводим биты графического изображения в формате XBM
  PrintCounter(szBuf, szBuff);

  // Посылаем содержимое буфера удаленному пользователю
  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;
}

// =============================================================
// Функция PrintCounter
// =============================================================
void PrintCounter(LPSTR szCounter, LPSTR szBuff)
{
  // Временный буфер
  CHAR  szTempBuf[4096];

  // Полная ширина изображения счетчика
  int nFinalWidth;

  // Полная высота изображения счетчика
  int nFinalHeight;

  // Номер текущей строки растра изображения
  int nLine;

  // Текущий символ
  unsigned int nChar;

  // Смещение в массиве изображений цифр
  int nDigitOffset;

  // Полная ширина изображения вычисляется исходя из
  // количества цифр отображаемой строки
  nFinalWidth  = char_width * strlen(szCounter);

  // Полная высота изображения равна высоте 
  // изображения цифр
  nFinalHeight = char_height;

  // Отменяем кэширование
  wsprintf(szTempBuf, "Expires: Thu, 03 Dec 1996 10:00:00 GMT\r\n");
  strcat(szBuff, szTempBuf);

  wsprintf(szTempBuf, "Pragma: no-cache\r\n");
  strcat(szBuff, szTempBuf);

  // Выводим заголовок изображения XBM
  wsprintf(szTempBuf, "#define counter_width %d\r\n",
    nFinalWidth);
  strcat(szBuff, szTempBuf);

  wsprintf(szTempBuf, "#define counter_height %d\r\n", 
    nFinalHeight);
  strcat(szBuff, szTempBuf);

  wsprintf(szTempBuf, "static unsigned char counter_bits[] = {\r\n");
  strcat(szBuff, szTempBuf);

  // Выводим в цикле биты изображения счетчика
  for(nLine=0; nLine < nFinalHeight; nLine++)
	{
		for(nChar=0; nChar < strlen(szCounter); nChar++)
		{
      nDigitOffset = szCounter[nChar] - '0';

      wsprintf(szTempBuf, "0x%02X, ", 
        char_bits[nDigitOffset][nLine]);

      strcat(szBuff, szTempBuf);
		}
	}
 
  // Выводим строку, закрывающую структуру в файле XBM
  strcat(szBuff, "};\r\n");
}