char *HTMLBuilder::getEncodedContactName(HANDLE hContact, const char* szProto, const char* szSmileyProto) {
	char *szName = NULL;
	wchar_t *name = getContactName(hContact, szProto);
	if (name != NULL) {
		szName = encodeUTF8(hContact, szSmileyProto, name, ENF_NAMESMILEYS, true);
		delete name;
		return szName;
	}
	return encodeUTF8(hContact, szSmileyProto, TranslateT("(Unknown Contact)"), ENF_NAMESMILEYS, true);
}
char * HTMLBuilder::encodeUTF8(HANDLE hContact, const char *proto, const char *text, int cp, int flags, bool isSent) {
	char * outputStr = NULL;
	if (text != NULL) {
		wchar_t *wtext = Utils::convertToWCS(text, cp);
		outputStr = encodeUTF8(hContact, proto, wtext, flags, isSent);
		delete wtext;
	}
	return outputStr;
}
Exemple #3
0
void process(const std::string& line)
{
  if (line.empty())
    {
      vm_stop(con);
      return;
    }
  const std::wstring s = IO2WString(line);
  if (s.length() == 1)
    {
      vm_letter(con, (char*)encodeUTF8(s).c_str());
      return;
    }
  std::wstring p;
  if (stringBegins(s, IO2WString(VOLUME_HEAD), p))
    {
      p = trim(p);
      if (!checkTypeUnsignedInt(p))
	{
	  std::cout << ERROR_PREFIX << "\'" << p << "\' is not a valid volume value" << std::endl;
	  return;
	}
      const size_t pp = parseAsUnsignedInt(p);
      if (pp > 100)
	{
	  std::cout << ERROR_PREFIX << "argument must be a value from 0 to 100" << std::endl;
	  return;
	}
      vm_volume(con, (unsigned char)pp);
      return;
    }
  if (stringBegins(s, IO2WString(PITCH_HEAD), p))
    {
      p = trim(p);
      if (!checkTypeUnsignedInt(p))
	{
	  std::cout << ERROR_PREFIX << "\'" << p << "\' is not a valid pitch value" << std::endl;
	  return;
	}
      const size_t pp = parseAsUnsignedInt(p);
      if (pp > 100)
	{
	  std::cout << ERROR_PREFIX << "argument must be a value from 0 to 100" << std::endl;
	  return;
	}
      vm_pitch(con, (unsigned char)pp);
      return;
    }
  if (stringBegins(s, IO2WString(RATE_HEAD), p))
    {
      p = trim(p);
      if (!checkTypeUnsignedInt(p))
	{
	  std::cout << ERROR_PREFIX << "\'" << p << "\' is not a valid rate value" << std::endl;
	  return;
	}
      const size_t pp = parseAsUnsignedInt(p);
      if (pp > 100)
	{
	  std::cout << ERROR_PREFIX << "argument must be a value from 0 to 100" << std::endl;
	  return;
	}
      vm_rate(con, (unsigned char)pp);
      return;
    }
  if (stringBegins(s, IO2WString(PUNC_HEAD), p))
    {
      p = trim(toLower(p));
      if (p == L"all")
	vm_procmode(con, VOICEMAN_PROCMODE_ALL); else
      if (p == L"some")
	vm_procmode(con, VOICEMAN_PROCMODE_SOME); else
      if (p == L"none")
	vm_procmode(con, VOICEMAN_PROCMODE_NONE); else
	{
	  std::cout << ERROR_PREFIX << "\'" << p << "\' is not a valid punctuation mode. Please use \'all\', \'some\' or \'none\' values" << std::endl;
	  return;
	}
      return;
    }
  if (stringBegins(s, IO2WString(FAMILY_HEAD), p))
    {
      p = trim(p);
      if (p.empty ())
	{
	  std::cout << ERROR_PREFIX << "this command requires an argument" << std::endl;
	  return;
	}
      vm_family(con, VOICEMAN_LANG_NONE, (char*)encodeUTF8(p).c_str());
      return;
    }
  vm_text(con, (char*)encodeUTF8(s).c_str());
}
Exemple #4
0
int main(int argc, char* argv[])
{
  if (!cmdLine.parse(argc, argv))
    return 1;
  if (cmdLine.used("help"))
    {
    printHelp();
    return 0;
    }

  //Establishing connection;
  if (cmdLine.used("host"))
    {
      const std::string param = cmdLine["host"];
      std::string h=getDelimitedSubStr(param, 0, ':');
      const std::string p=getDelimitedSubStr(param, 1, ':');
      if (trim(h).empty())
	h="localhost";
      size_t port;
      if (!trim(p).empty())
	{
	  if (!checkTypeUnsignedInt(p))
	    {
	      std::cerr << ERROR_PREFIX << "\'" << trim(p) << "\' is not a valid port number." << std::endl;
	      return 1;
	    }
	  port = parseAsUnsignedInt(p);
	} else 
	port=VOICEMAN_DEFAULT_PORT;
      con = vm_connect_inet((char*)h.c_str(), port);
      if (con == VOICEMAN_BAD_CONNECTION)
	{
	  std::cerr << ERROR_PREFIX << "ERROR:Could not connect to host \'" << trim(h) << "\' with port " << port << "." << std::endl;
	  return 1;
	}
    } else
    if (cmdLine.used("socket"))
      {
	std::string p = cmdLine["socket"];
	if (trim(p).empty())
	  {
	    std::cerr << ERROR_PREFIX << "Missed name of UNIX domain socket." << std::endl;
	    return 1;
	  }
	if (trim(p) == "-")
	  p = VOICEMAN_DEFAULT_SOCKET;
	con = vm_connect_unix((char*)p.c_str());
	if (con == VOICEMAN_BAD_CONNECTION)
	  {
	    std::cerr << ERROR_PREFIX << "Could not connect to server via UNIX domain socket \'" << p << "\'." << std::endl;
	    return 1;
	  }
      } else
      {
	con = vm_connect();
	if (con == VOICEMAN_BAD_CONNECTION)
	  {
	    std::cerr << ERROR_PREFIX << "Could not connect to voicemand with default settings." << std::endl;
	    return 1;
	  }
      }

  ConnectionAutoClosing autoClosing(con);
  struct sigaction sa;
  sigaction(SIGPIPE, NULL, &sa);
  sa.sa_handler = sigPipeHandler;
  sa.sa_flags |= SA_RESTART;
  sigaction(SIGPIPE, &sa, NULL);



  //INitial connection parameters;
  assert(con != VOICEMAN_BAD_CONNECTION);
  if (cmdLine.used("stop"))
    vm_stop(con);
  if (cmdLine.used("pitch"))
    {
      const std::string value = trim(cmdLine["pitch"]);
      if (!checkTypeUnsignedInt(value))
	{
	  std::cerr << ERROR_PREFIX << "\'" << value << "\' is not a valid pitch value" << std::endl;
	  return 1;
	}
      vm_pitch(con, parseAsUnsignedInt(value));
    }
  if (cmdLine.used("rate"))
    {
      const std::string value = trim(cmdLine["rate"]);
      if (!checkTypeUnsignedInt(value))
	{
	  std::cerr << ERROR_PREFIX << "\'" << value << "\' is not a valid rate value" << std::endl;
	  return 1;
	}
      vm_rate(con, parseAsUnsignedInt(value));
    }
  if (cmdLine.used("volume"))
    {
      const std::string value = trim(cmdLine["volume"]);
      if (!checkTypeUnsignedInt(value))
	{
	  std::cerr << ERROR_PREFIX << "\'" << value << "\' is not a valid volume value" << std::endl;
	  return 1;
	}
      vm_volume(con, parseAsUnsignedInt(value));
    }
  if (cmdLine.used("family"))
    {
      //Neither trim() nor toLower() functions must be applied to teh value;
      //Let do it by the server itself;
      const std::string value = cmdLine["family"];
      if (trim(value).empty())
	{
	  std::cerr << ERROR_PREFIX << "voice family specification has an empty string value" << std::endl;
	  return 1;
	}
      for(std::string::size_type i = 0;i < value.length();i++)
	if (value[i] == ':' || value[i] == '\n')
	  {
	    std::cerr << ERROR_PREFIX << "voice family specification cannot contain \':\' and new line characters" << std::endl;
	    return 1;
	  }
      vm_family(con, VOICEMAN_LANG_NONE, (char*)value.c_str());
    }
  if (cmdLine.used("punc"))
    {
      const std::string value = trim(toLower(cmdLine["punc"]));
      if (value == "all")
	vm_procmode(con, VOICEMAN_PROCMODE_ALL); else
      if (value == "some")
	vm_procmode(con, VOICEMAN_PROCMODE_SOME); else
      if (value == "none")
	vm_procmode(con, VOICEMAN_PROCMODE_NONE); else
	{
	  std::cerr << ERROR_PREFIX << "punctuation mode can be only \'all\', \'some\' or \'none\'" << std::endl;
	  return 1;
	}
    }
  if (cmdLine.used("say"))
    {
      std::string value;
      for(size_t i = 0;i < cmdLine.files.size();i++)
	attachStringWithSpace(value, cmdLine.files[i]);
      vm_text(con, (char*)encodeUTF8(IO2WString(trim(value))).c_str());
      return 0;
    }
  if (cmdLine.used("stop"))
    return 0;

  std::cout << "VOICEMAN speech system. Version: " << PACKAGE_VERSION << "." << std::endl;
  std::cout << "Type \'quit\' or press Ctrl+D to leave this prompt." << std::endl;

  while(1)
    {
      std::string l;
      bool toQuit = 0;
      std::cout << "voiceman>";
      while(1)
	{
	  char c;
	  if (!std::cin.get(c))
	    {
	      toQuit = 1;
	      break;
	    }
	  if (c == '\r')
	    continue;
	  if (c == '\n')
	    break;
	  l += c;
	}
      if (toQuit || trim(toLower(l))  == "quit")
	break;
      process(l);
    }
  std::cout << std::endl;
  std::cout << "Bye!!!" << std::endl;
  return 0;
}
void TemplateHTMLBuilder::appendEventTemplate(IEView *view, IEVIEWEVENT *event, ProtocolSettings* protoSettings) {
	DBVARIANT dbv;
	CONTACTINFO ci;
	HANDLE hRealContact;
	char *szRealProto = NULL;
	char tempBase[1024];
	char *szBase=NULL;
	char tempStr[1024];
	char *szNoAvatar=NULL;
	char szCID[32];
	char *szName = NULL;
	char *szNameIn = NULL;
	char *szNameOut = NULL;
	char *szUIN = NULL;
	char *szUINIn = NULL;
	char *szUINOut = NULL;
	char *szNickIn = NULL;
	char *szNickOut = NULL;
	char *szStatusMsg = NULL;
	char *szAvatar = NULL;
	char *szAvatarIn = NULL;
	char *szAvatarOut = NULL;
	char *szText = NULL;
	char *szProto = NULL;
	char *szFileDesc = NULL;
	const char *tmpltName[2];
	bool isGrouping = false;
//	DWORD today = (DWORD)time(NULL);
//	today = today - today % 86400;
	if (protoSettings == NULL) {
		return;
	}
	hRealContact = getRealContact(event->hContact);
	szRealProto = getProto(hRealContact);
	szProto = getProto(event->pszProto, event->hContact);
	tempBase[0]='\0';
	TemplateMap *tmpm = getTemplateMap(protoSettings);
	if (tmpm!=NULL) {
		strcpy(tempBase, "file://");
		strcat(tempBase, tmpm->getFilename());
		char* pathrun = tempBase + strlen(tempBase);
		while ((*pathrun != '\\' && *pathrun != '/') && (pathrun > tempBase)) pathrun--;
		pathrun++;
		*pathrun = '\0';
		isGrouping = tmpm->isGrouping();
	}
	szBase = Utils::UTF8Encode(tempBase);

	if (event->hContact != NULL) {
		getUINs(event->hContact, szUINIn, szUINOut);
	}

	if (event->hContact != NULL) {
		szNameOut = getEncodedContactName(NULL, szProto, szRealProto);
		szNameIn = getEncodedContactName(event->hContact, szProto, szRealProto);
	} else {
		szNameOut = Utils::dupString("&nbsp;");
		szNameIn = Utils::dupString("&nbsp;");
	}
	sprintf(tempStr, "%snoavatar.jpg", tempBase);
	szNoAvatar = Utils::UTF8Encode(tempStr);

	if(event->hContact != NULL) {
		szAvatarIn = getAvatar(event->hContact, szRealProto);
	}
	if (szAvatarIn == NULL) {
		szAvatarIn = Utils::dupString(szNoAvatar);
	}
	szAvatarOut = getAvatar(NULL, szRealProto);
	if (szAvatarOut == NULL) {
		szAvatarOut = Utils::dupString(szNoAvatar);
	}
	if(event->hContact != NULL) {
		if (!DBGetContactSetting(event->hContact, "CList", "StatusMsg",&dbv)) {
			if (strlen(dbv.pszVal) > 0) {
				szStatusMsg = Utils::UTF8Encode(dbv.pszVal);
			}
			DBFreeVariant(&dbv);
		}
	}
	ZeroMemory(&ci, sizeof(ci));
	ci.cbSize = sizeof(ci);
	ci.hContact = event->hContact;
	ci.szProto = szProto;
	ci.dwFlag = CNF_NICK | CNF_TCHAR;
	if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) {
		szNickIn = encodeUTF8(event->hContact, szRealProto, ci.pszVal, ENF_NAMESMILEYS, true);
	}
	ZeroMemory(&ci, sizeof(ci));
	ci.cbSize = sizeof(ci);
	ci.hContact = NULL;
	ci.szProto = szProto;
	ci.dwFlag = CNF_NICK | CNF_TCHAR;
	if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) {
		szNickOut = encodeUTF8(event->hContact, szRealProto, ci.pszVal, ENF_NAMESMILEYS, true);
	}
	IEVIEWEVENTDATA* eventData = event->eventData;
	for (int eventIdx = 0; eventData!=NULL && (eventIdx < event->count || event->count==-1); eventData = eventData->next, eventIdx++) {
		int outputSize;
		char *output;
		output = NULL;
		if (eventData->iType == IEED_EVENT_MESSAGE || eventData->iType == IEED_EVENT_STATUSCHANGE || eventData->iType == IEED_EVENT_FILE || eventData->iType == IEED_EVENT_URL || eventData->iType == IEED_EVENT_SYSTEM) {
			int isSent = (eventData->dwFlags & IEEDF_SENT);
			int isRTL = (eventData->dwFlags & IEEDF_RTL) && tmpm->isRTL();
			int isHistory = (eventData->time < (DWORD)getStartedTime() && (eventData->dwFlags & IEEDF_READ || eventData->dwFlags & IEEDF_SENT));
			int isGroupBreak = TRUE;
 		  	if ((getFlags(protoSettings) & Options::LOG_GROUP_MESSAGES) && eventData->dwFlags == LOWORD(getLastEventType())
			  && eventData->iType == IEED_EVENT_MESSAGE && HIWORD(getLastEventType()) == IEED_EVENT_MESSAGE
			  && (isSameDate(eventData->time, getLastEventTime()))
//			  && ((eventData->time < today) == (getLastEventTime() < today))
			  && (((eventData->time < (DWORD)startedTime) == (getLastEventTime() < (DWORD)startedTime)) || !(eventData->dwFlags & IEEDF_READ))) {
				isGroupBreak = FALSE;
			}
			if (isSent) {
				szAvatar = szAvatarOut;
				szUIN = szUINOut;
				sprintf(szCID, "%d", 0);
			} else {
				szAvatar = szAvatarIn;
				szUIN = szUINIn;
				sprintf(szCID, "%d", (int)event->hContact);
			}
			tmpltName[0] = groupTemplate;
			tmpltName[1] = NULL;
			groupTemplate = NULL;
			szName = NULL;
			szText = NULL;
			szFileDesc = NULL;
			if (event->eventData->dwFlags & IEEDF_UNICODE_NICK) {
				szName = encodeUTF8(event->hContact, szRealProto, eventData->pszNickW, ENF_NAMESMILEYS, true);
			} else {
				szName = encodeUTF8(event->hContact, szRealProto, eventData->pszNick, ENF_NAMESMILEYS, true);
			}
			if (eventData->dwFlags & IEEDF_UNICODE_TEXT) {
				szText = encodeUTF8(event->hContact, szRealProto, eventData->pszTextW, eventData->iType == IEED_EVENT_MESSAGE ? ENF_ALL : 0, isSent);
   			} else {
				szText = encodeUTF8(event->hContact, szRealProto, eventData->pszText, event->codepage, eventData->iType == IEED_EVENT_MESSAGE ? ENF_ALL : 0, isSent);
			}
			if (eventData->dwFlags & IEEDF_UNICODE_TEXT2) {
				szFileDesc = encodeUTF8(event->hContact, szRealProto, eventData->pszText2W, 0, isSent);
   			} else {
				szFileDesc = encodeUTF8(event->hContact, szRealProto, eventData->pszText2, event->codepage, 0, isSent);
			}
			if ((eventData->iType == IEED_EVENT_MESSAGE)) {
				if (!isRTL) {
					if (isGrouping && (getFlags(protoSettings) & Options::LOG_GROUP_MESSAGES)) {
						if (isGroupBreak) {
							tmpltName[1] = isHistory ? isSent ? "hMessageOutGroupStart" : "hMessageInGroupStart" : isSent ? "MessageOutGroupStart" : "MessageInGroupStart";
						} else {
							tmpltName[0] = isHistory ? isSent ? "hMessageOutGroupInner" : "hMessageInGroupInner" : isSent ? "MessageOutGroupInner" : "MessageInGroupInner";
						}
						groupTemplate = isHistory ? isSent ? "hMessageOutGroupEnd" : "hMessageInGroupEnd" : isSent ? "MessageOutGroupEnd" : "MessageInGroupEnd";
					} else {
						tmpltName[1] = isHistory ? isSent ? "hMessageOut" : "hMessageIn" : isSent ? "MessageOut" : "MessageIn";
					}
				} else {
					if (isGrouping && (getFlags(protoSettings) & Options::LOG_GROUP_MESSAGES)) {
						if (isGroupBreak) {
							tmpltName[1] = isHistory ? isSent ? "hMessageOutGroupStartRTL" : "hMessageInGroupStartRTL" : isSent ? "MessageOutGroupStartRTL" : "MessageInGroupStartRTL";
						} else {
							tmpltName[0] = isHistory ? isSent ? "hMessageOutGroupInnerRTL" : "hMessageInGroupInnerRTL" : isSent ? "MessageOutGroupInnerRTL" : "MessageInGroupInnerRTL";
						}
						groupTemplate = isHistory ? isSent ? "hMessageOutGroupEndRTL" : "hMessageInGroupEndRTL" : isSent ? "MessageOutGroupEndRTL" : "MessageInGroupEndRTL";
					} else {
						tmpltName[1] = isHistory ? isSent ? "hMessageOutRTL" : "hMessageInRTL" : isSent ? "MessageOutRTL" : "MessageInRTL";
					}
				}
			} else if (eventData->iType == IEED_EVENT_FILE) {
				tmpltName[1] = isHistory ? isSent ? "hFileOut" : "hFileIn" : isSent ? "FileOut" : "FileIn";
				Template *tmplt = tmpm->getTemplate(tmpltName[1]);
				if (tmplt == NULL) {
					tmpltName[1] = isHistory ? "hFile" : "File";
				}
			} else if (eventData->iType == IEED_EVENT_URL) {
				tmpltName[1] = isHistory ? isSent ? "hURLOut" : "hURLIn" : isSent ? "URLOut" : "URLIn";
				Template *tmplt = tmpm->getTemplate(tmpltName[1]);
				if (tmplt == NULL) {
					tmpltName[1] = isHistory ? "hURL" : "URL";
				}
			} else if (eventData->iType == IEED_EVENT_STATUSCHANGE || (eventData->iType == IEED_EVENT_SYSTEM)) {
				tmpltName[1] = isHistory ? "hStatus" : "Status";
			}
			/* template-specific formatting */
			for (int i=0;i<2;i++) {
				Template *tmplt;
				if (tmpltName[i] == NULL) continue;
				tmplt = tmpm->getTemplate(tmpltName[i]);
				if (tmplt == NULL) continue;
				for (Token *token = tmplt->getTokens();token!=NULL;token=token->getNext()) {
					const char *tokenVal;
					tokenVal = NULL;
					switch (token->getType()) {
						case Token::PLAIN:
							tokenVal = token->getText();
							break;
						case Token::NAME:
							if (getFlags(protoSettings) & Options::LOG_SHOW_NICKNAMES) {
								tokenVal = szName;
							} else {
								tokenVal = "&nbsp;";
							}
							break;
						case Token::TIME:
							if (getFlags(protoSettings) & Options::LOG_SHOW_TIME) {
								tokenVal = timestampToString(getFlags(protoSettings), eventData->time, 1);
							} else {
								tokenVal = "&nbsp;";
							}
							break;
						case Token::DATE:
							if (getFlags(protoSettings) & Options::LOG_SHOW_DATE) {
								tokenVal = timestampToString(getFlags(protoSettings), eventData->time, 0);
							} else {
								tokenVal = "&nbsp;";
							}
							break;
	  					case Token::TEXT:
							tokenVal = szText;
							break;
	  					case Token::AVATAR:
							tokenVal = szAvatar;
							break;
	  					case Token::CID:
							tokenVal = szCID;
							break;
						case Token::BASE:
							tokenVal = szBase;
							break;
						case Token::NAMEIN:
							if (getFlags(protoSettings) & Options::LOG_SHOW_NICKNAMES) {
								if (event->hContact != NULL) {
									tokenVal = szNameIn;
								} else {
									tokenVal = szName;
								}
							} else {
								tokenVal = "&nbsp;";
							}
							break;
						case Token::NAMEOUT:
							if (getFlags(protoSettings) & Options::LOG_SHOW_NICKNAMES) {
								if (event->hContact != NULL) {
									tokenVal = szNameOut;
								} else {
									tokenVal = szName;
								}
							} else {
								tokenVal = "&nbsp;";
							}
							break;
						case Token::AVATARIN:
							tokenVal = szAvatarIn;
							break;
						case Token::AVATAROUT:
							tokenVal = szAvatarOut;
							break;
						case Token::PROTO:
							tokenVal = szRealProto;
							break;
						case Token::UIN:
							tokenVal = szUIN;
							break;
						case Token::UININ:
							tokenVal = szUINIn;
							break;
						case Token::UINOUT:
							tokenVal = szUINOut;
							break;
						case Token::STATUSMSG:
							tokenVal = szStatusMsg;
							break;
						case Token::NICKIN:
							tokenVal = szNickIn;
							break;
		 				case Token::NICKOUT:
							tokenVal = szNickOut;
							break;
						case Token::FILEDESC:
							tokenVal = szFileDesc;
							break;
					}
					if (tokenVal != NULL) {
						if (token->getEscape()) {
							char *escapedToken  = Utils::escapeString(tokenVal);
							Utils::appendText(&output, &outputSize, "%s", escapedToken);
							delete escapedToken;
						} else {
							Utils::appendText(&output, &outputSize, "%s", tokenVal);
						}
					}
				}
			}
			setLastEventType(MAKELONG(eventData->dwFlags, eventData->iType));
			setLastEventTime(eventData->time);
			if (szName!=NULL) delete szName;
			if (szText!=NULL) delete szText;
			if (szFileDesc!=NULL) delete szFileDesc;
		}
		if (output != NULL) {
			view->write(output);
			free(output);
		}
	}
	if (szBase!=NULL) delete szBase;
	if (szRealProto!=NULL) delete szRealProto;
	if (szProto!=NULL) delete szProto;
	if (szUINIn!=NULL) delete szUINIn;
	if (szUINOut!=NULL) delete szUINOut;
	if (szNoAvatar!=NULL) delete szNoAvatar;
	if (szAvatarIn!=NULL) delete szAvatarIn;
	if (szAvatarOut!=NULL) delete szAvatarOut;
	if (szNameIn!=NULL) delete szNameIn;
	if (szNameOut!=NULL) delete szNameOut;
	if (szNickIn!=NULL) delete szNickIn;
	if (szNickOut!=NULL) delete szNickOut;
	if (szStatusMsg!=NULL) delete szStatusMsg;
	view->documentClose();
}
void TemplateHTMLBuilder::buildHeadTemplate(IEView *view, IEVIEWEVENT *event, ProtocolSettings *protoSettings) {
	DBVARIANT dbv;
	CONTACTINFO ci;
	char tempBase[1024];
	char tempStr[1024];
	HANDLE hRealContact;
	char *szRealProto = NULL;
	char *szBase=NULL;
	char *szNoAvatar=NULL;
	char *szProto = NULL;
	char *szNameIn = NULL;
	char *szNameOut = NULL;
	char *szAvatarIn = NULL;
	char *szAvatarOut = NULL;
	char *szUINIn = NULL;
	char *szUINOut = NULL;
	char *szNickIn = NULL;
	char *szNickOut = NULL;
	char *szStatusMsg = NULL;
	int outputSize;
	char *output;

	output = NULL;
	hRealContact = getRealContact(event->hContact);
	szRealProto = getProto(hRealContact);
	szProto = getProto(event->pszProto, event->hContact);
	tempBase[0]='\0';
	if (protoSettings == NULL)
		return;

	TemplateMap *tmpm = getTemplateMap(protoSettings);
	if (tmpm==NULL)
		return;

	strcpy(tempBase, "file://");
	strcat(tempBase, tmpm->getFilename());
	char* pathrun = tempBase + strlen(tempBase);
	while ((*pathrun != '\\' && *pathrun != '/') && (pathrun > tempBase)) pathrun--;
	pathrun++;
	*pathrun = '\0';

	szBase = Utils::UTF8Encode(tempBase);
	getUINs(event->hContact, szUINIn, szUINOut);
	if (getFlags(protoSettings) & Options::LOG_SHOW_NICKNAMES) {
		szNameOut = getEncodedContactName(NULL, szProto, szRealProto);
		szNameIn = getEncodedContactName(event->hContact, szProto, szRealProto);
	} else {
		szNameOut = Utils::dupString("&nbsp;");
		szNameIn = Utils::dupString("&nbsp;");
	}
	sprintf(tempStr, "%snoavatar.jpg", tempBase);
	szNoAvatar = Utils::UTF8Encode(tempStr);
	szAvatarIn = getAvatar(event->hContact, szRealProto);
	if (szAvatarIn == NULL) {
		szAvatarIn = Utils::dupString(szNoAvatar);
	}
	szAvatarOut = getAvatar(NULL, szRealProto);
	if (szAvatarOut == NULL) {
		szAvatarOut = Utils::dupString(szNoAvatar);
	}
	if (!DBGetContactSetting(event->hContact, "CList", "StatusMsg",&dbv)) {
		if (strlen(dbv.pszVal) > 0) {
			szStatusMsg = Utils::UTF8Encode(dbv.pszVal);
		}
		DBFreeVariant(&dbv);
	}
	ZeroMemory(&ci, sizeof(ci));
	ci.cbSize = sizeof(ci);
	ci.hContact = event->hContact;
	ci.szProto = szProto;
	ci.dwFlag = CNF_NICK | CNF_TCHAR;
	if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) {
		szNickIn = encodeUTF8(event->hContact, szRealProto, ci.pszVal, ENF_NAMESMILEYS, true);
	}
	ZeroMemory(&ci, sizeof(ci));
	ci.cbSize = sizeof(ci);
	ci.hContact = NULL;
	ci.szProto = szProto;
	ci.dwFlag = CNF_NICK | CNF_TCHAR;
	if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) {
		szNickOut = encodeUTF8(event->hContact, szRealProto, ci.pszVal, ENF_NAMESMILEYS, true);
	}

	Template *tmplt = tmpm->getTemplate(((event->dwFlags & IEEF_RTL) && tmpm->isRTL()) ? "HTMLStartRTL" : "HTMLStart");
	if (tmplt == NULL) {
		tmplt = tmpm->getTemplate("HTMLStart");
	}
	if (tmplt!=NULL) {
		for (Token *token = tmplt->getTokens();token!=NULL;token=token->getNext()) {
			const char *tokenVal;
			tokenVal = NULL;
			switch (token->getType()) {
				case Token::PLAIN:
					tokenVal = token->getText();
					break;
				case Token::BASE:
					tokenVal = szBase;
					break;
				case Token::NAMEIN:
					tokenVal = szNameIn;
					break;
				case Token::NAMEOUT:
					tokenVal = szNameOut;
					break;
				case Token::AVATARIN:
					tokenVal = szAvatarIn;
					break;
				case Token::AVATAROUT:
					tokenVal = szAvatarOut;
					break;
				case Token::PROTO:
					tokenVal = szRealProto;
					break;
				case Token::UININ:
					tokenVal = szUINIn;
					break;
				case Token::UINOUT:
					tokenVal = szUINOut;
					break;
				case Token::STATUSMSG:
					tokenVal = szStatusMsg;
					break;
				case Token::NICKIN:
					tokenVal = szNickIn;
					break;
 				case Token::NICKOUT:
					tokenVal = szNickOut;
					break;
			}
			if (tokenVal != NULL) {
				if (token->getEscape()) {
					char *escapedToken  = Utils::escapeString(tokenVal);
					Utils::appendText(&output, &outputSize, "%s", escapedToken);
					delete escapedToken;
				} else {
					Utils::appendText(&output, &outputSize, "%s", tokenVal);
				}
			}
		}
	}
	if (output != NULL) {
		view->write(output);
		free(output);
	}
	if (szBase!=NULL) delete szBase;
	if (szRealProto!=NULL) delete szRealProto;
	if (szProto!=NULL) delete szProto;
	if (szUINIn!=NULL) delete szUINIn;
	if (szUINOut!=NULL) delete szUINOut;
	if (szNoAvatar!=NULL) delete szNoAvatar;
	if (szAvatarIn!=NULL) delete szAvatarIn;
	if (szAvatarOut!=NULL) delete szAvatarOut;
	if (szNameIn!=NULL) delete szNameIn;
	if (szNameOut!=NULL) delete szNameOut;
	if (szNickIn!=NULL) delete szNickIn;
	if (szNickOut!=NULL) delete szNickOut;
	if (szStatusMsg!=NULL) delete szStatusMsg;
	//view->scrollToBottom();
	groupTemplate = NULL;
	iLastEventType = -1;
}
void TemplateHTMLBuilder::buildHead(IEView *view, IEVIEWEVENT *event) {
	DBVARIANT dbv;
	CONTACTINFO ci;
	char szBase[1024];
	char szNoAvatar[1024];
	char *szProto = NULL;
	char *szNameIn = NULL;
	char *szNameOut = NULL;
	char *szAvatarIn = NULL;
	char *szAvatarOut = NULL;
	int outputSize;
	char *output;

	output = NULL;
	szProto = Utils::dupString((char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) event->hContact, 0));
	szBase[0]='\0';
	TemplateMap *tmpm = (event->dwFlags & IEEF_RTL) ? TemplateMap::getTemplateMap("default_rtl") : TemplateMap::getTemplateMap("default");
	if (tmpm!=NULL) {
    	strcpy(szBase, tmpm->getFilename());
    	char* pathrun = szBase + strlen(szBase);
    	while ((*pathrun != '\\' && *pathrun != '/') && (pathrun > szBase)) pathrun--;
    	pathrun++;
    	*pathrun = '\0';
	}
	sprintf(szNoAvatar, "%snoavatar.jpg", szBase);
	if (Options::getTemplatesFlags() & Options::LOG_SHOW_NICKNAMES) {
		ZeroMemory(&ci, sizeof(ci));
	    ci.cbSize = sizeof(ci);
	    ci.hContact = NULL;
	    ci.szProto = szProto;
	    ci.dwFlag = CNF_DISPLAY;
		if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) {
	        szNameOut = encodeUTF8(ci.pszVal, NULL, false);
		}
		szNameIn = encodeUTF8((char *) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM) event->hContact, 0), NULL, false);
	} else {
        szNameOut = Utils::dupString("&nbsp;");
        szNameIn = Utils::dupString("&nbsp;");
	}
	if (!DBGetContactSetting(event->hContact, "ContactPhoto", "File",&dbv)) {
	    if (strlen(dbv.pszVal) > 0) {
       		szAvatarIn = Utils::dupString(dbv.pszVal);
		    Utils::convertPath(szAvatarIn);
	    }
       	DBFreeVariant(&dbv);
	}
	if (szAvatarIn == NULL) {
        szAvatarIn = Utils::dupString(szNoAvatar);
	}
	if (!DBGetContactSetting(NULL, "ContactPhoto", "File",&dbv)) {
	    if (strlen(dbv.pszVal) > 0) {
       		szAvatarOut = Utils::dupString(dbv.pszVal);
		    Utils::convertPath(szAvatarOut);
	    }
       	DBFreeVariant(&dbv);
	}
	if (szAvatarOut == NULL) {
        szAvatarOut = Utils::dupString(szNoAvatar);
	}
	Template *tmplt = (event->dwFlags & IEEF_RTL) ? TemplateMap::getTemplate("default_rtl", "HTMLStart") : TemplateMap::getTemplate("default", "HTMLStart");
	if (tmplt!=NULL) {
		for (Token *token = tmplt->getTokens();token!=NULL;token=token->getNext()) {
			const char *tokenVal;
			tokenVal = NULL;
			switch (token->getType()) {
				case Token::PLAIN:
                    tokenVal = token->getText();
					break;
				case Token::BASE:
				    tokenVal = szBase;
				    break;
				case Token::NAMEIN:
                    tokenVal = szNameIn;
					break;
				case Token::NAMEOUT:
                    tokenVal = szNameOut;
					break;
				case Token::AVATARIN:
			    	tokenVal = szAvatarIn;
					break;
				case Token::AVATAROUT:
			    	tokenVal = szAvatarOut;
					break;
				case Token::PROTO:
				    tokenVal = szProto;
				    break;
			}
			if (tokenVal != NULL) {
				Utils::appendText(&output, &outputSize, "%s", tokenVal);
			}
		}
	}
	if (output != NULL) {
        view->write(output);
		free(output);
	}
    if (szProto!=NULL) delete szProto;
	if (szAvatarIn!=NULL) delete szAvatarIn;
	if (szAvatarOut!=NULL) delete szAvatarOut;
	if (szNameIn!=NULL) delete szNameIn;
	if (szNameOut!=NULL) delete szNameOut;
	view->scrollToBottom();
	groupTemplate = NULL;
	iLastEventType = -1;
}
void TemplateHTMLBuilder::appendEvent(IEView *view, IEVIEWEVENT *event) {
	DBVARIANT dbv;
	CONTACTINFO ci;
	char szBase[1024];
	char szNoAvatar[1024];
	char szCID[32];
	char *szName = NULL;
	char *szNameIn = NULL;
	char *szNameOut = NULL;
	char *szAvatar = NULL;
	char *szAvatarIn = NULL;
	char *szAvatarOut = NULL;
	char *szText = NULL;
	char *szProto = NULL;
	const char *tmpltName[2];
	bool isGrouping = false;

	int cp = CP_ACP;
	if (event->cbSize == sizeof(IEVIEWEVENT)) {
		cp = event->codepage;
	}
	szProto = Utils::dupString((char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) event->hContact, 0));
	szBase[0]='\0';
	TemplateMap *tmpm = (event->dwFlags & IEEF_RTL) ? TemplateMap::getTemplateMap("default_rtl") : TemplateMap::getTemplateMap("default");
	if (tmpm!=NULL) {
    	strcpy(szBase, tmpm->getFilename());
    	char* pathrun = szBase + strlen(szBase);
    	while ((*pathrun != '\\' && *pathrun != '/') && (pathrun > szBase)) pathrun--;
    	pathrun++;
    	*pathrun = '\0';
    	isGrouping = tmpm->isGrouping();
	}
	sprintf(szNoAvatar, "%snoavatar.jpg", szBase);
	if (Options::getTemplatesFlags() & Options::LOG_SHOW_NICKNAMES) {
		ZeroMemory(&ci, sizeof(ci));
	    ci.cbSize = sizeof(ci);
	    ci.hContact = NULL;
	    ci.szProto = szProto;
	    ci.dwFlag = CNF_DISPLAY;
		if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) {
	        szNameOut = encodeUTF8(ci.pszVal, NULL, false);
		}
		szNameIn = encodeUTF8((char *) CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM) event->hContact, 0), NULL, false);
	} else {
        szNameOut = Utils::dupString("&nbsp;");
        szNameIn = Utils::dupString("&nbsp;");
	}
	if (!DBGetContactSetting(event->hContact, "ContactPhoto", "File",&dbv)) {
	    if (strlen(dbv.pszVal) > 0) {
       		szAvatarIn = Utils::dupString(dbv.pszVal);
		    Utils::convertPath(szAvatarIn);
	    }
       	DBFreeVariant(&dbv);
	}
	if (szAvatarIn == NULL) {
        szAvatarIn = Utils::dupString(szNoAvatar);
	}
	if (!DBGetContactSetting(NULL, "ContactPhoto", "File",&dbv)) {
	    if (strlen(dbv.pszVal) > 0) {
       		szAvatarOut = Utils::dupString(dbv.pszVal);
		    Utils::convertPath(szAvatarOut);
	    }
       	DBFreeVariant(&dbv);
	}
	if (szAvatarOut == NULL) {
        szAvatarOut = Utils::dupString(szNoAvatar);
	}
	HANDLE hDbEvent = event->hDbEventFirst;
	event->hDbEventFirst = NULL;
	for (int eventIdx = 0; hDbEvent!=NULL && (eventIdx < event->count || event->count==-1); eventIdx++) {
		int outputSize;
		char *output;
		DBEVENTINFO dbei = { 0 };
        dbei.cbSize = sizeof(dbei);
        dbei.cbBlob = CallService(MS_DB_EVENT_GETBLOBSIZE, (WPARAM) hDbEvent, 0);
        if (dbei.cbBlob == 0xFFFFFFFF) {
            return;
		}
        dbei.pBlob = (PBYTE) malloc(dbei.cbBlob);
        CallService(MS_DB_EVENT_GET, (WPARAM)  hDbEvent, (LPARAM) & dbei);

		if (!(dbei.flags & DBEF_SENT) && (dbei.eventType == EVENTTYPE_MESSAGE )) {
			CallService(MS_DB_EVENT_MARKREAD, (WPARAM) event->hContact, (LPARAM) hDbEvent);
			CallService(MS_CLIST_REMOVEEVENT, (WPARAM) event->hContact, (LPARAM) hDbEvent);
		} else if (dbei.eventType == EVENTTYPE_STATUSCHANGE) {
			CallService(MS_DB_EVENT_MARKREAD, (WPARAM) event->hContact, (LPARAM) hDbEvent);
		}
		HANDLE hCurDbEvent = hDbEvent;
        hDbEvent = (HANDLE) CallService(MS_DB_EVENT_FINDNEXT, (WPARAM) hDbEvent, 0);
		if (!isDbEventShown(0, &dbei)) {
            free(dbei.pBlob);
	        continue;
    	}
		output = NULL;
		if (dbei.eventType == EVENTTYPE_MESSAGE || dbei.eventType == EVENTTYPE_STATUSCHANGE || dbei.eventType == EVENTTYPE_FILE || dbei.eventType == EVENTTYPE_URL) {
			int isSent = (dbei.flags & DBEF_SENT);
			int isHistory = (dbei.timestamp < (DWORD)getStartedTime() && (dbei.flags & DBEF_READ || dbei.flags & DBEF_SENT));
			int isGroupBreak = TRUE;
 		  	if ((Options::getTemplatesFlags() & Options::LOG_GROUP_MESSAGES) && dbei.flags == LOWORD(getLastEventType())
			  && dbei.eventType == EVENTTYPE_MESSAGE && HIWORD(getLastEventType()) == EVENTTYPE_MESSAGE
			  && ((dbei.timestamp - getLastEventTime()) < 86400)) {
		        isGroupBreak = FALSE;
		    }
			if (isSent) {
				szName = szNameOut;
				szAvatar = szAvatarOut;
				sprintf(szCID, "%d", 0);
			} else {
				szName = szNameIn;
				szAvatar = szAvatarIn;
				sprintf(szCID, "%d", (int)event->hContact);
			}
			tmpltName[0] = groupTemplate;
			tmpltName[1] = NULL;
			groupTemplate = NULL;
			if (dbei.eventType == EVENTTYPE_MESSAGE) {
				DWORD aLen = strlen((char *)dbei.pBlob)+1;
				if (dbei.cbBlob > aLen && !(event->dwFlags & IEEF_NO_UNICODE)) {
					DWORD wlen = Utils::safe_wcslen((wchar_t *)&dbei.pBlob[aLen], (dbei.cbBlob - aLen) / 2);
					if (wlen > 0 && wlen < aLen) {
                        szText = encodeUTF8((wchar_t *)&dbei.pBlob[aLen], szProto, true);
					} else {
                        szText = encodeUTF8((char *)dbei.pBlob, cp, szProto, true);
					}
				} else {
                	szText = encodeUTF8((char *)dbei.pBlob, cp, szProto, true);
				}
                if (isGrouping && (Options::getTemplatesFlags() & Options::LOG_GROUP_MESSAGES)) {
                    if (isGroupBreak) {
              		    tmpltName[1] = isHistory ? isSent ? "hMessageOutGroupStart" : "hMessageInGroupStart" : isSent ? "MessageOutGroupStart" : "MessageInGroupStart";
                   	} else {
                   		tmpltName[0] = isHistory ? isSent ? "hMessageOutGroupInner" : "hMessageInGroupInner" : isSent ? "MessageOutGroupInner" : "MessageInGroupInner";
                   	}    
               		groupTemplate = isHistory ? isSent ? "hMessageOutGroupEnd" : "hMessageInGroupEnd" : isSent ? "MessageOutGroupEnd" : "MessageInGroupEnd";
               	} else {
               		tmpltName[1] = isHistory ? isSent ? "hMessageOut" : "hMessageIn" : isSent ? "MessageOut" : "MessageIn";
               	}    
			} else if (dbei.eventType == EVENTTYPE_FILE) {
                szText = encodeUTF8((char *)dbei.pBlob + sizeof(DWORD), NULL, false);
                tmpltName[1] = isHistory ? "hFile" : "File";
			} else if (dbei.eventType == EVENTTYPE_URL) {
                szText = encodeUTF8((char *)dbei.pBlob, NULL, false);
                tmpltName[1] = isHistory ? "hURL" : "URL";
			} else if (dbei.eventType == EVENTTYPE_STATUSCHANGE) {
                szText = encodeUTF8((char *)dbei.pBlob, NULL, false);
                tmpltName[1] = isHistory ? "hStatus" : "Status";
			}
			/* template-specific formatting */
			for (int i=0;i<2;i++) {
				Template *tmplt;
				if (tmpltName[i] == NULL) continue;
				tmplt = (event->dwFlags & IEEF_RTL) ? TemplateMap::getTemplate("default_rtl", tmpltName[i]) : TemplateMap::getTemplate("default", tmpltName[i]);
				if (tmplt == NULL) continue;
				for (Token *token = tmplt->getTokens();token!=NULL;token=token->getNext()) {
					const char *tokenVal;
					tokenVal = NULL;
					switch (token->getType()) {
						case Token::PLAIN:
                            tokenVal = token->getText();
							break;
						case Token::NAME:
                            tokenVal = szName;
							break;
						case Token::TIME:
							if (Options::getTemplatesFlags() & Options::LOG_SHOW_TIME) {
	                            tokenVal = timestampToString(dbei.timestamp, 1);
							} else {
                                tokenVal = "&nbsp;";
							}
							break;
						case Token::DATE:
							if (Options::getTemplatesFlags() & Options::LOG_SHOW_DATE) {
	                            tokenVal = timestampToString(dbei.timestamp, 0);
							} else {
                                tokenVal = "&nbsp;";
							}
							break;
	  					case Token::TEXT:
							tokenVal = szText;
							break;
	  					case Token::AVATAR:
  					    	tokenVal = szAvatar;
							break;
	  					case Token::CID:
							tokenVal = szCID;
							break;
						case Token::BASE:
						    tokenVal = szBase;
						    break;
						case Token::NAMEIN:
		                    tokenVal = szNameIn;
							break;
						case Token::NAMEOUT:
		                    tokenVal = szNameOut;
							break;
						case Token::AVATARIN:
					    	tokenVal = szAvatarIn;
							break;
						case Token::AVATAROUT:
					    	tokenVal = szAvatarOut;
							break;
						case Token::PROTO:
						    tokenVal = szProto;
						    break;
					}
					if (tokenVal != NULL) {
						Utils::appendText(&output, &outputSize, "%s", tokenVal);
					}
				}
			}
			event->hDbEventFirst = hCurDbEvent;
			setLastEventType(MAKELONG(dbei.flags, dbei.eventType));
			setLastEventTime(dbei.timestamp);
			if (szText!=NULL) delete szText;
		}
		if (output != NULL) {
            view->write(output);
			free(output);
		}
        free(dbei.pBlob);
    }
    if (szProto!=NULL) delete szProto;
	if (szAvatarIn!=NULL) delete szAvatarIn;
	if (szAvatarOut!=NULL) delete szAvatarOut;
	if (szNameIn!=NULL) delete szNameIn;
	if (szNameOut!=NULL) delete szNameOut;
	view->scrollToBottom();
}
void TemplateHTMLBuilder::appendEventTemplate(IEView *view, IEVIEWEVENT *event, ProtocolSettings* protoSettings)
{
	DBVARIANT dbv;
	CONTACTINFO ci;
	char *szRealProto = NULL;
	char tempBase[1024];
	char *szBase=NULL;
	char tempStr[1024];
	char *szNoAvatar=NULL;
	char szCID[32];
	char *szName = NULL;
	char *szNameIn = NULL;
	char *szNameOut = NULL;
	char *szUIN = NULL;
	char *szUINIn = NULL;
	char *szUINOut = NULL;
	char *szNickIn = NULL;
	char *szNickOut = NULL;
	char *szStatusMsg = NULL;
	char *szAvatar = NULL;
	char *szAvatarIn = NULL;
	char *szAvatarOut = NULL;
	char *szText = NULL;
	char *szProto = NULL;
	char *szFileDesc = NULL;
	const char *tmpltName[2];
	bool isGrouping = false;
	if (protoSettings == NULL)
		return;
	
	MCONTACT hRealContact = getRealContact(event->hContact);
	szRealProto = getProto(hRealContact);
	szProto = getProto(event->pszProto, event->hContact);
	tempBase[0]='\0';
	TemplateMap *tmpm = getTemplateMap(protoSettings);
	if (tmpm!=NULL) {
		strcpy(tempBase, "file://");
		strcat(tempBase, tmpm->getFilename());
		char* pathrun = tempBase + strlen(tempBase);
		while ((*pathrun != '\\' && *pathrun != '/') && (pathrun > tempBase)) pathrun--;
		pathrun++;
		*pathrun = '\0';
		isGrouping = tmpm->isGrouping();
	}
	szBase = mir_utf8encode(tempBase);

	if (event->hContact != NULL)
		getUINs(event->hContact, szUINIn, szUINOut);

	if (event->hContact != NULL) {
		szNameOut = getEncodedContactName(NULL, szProto, szRealProto);
		szNameIn = getEncodedContactName(event->hContact, szProto, szRealProto);
	}
	else {
		szNameOut = mir_strdup("&nbsp;");
		szNameIn = mir_strdup("&nbsp;");
	}
	TCHAR szNoAvatarPath[MAX_PATH];
	mir_sntprintf(szNoAvatarPath, SIZEOF(szNoAvatarPath), _T("%s"), _A2T(protoSettings->getSRMMTemplateFilename()));
	TCHAR *szNoAvatarPathTmp = _tcsrchr(szNoAvatarPath, '\\');
	if (szNoAvatarPathTmp != NULL)
		*szNoAvatarPathTmp = 0;
	_tcscat(szNoAvatarPath, _T("\\noavatar.png"));
	if (_taccess(szNoAvatarPath, 0) == -1)
		mir_snprintf(tempStr, SIZEOF(tempStr), "%snoavatar.jpg", tempBase);
	else
		mir_snprintf(tempStr, SIZEOF(tempStr), "%snoavatar.png", tempBase);
	szNoAvatar = mir_utf8encode(tempStr);
	if(event->hContact != NULL)
		szAvatarIn = getAvatar(event->hContact, szRealProto);

	if (szAvatarIn == NULL)
		szAvatarIn = mir_strdup(szNoAvatar);

	szAvatarOut = getAvatar(NULL, szRealProto);
	if (szAvatarOut == NULL)
		szAvatarOut = mir_strdup(szNoAvatar);

	if(event->hContact != NULL) {
		if (!db_get(event->hContact, "CList", "StatusMsg",&dbv)) {
			if (strlen(dbv.pszVal) > 0)
				szStatusMsg = mir_utf8encode(dbv.pszVal);
			db_free(&dbv);
		}
	}
	ZeroMemory(&ci, sizeof(ci));
	ci.cbSize = sizeof(ci);
	ci.hContact = event->hContact;
	ci.szProto = szProto;
	ci.dwFlag = CNF_NICK | CNF_TCHAR;
	if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci))
		szNickIn = encodeUTF8(event->hContact, szRealProto, ci.pszVal, ENF_NAMESMILEYS, true);

	ZeroMemory(&ci, sizeof(ci));
	ci.cbSize = sizeof(ci);
	ci.hContact = NULL;
	ci.szProto = szProto;
	ci.dwFlag = CNF_NICK | CNF_TCHAR;
	if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci))
		szNickOut = encodeUTF8(event->hContact, szRealProto, ci.pszVal, ENF_NAMESMILEYS, true);

	IEVIEWEVENTDATA* eventData = event->eventData;
	for (int eventIdx = 0; eventData!=NULL && (eventIdx < event->count || event->count==-1); eventData = eventData->next, eventIdx++) {
		int outputSize;
		char *output = NULL;
		if (eventData->iType == IEED_EVENT_MESSAGE || eventData->iType == IEED_EVENT_STATUSCHANGE || eventData->iType == IEED_EVENT_FILE || eventData->iType == IEED_EVENT_URL || eventData->iType == IEED_EVENT_SYSTEM) {
			bool isSent = (eventData->dwFlags & IEEDF_SENT) != 0;
			bool isRTL = (eventData->dwFlags & IEEDF_RTL) && tmpm->isRTL();
			bool isHistory = (eventData->time < (DWORD)getStartedTime() && (eventData->dwFlags & IEEDF_READ || eventData->dwFlags & IEEDF_SENT));
			bool isGroupBreak = TRUE;
 			if ((getFlags(protoSettings) & Options::LOG_GROUP_MESSAGES) && eventData->dwFlags == LOWORD(getLastEventType()) &&
					eventData->iType == IEED_EVENT_MESSAGE && HIWORD(getLastEventType()) == IEED_EVENT_MESSAGE &&
					(isSameDate(eventData->time, getLastEventTime())) &&
					(((eventData->time < (DWORD)startedTime) == (getLastEventTime() < (DWORD)startedTime)) || !(eventData->dwFlags & IEEDF_READ)))
			{
				isGroupBreak = FALSE;
			}
			if (isSent) {
				szAvatar = szAvatarOut;
				szUIN = szUINOut;
				mir_snprintf(szCID, SIZEOF(szCID), "%d", 0);
			}
			else {
				szAvatar = szAvatarIn;
				szUIN = szUINIn;
				mir_snprintf(szCID, SIZEOF(szCID), "%d", (int)event->hContact);
			}
			tmpltName[0] = groupTemplate;
			tmpltName[1] = NULL;
			groupTemplate = NULL;
			szName = NULL;
			szText = NULL;
			szFileDesc = NULL;
			if (event->eventData->dwFlags & IEEDF_UNICODE_NICK)
				szName = encodeUTF8(event->hContact, szRealProto, eventData->pszNickW, ENF_NAMESMILEYS, true);
			else
				szName = encodeUTF8(event->hContact, szRealProto, eventData->pszNick, ENF_NAMESMILEYS, true);

			if (eventData->dwFlags & IEEDF_UNICODE_TEXT)
				szText = encodeUTF8(event->hContact, szRealProto, eventData->pszTextW, eventData->iType == IEED_EVENT_MESSAGE ? ENF_ALL : 0, isSent);
			else
				szText = encodeUTF8(event->hContact, szRealProto, eventData->pszText, event->codepage, eventData->iType == IEED_EVENT_MESSAGE ? ENF_ALL : 0, isSent);

			if (eventData->dwFlags & IEEDF_UNICODE_TEXT2)
				szFileDesc = encodeUTF8(event->hContact, szRealProto, eventData->pszText2W, 0, isSent);
			else
				szFileDesc = encodeUTF8(event->hContact, szRealProto, eventData->pszText2, event->codepage, 0, isSent);

			if ((eventData->iType == IEED_EVENT_MESSAGE)) {
				if (!isRTL) {
					if (isGrouping && (getFlags(protoSettings) & Options::LOG_GROUP_MESSAGES)) {
						if (isGroupBreak)
							tmpltName[1] = isHistory ? isSent ? "hMessageOutGroupStart" : "hMessageInGroupStart" : isSent ? "MessageOutGroupStart" : "MessageInGroupStart";
						else
							tmpltName[0] = isHistory ? isSent ? "hMessageOutGroupInner" : "hMessageInGroupInner" : isSent ? "MessageOutGroupInner" : "MessageInGroupInner";

						groupTemplate = isHistory ? isSent ? "hMessageOutGroupEnd" : "hMessageInGroupEnd" : isSent ? "MessageOutGroupEnd" : "MessageInGroupEnd";
					}
					else tmpltName[1] = isHistory ? isSent ? "hMessageOut" : "hMessageIn" : isSent ? "MessageOut" : "MessageIn";
				}
				else {
					if (isGrouping && (getFlags(protoSettings) & Options::LOG_GROUP_MESSAGES)) {
						if (isGroupBreak)
							tmpltName[1] = isHistory ? isSent ? "hMessageOutGroupStartRTL" : "hMessageInGroupStartRTL" : isSent ? "MessageOutGroupStartRTL" : "MessageInGroupStartRTL";
						else
							tmpltName[0] = isHistory ? isSent ? "hMessageOutGroupInnerRTL" : "hMessageInGroupInnerRTL" : isSent ? "MessageOutGroupInnerRTL" : "MessageInGroupInnerRTL";

						groupTemplate = isHistory ? isSent ? "hMessageOutGroupEndRTL" : "hMessageInGroupEndRTL" : isSent ? "MessageOutGroupEndRTL" : "MessageInGroupEndRTL";
					}
					else tmpltName[1] = isHistory ? isSent ? "hMessageOutRTL" : "hMessageInRTL" : isSent ? "MessageOutRTL" : "MessageInRTL";
				}
			}
			else if (eventData->iType == IEED_EVENT_FILE) {
				tmpltName[1] = isHistory ? isSent ? "hFileOut" : "hFileIn" : isSent ? "FileOut" : "FileIn";
				Template *tmplt = (tmpm == NULL) ? NULL : tmpm->getTemplate(tmpltName[1]);
				if (tmplt == NULL)
					tmpltName[1] = isHistory ? "hFile" : "File";
			}
			else if (eventData->iType == IEED_EVENT_URL) {
				tmpltName[1] = isHistory ? isSent ? "hURLOut" : "hURLIn" : isSent ? "URLOut" : "URLIn";
				Template *tmplt = (tmpm == NULL) ? NULL : tmpm->getTemplate(tmpltName[1]);
				if (tmplt == NULL)
					tmpltName[1] = isHistory ? "hURL" : "URL";
			}
			else if (eventData->iType == IEED_EVENT_STATUSCHANGE || (eventData->iType == IEED_EVENT_SYSTEM))
				tmpltName[1] = isHistory ? "hStatus" : "Status";

			/* template-specific formatting */
			for (int i=0;i<2;i++) {
				if (tmpltName[i] == NULL || tmpm == NULL) continue;
				Template *tmplt = tmpm->getTemplate(tmpltName[i]);
				if (tmplt == NULL) continue;
				for (Token *token = tmplt->getTokens();token!=NULL;token=token->getNext()) {
					const char *tokenVal;
					tokenVal = NULL;
					switch (token->getType()) {
					case Token::PLAIN:
						tokenVal = token->getText();
						break;
					case Token::INAME:
						if (getFlags(protoSettings) & Options::LOG_SHOW_NICKNAMES)
							tokenVal = szName;
						else
							tokenVal = "&nbsp;";
						break;
					case Token::TIME:
						if (getFlags(protoSettings) & Options::LOG_SHOW_TIME)
							tokenVal = timestampToString(getFlags(protoSettings), eventData->time, 1);
						else
							tokenVal = "&nbsp;";
						break;
					case Token::DATE:
						if (getFlags(protoSettings) & Options::LOG_SHOW_DATE)
							tokenVal = timestampToString(getFlags(protoSettings), eventData->time, 0);
						else
							tokenVal = "&nbsp;";
						break;
					case Token::TEXT:
						tokenVal = szText;
						break;
					case Token::AVATAR:
						tokenVal = szAvatar;
						break;
					case Token::CID:
						tokenVal = szCID;
						break;
					case Token::BASE:
						tokenVal = szBase;
						break;
					case Token::NAMEIN:
						if (getFlags(protoSettings) & Options::LOG_SHOW_NICKNAMES) {
							if (event->hContact != NULL)
								tokenVal = szNameIn;
							else
								tokenVal = szName;
						}
						else tokenVal = "&nbsp;";
						break;
					case Token::NAMEOUT:
						if (getFlags(protoSettings) & Options::LOG_SHOW_NICKNAMES) {
							if (event->hContact != NULL)
								tokenVal = szNameOut;
							else
								tokenVal = szName;
						}
						else tokenVal = "&nbsp;";
						break;
					case Token::AVATARIN:
						tokenVal = szAvatarIn;
						break;
					case Token::AVATAROUT:
						tokenVal = szAvatarOut;
						break;
					case Token::PROTO:
						tokenVal = szRealProto;
						break;
					case Token::UIN:
						tokenVal = szUIN;
						break;
					case Token::UININ:
						tokenVal = szUINIn;
						break;
					case Token::UINOUT:
						tokenVal = szUINOut;
						break;
					case Token::STATUSMSG:
						tokenVal = szStatusMsg;
						break;
					case Token::NICKIN:
						tokenVal = szNickIn;
						break;
					case Token::NICKOUT:
						tokenVal = szNickOut;
						break;
					case Token::FILEDESC:
						tokenVal = szFileDesc;
						break;
					}
					if (tokenVal != NULL) {
						if (token->getEscape())
							Utils::appendText(&output, &outputSize, "%s", ptrA(Utils::escapeString(tokenVal)));
						else
							Utils::appendText(&output, &outputSize, "%s", tokenVal);
					}
				}
			}
			setLastEventType(MAKELONG(eventData->dwFlags, eventData->iType));
			setLastEventTime(eventData->time);
			
			mir_free(szName);
			mir_free(szText);
			mir_free(szFileDesc);
		}
		if (output != NULL) {
			view->write(output);
			free(output);
		}
	}
	mir_free(szBase);
	mir_free(szRealProto);
	mir_free(szProto);
	mir_free(szUINIn);
	mir_free(szUINOut);
	mir_free(szNoAvatar);
	mir_free(szAvatarIn);
	mir_free(szAvatarOut);
	mir_free(szNameIn);
	mir_free(szNameOut);
	mir_free(szNickIn);
	mir_free(szNickOut);
	mir_free(szStatusMsg);
	view->documentClose();
}
void TemplateHTMLBuilder::buildHeadTemplate(IEView *view, IEVIEWEVENT *event, ProtocolSettings *protoSettings)
{
	DBVARIANT dbv;
	CONTACTINFO ci;
	char tempBase[1024];
	char tempStr[1024];
	char *szRealProto = NULL;
	char *szBase=NULL;
	char *szNoAvatar=NULL;
	char *szProto = NULL;
	char *szNameIn = NULL;
	char *szNameOut = NULL;
	char *szAvatarIn = NULL;
	char *szAvatarOut = NULL;
	char *szUINIn = NULL;
	char *szUINOut = NULL;
	char *szNickIn = NULL;
	char *szNickOut = NULL;
	char *szStatusMsg = NULL;
	int outputSize;
	char *output;

	output = NULL;
	MCONTACT hRealContact = getRealContact(event->hContact);
	szRealProto = getProto(hRealContact);
	szProto = getProto(event->pszProto, event->hContact);
	tempBase[0]='\0';
	if (protoSettings == NULL)
		return;

	TemplateMap *tmpm = getTemplateMap(protoSettings);
	if (tmpm==NULL)
		return;

	strcpy(tempBase, "file://");
	strcat(tempBase, tmpm->getFilename());
	char* pathrun = tempBase + strlen(tempBase);
	while ((*pathrun != '\\' && *pathrun != '/') && (pathrun > tempBase)) pathrun--;
	pathrun++;
	*pathrun = '\0';

	szBase = mir_utf8encode(tempBase);
	getUINs(event->hContact, szUINIn, szUINOut);
	if (getFlags(protoSettings) & Options::LOG_SHOW_NICKNAMES) {
		szNameOut = getEncodedContactName(NULL, szProto, szRealProto);
		szNameIn = getEncodedContactName(event->hContact, szProto, szRealProto);
	} else {
		szNameOut = mir_strdup("&nbsp;");
		szNameIn = mir_strdup("&nbsp;");
	}
	mir_snprintf(tempStr, SIZEOF(tempStr), "%snoavatar.png", tempBase);
	TCHAR szNoAvatarPath[MAX_PATH];
	mir_sntprintf(szNoAvatarPath, SIZEOF(szNoAvatarPath), _T("%s"), _A2T(protoSettings->getSRMMTemplateFilename()));
	TCHAR *szNoAvatarPathTmp = _tcsrchr(szNoAvatarPath, '\\');
	if (szNoAvatarPathTmp != NULL)
		*szNoAvatarPathTmp = 0;
	_tcscat(szNoAvatarPath, _T("\\noavatar.png"));
	if (_taccess(szNoAvatarPath, 0) == -1)
		mir_snprintf(tempStr, SIZEOF(tempStr), "%snoavatar.jpg", tempBase);
	else
		mir_snprintf(tempStr, SIZEOF(tempStr), "%snoavatar.png", tempBase);
	szNoAvatar = mir_utf8encode(tempStr);
	szAvatarIn = getAvatar(event->hContact, szRealProto);
	if (szAvatarIn == NULL) {
		szAvatarIn = mir_strdup(szNoAvatar);
	}
	szAvatarOut = getAvatar(NULL, szRealProto);
	if (szAvatarOut == NULL) {
		szAvatarOut = mir_strdup(szNoAvatar);
	}
	if (!db_get(event->hContact, "CList", "StatusMsg",&dbv)) {
		if (strlen(dbv.pszVal) > 0) {
			szStatusMsg = mir_utf8encode(dbv.pszVal);
		}
		db_free(&dbv);
	}
	ZeroMemory(&ci, sizeof(ci));
	ci.cbSize = sizeof(ci);
	ci.hContact = event->hContact;
	ci.szProto = szProto;
	ci.dwFlag = CNF_NICK | CNF_TCHAR;
	if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) {
		szNickIn = encodeUTF8(event->hContact, szRealProto, ci.pszVal, ENF_NAMESMILEYS, true);
	}
	ZeroMemory(&ci, sizeof(ci));
	ci.cbSize = sizeof(ci);
	ci.hContact = NULL;
	ci.szProto = szProto;
	ci.dwFlag = CNF_NICK | CNF_TCHAR;
	if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) {
		szNickOut = encodeUTF8(event->hContact, szRealProto, ci.pszVal, ENF_NAMESMILEYS, true);
	}

	Template *tmplt = tmpm->getTemplate(((event->dwFlags & IEEF_RTL) && tmpm->isRTL()) ? "HTMLStartRTL" : "HTMLStart");
	if (tmplt == NULL) {
		tmplt = tmpm->getTemplate("HTMLStart");
	}
	if (tmplt!=NULL) {
		for (Token *token = tmplt->getTokens();token!=NULL;token=token->getNext()) {
			const char *tokenVal;
			tokenVal = NULL;
			switch (token->getType()) {
				case Token::PLAIN:
					tokenVal = token->getText();
					break;
				case Token::BASE:
					tokenVal = szBase;
					break;
				case Token::NAMEIN:
					tokenVal = szNameIn;
					break;
				case Token::NAMEOUT:
					tokenVal = szNameOut;
					break;
				case Token::AVATARIN:
					tokenVal = szAvatarIn;
					break;
				case Token::AVATAROUT:
					tokenVal = szAvatarOut;
					break;
				case Token::PROTO:
					tokenVal = szRealProto;
					break;
				case Token::UININ:
					tokenVal = szUINIn;
					break;
				case Token::UINOUT:
					tokenVal = szUINOut;
					break;
				case Token::STATUSMSG:
					tokenVal = szStatusMsg;
					break;
				case Token::NICKIN:
					tokenVal = szNickIn;
					break;
 				case Token::NICKOUT:
					tokenVal = szNickOut;
					break;
			}
			if (tokenVal != NULL) {
				if (token->getEscape())
					Utils::appendText(&output, &outputSize, "%s", ptrA(Utils::escapeString(tokenVal)));
				else
					Utils::appendText(&output, &outputSize, "%s", tokenVal);
			}
		}
	}
	if (output != NULL) {
		view->write(output);
		free(output);
	}
	mir_free(szBase);
	mir_free(szRealProto);
	mir_free(szProto);
	mir_free(szUINIn);
	mir_free(szUINOut);
	mir_free(szNoAvatar);
	mir_free(szAvatarIn);
	mir_free(szAvatarOut);
	mir_free(szNameIn);
	mir_free(szNameOut);
	mir_free(szNickIn);
	mir_free(szNickOut);
	mir_free(szStatusMsg);

	groupTemplate = NULL;
	iLastEventType = -1;
}