コード例 #1
0
ファイル: arccmd.cpp プロジェクト: CyberShadow/FAR
int ArcCommand::ProcessCommand(char *Command,int CommandType,int IgnoreErrors,
                               char *ListFileName)
{
  MaxAllowedExitCode=0;
  DeleteBraces(Command);

  for (char *CurPtr=Command;*CurPtr;)
  {
    int Length=lstrlen(Command);
    switch(ReplaceVar(CurPtr,Length))
    {
      case 1:
        CurPtr+=Length;
        break;
      case -1:
        return FALSE;
      default:
        CurPtr++;
        break;
    }
  }

  if (*Command)
  {
    int Hide=Opt.HideOutput;
    if ((Hide==1 && CommandType==0) || CommandType==2)
      Hide=0;
    ExecCode=Execute(this,Command,Hide,Silent,!*Password,ListFileName);
    if(ExecCode==RETEXEC_ARCNOTFOUND)
    {
      return FALSE;
    }
    if (ExecCode<=MaxAllowedExitCode)
      ExecCode=0;
    if (!IgnoreErrors && ExecCode!=0)
    {
      if(!Silent)
      {
        char ErrMsg[200];
        char NameMsg[NM];
        FSF.sprintf(ErrMsg,(char *)GetMsg(MArcNonZero),ExecCode);
        const char *MsgItems[]={GetMsg(MError),NameMsg,ErrMsg,GetMsg(MOk)};
        FSF.TruncPathStr(lstrcpyn(NameMsg,ArcName,sizeof(NameMsg)),MAX_WIDTH_MESSAGE);
        Info.Message(Info.ModuleNumber,FMSG_WARNING,NULL,MsgItems,ARRAYSIZE(MsgItems),1);
      }
      return FALSE;
    }
  }
  else
  {
    if(!Silent)
    {
      const char *MsgItems[]={GetMsg(MError),GetMsg(MArcCommandNotFound),GetMsg(MOk)};
      Info.Message(Info.ModuleNumber,FMSG_WARNING,NULL,MsgItems,ARRAYSIZE(MsgItems),1);
    }
    return FALSE;
  }
  return TRUE;
}
コード例 #2
0
ファイル: arccmd.cpp プロジェクト: CyberShadow/FAR
void ArcCommand::DeleteBraces(char *Command)
{
  char CheckStr[512],*CurPtr,*EndPtr;
  int NonEmptyVar;
  while (1)
  {
    if ((Command=strchr(Command,'{'))==NULL)
      return;
    if ((EndPtr=strchr(Command+1,'}'))==NULL)
      return;
    for (NonEmptyVar=0,CurPtr=Command+1;CurPtr<EndPtr-2;CurPtr++)
    {
      int Length;
      lstrcpyn(CheckStr,CurPtr,4);
      if (CheckStr[0]=='%' && CheckStr[1]=='%' && strchr("FfLl",CheckStr[2])!=NULL)
      {
        NonEmptyVar=(ItemsNumber>0);
        break;
      }
      Length=0;
      if (ReplaceVar(CheckStr,Length))
        if (Length>0)
        {
          NonEmptyVar=1;
          break;
        }
    }

    if (NonEmptyVar)
    {
      *Command=*EndPtr=' ';
      Command=EndPtr+1;
    }
    else
    {
      char TmpStr[MAX_COMMAND_LENGTH];
      lstrcpy(TmpStr,EndPtr+1);
      lstrcpy(Command,TmpStr);
    }
  }
}
コード例 #3
0
ファイル: arccmd.cpp プロジェクト: elfmz/far2l
void ArcCommand::DeleteBraces(std::string &Command)
{
  std::string CheckStr;
  for (size_t left = std::string::npos;;)
  {
    size_t right = Command.rfind('}', left);
    if (right == std::string::npos || right == 0)
      return;

    left = Command.rfind('{', right - 1);
    if (right == std::string::npos)
      return;

    bool NonEmptyVar = false;
    for (size_t i = left + 1; i + 2 < right; ++i)
    {
      if (Command[i] == '%' && Command[i + 1] == '%'  && strchr("FfLl", Command[i + 2]) != NULL)
      {
        NonEmptyVar = (ItemsNumber > 0);
        break;
      }
      CheckStr.assign(Command.c_str() + i, std::min((size_t)4, right - i));
      if (ReplaceVar(CheckStr) && CheckStr.size() > 0)
      {
        NonEmptyVar = true;
        break;
      }
    }

    if (NonEmptyVar)
    {
      Command[left] = ' ';
      Command[right] = ' ';
    }
    else
    {
      Command.erase(left, right - left + 1);
    }
  }
}
コード例 #4
0
ファイル: variable.cpp プロジェクト: jjkee/hyphy
//__________________________________________________________________________________
void    _Variable::ClearConstraints (void)
{
    if (IsCategory ()) {
        _Variable newVar (*GetName(), IsGlobal());
        newVar.SetValue ((_PMathObj)Compute()->makeDynamic(),false);
        ReplaceVar ( &newVar);
        /*_Matrix * modelMatrix = (_Matrix*)LocateVar(modelMatrixIndices.lData[1])->GetValue();
        for (long k=0; k<4; k++)
            for (long k2 = 0; k2<4; k2++)
                if (k!=k2)
                {
                    StringToConsole (*(_String*)modelMatrix->GetFormula(k,k2)->toStr());
                    BufferToConsole ("\n");
                }
        */
    } else {
        if (!IsIndependent()) {
            SetValue ((_PMathObj)Compute()->makeDynamic(),false);
        }
        SetBounds (DEFAULTLOWERBOUND,DEFAULTUPPERBOUND);
    }
}
コード例 #5
0
ファイル: utils.cpp プロジェクト: 0xmono/miranda-ng
TCHAR* ReplaceVarsNum(TCHAR *dst, unsigned int len, int num)
{
	TCHAR response[2048];
	int ret, i = 1;
	pcre *re;
	const char *error;
	int erroroffs, rc;
	char *_str, *tmp;
	TCHAR **r;
	TCHAR *ttmp, *dstcopy;
	int opts = 0;
	char regex[] = "%response([#-_]([0-9]+))?%";
	int ovector[9];

	re = pcre_compile(regex, 0, &error, &erroroffs, NULL);
	if (!re)
		return FALSE; // [TODO] and log some error
	
	_getOptS(response, 2048, "Response", defaultResponse);	

	r = (TCHAR**)malloc(sizeof(char*));
	ttmp = _tcstok(response, L"\r\n");
	r[0] = ttmp;
	while(ttmp) {
		ttmp = _tcstok(NULL, L"\r\n");
		if (ttmp != NULL) {
			r = (TCHAR**)realloc(r, (i+1)*sizeof(TCHAR*));
			r[i++] = ttmp;
		}
	}

	do {
		_str = mir_u2a(dst);
		dstcopy = (TCHAR*)malloc((_tcslen(dst)+1)*sizeof(TCHAR));
		_tcscpy(dstcopy, dst);
		
		rc = pcre_exec(re, NULL, _str, (int)strlen(_str), 0, 0, ovector, 9);
		if (rc < 0) {
			ret = -1;
		} else if (rc == 3) {
			ttmp = dstcopy + ovector[0];
			ttmp[ovector[1]-ovector[0]] = 0;
			tmp = _str + ovector[4];
			tmp[ovector[5]-ovector[4]] = 0;
			ret = atoi(tmp);
		} else {
			ttmp = dstcopy + ovector[0];
			ttmp[ovector[1]-ovector[0]] = 0;
			ret = 0;
		}

		if (ret >= 0) {
			if (ret > i)
				ReplaceVar(dst, len, ttmp, r[0]);
			else if (ret == 0 && num > 0 && num < i)
				ReplaceVar(dst, len, ttmp, r[num]);
			else
				ReplaceVar(dst, len, ttmp, r[ret == 0 ? 0 : ret-1]);
		}

		if (_str)
			mir_free(_str);
		if (dstcopy)
			free(dstcopy);
	} while (rc >= 0);

	if (re)
		pcre_free(re);

	return dst;
} 
コード例 #6
0
ファイル: arccmd.cpp プロジェクト: elfmz/far2l
bool ArcCommand::ProcessCommand(std::string FormatString, int CommandType, int IgnoreErrors,
                               char *pcListFileName)
{
  MaxAllowedExitCode=0;
  DeleteBraces(FormatString);

//  for (char *CurPtr=Command; *CurPtr;)
  std::string tmp, NonVar, Command;
  while (!FormatString.empty())
  {
    tmp = FormatString;
    int r = ReplaceVar(tmp);
//    fprintf(stderr, "ReplaceVar: %d  '%s' -> '%s'\n", r, FormatString.c_str(), tmp.c_str());
    if (r < 0)
      return false;
    if (r == 0) {
      r = 1;
      NonVar+= FormatString[0];
    } else {
      Command+= ExpandEnv(NonVar);
      Command+= tmp;
      NonVar.clear();
    }

    FormatString.erase(0, r);
  }
  Command+= ExpandEnv(NonVar);
//  fprintf(stderr, "Command='%s'\n", Command.c_str());

  if (Command.empty())
  {
    if(!Silent)
    {
      const char *MsgItems[]={GetMsg(MError),GetMsg(MArcCommandNotFound),GetMsg(MOk)};
      Info.Message(Info.ModuleNumber,FMSG_WARNING,NULL,MsgItems,ARRAYSIZE(MsgItems),1);
    }
    return false;
  }

  int Hide = Opt.HideOutput;
  if ((Hide == 1 && CommandType == 0) || CommandType == 2)
    Hide = 0;

  ExecCode = Execute(this, Command, Hide, Silent, NeedSudo, Password.empty(), ListFileName);
  if (ExecCode==RETEXEC_ARCNOTFOUND)
    return false;

  if (ExecCode <= MaxAllowedExitCode)
    ExecCode = 0;

  if (!IgnoreErrors && ExecCode!=0)
  {
    if(!Silent)
    {
      char ErrMsg[200];
      char NameMsg[NM];
      FSF.sprintf(ErrMsg,(char *)GetMsg(MArcNonZero),ExecCode);
      const char *MsgItems[]={GetMsg(MError),NameMsg,ErrMsg,GetMsg(MOk)};

      FSF.TruncPathStr(strncpy(NameMsg,ArcName.c_str(),sizeof(NameMsg)),MAX_WIDTH_MESSAGE);
      Info.Message(Info.ModuleNumber,FMSG_WARNING,NULL,MsgItems,ARRAYSIZE(MsgItems),1);
    }
    return false;
  }

  return true;
}
コード例 #7
0
int OnDBEventFilterAdd(WPARAM wParam, LPARAM lParam)
{
	HANDLE hContact = (HANDLE)wParam;
	DBEVENTINFO *dbei = (DBEVENTINFO *)lParam;
	char *msgblob;
	POPUPDATA ppdp = {0};
	DBTIMETOSTRING tts = {0};
	char protoOption[256] = {0};
	char *response, *tmp, *challenge;
	int buflen = MAX_BUFFER_LENGTH;
	TCHAR buf[MAX_BUFFER_LENGTH];
	TCHAR *message = NULL, *challengeW = NULL, *tmpW = NULL;
	TCHAR *whitelist = NULL, *ptok;
	TCHAR mexpr[64];
	int maxmsglen = 0, a, b, i;
	BOOL bayesEnabled = _getOptB("BayesEnabled", defaultBayesEnabled);
	BOOL bCorrectResponse = FALSE;

	// get hContact from DBEVENTINFO as icq_proto.c doesn't pass hContact the usual way for some reason.
	if (dbei->eventType == EVENTTYPE_AUTHREQUEST)
		hContact = *((PHANDLE)(dbei->pBlob+sizeof(DWORD)));

	// get maximum length of the message a protocol supports
	maxmsglen = CallProtoService(dbei->szModule, PS_GETCAPS, PFLAG_MAXLENOFMESSAGE, (LPARAM)hContact);

	
	/*** Dequeue and learn messages ***/
	
	if (bayesEnabled && _getOptB("BayesAutolearnNotApproved", defaultBayesAutolearnNotApproved))
		if (time(NULL) - last_queue_check > 4*3600) { // dequeue every 4 hours
			dequeue_messages();
			last_queue_check = time(NULL);
		}


	/*** Check for conditional and unconditional approval ***/

	// Pass-through if protocol is not enabled
	strcat(protoOption, "proto_");
	strcat(protoOption, dbei->szModule);
	if (_getOptB(protoOption, 0) == 0) // Protocol is not handled by Spam-o-tron
		return 0;

	// Pass-through if the event is not of type EVENTTYPE_MESSAGE or EVENTTYPE_AUTHREQUEST
	if (dbei->eventType != EVENTTYPE_MESSAGE && dbei->eventType != EVENTTYPE_AUTHREQUEST)
		return 0;

	// Pass-through if contact is already verified.
	if (_getCOptB(hContact, "Verified", 0) == 1)
		return 0;

	// Pass-through if the event is already read.
	if (dbei->flags & DBEF_READ)
		return 0;

	// Pass-through if event is from a contact that is already in the list. 
	if (db_get_b(hContact, "CList", "NotOnList", 1) == 0) // Already in the list
		return 0;

	// Pass-through if event is from a contact that is already in the server-side contact list
	if (db_get_w(hContact, dbei->szModule, "ServerId", 0))
		return 0;

	// Pass-through if contact is a MetaContact
	if (db_get_dw(hContact, "MetaContacts", "NumContacts", 0))
		return 0;

	// Pass-through and approve if outgoing event.
	if (dbei->flags & DBEF_SENT) {
		if (_getOptB("ApproveOnMsgOut", 0)) {
			_setCOptB(hContact, "Verified", 1);
			if (_getOptB("AddPermanently", defaultAddPermanently))
				db_unset(hContact, "CList", "NotOnList");
			db_unset(hContact, "CList", "Delete");
		}
		return 0;
	}

	// Hide the contact until verified if option set.
	if (_getOptB("HideUnverified", defaultHideUnverified))
		db_set_b(hContact, "CList", "Hidden", 1);

	// Fetch the incoming message body
	if (dbei->eventType == EVENTTYPE_MESSAGE) {
		msgblob = (char *)dbei->pBlob;
	} else if (dbei->eventType == EVENTTYPE_AUTHREQUEST) {
		msgblob = (char *)(dbei->pBlob + sizeof(DWORD) + sizeof(HANDLE));
		for(a=4;a>0;a--)
			msgblob += strlen(msgblob)+1;
	}

	if (dbei->flags & DBEF_UTF)
		message = mir_utf8decodeW(msgblob);
	else
		message = mir_a2u(msgblob);

	
	/*** Check for words in white-list ***/

	if (_getOptB("ApproveOnMsgIn", defaultApproveOnMsgIn)) {
		whitelist = (TCHAR*)malloc(2048 * sizeof(TCHAR));
		if (whitelist != NULL) {
			_getOptS(whitelist, 2048, "ApproveOnMsgInWordlist", defaultApproveOnMsgInWordlist);
			if (_isregex(whitelist)) {
				if (_regmatch(message, whitelist))
					bCorrectResponse = TRUE;
			} else {
				ptok = _tcstok(whitelist, L" ");
				while (ptok != NULL) {
					if (_tcsstr(message, ptok)) {
						bCorrectResponse = TRUE;
						break;
					}
					ptok = _tcstok(NULL, L" ");
				}
			}
			free(whitelist);

			if (bCorrectResponse) {
				_setCOptB(hContact, "Verified", 1);
				if (_getOptB("HideUnverified", defaultHideUnverified))
					db_unset(hContact, "CList", "Hidden");
				if (_getOptB("AddPermanently", defaultAddPermanently))
					db_unset(hContact, "CList", "NotOnList");
				db_unset(hContact, "CList", "Delete");
				if (_getOptB("ReplyOnSuccess", defaultReplyOnSuccess) && (_getCOptB(hContact, "MsgSent", 0))) {
					tmp = mir_u2a(_getOptS(buf, buflen, "SuccessResponse", defaultSuccessResponse));
					response = mir_utf8encode(tmp);
					mir_free(tmp);
					CallContactService(hContact, PSS_MESSAGE, PREF_UTF,	(LPARAM)response);
					mir_free(response);
				}
				return 0;
			}
		}
	}


	/*** Check for correct answer ***/
	
	switch (_getOptB("Mode", defaultMode))
	{
		case SPAMOTRON_MODE_ROTATE:
		case SPAMOTRON_MODE_RANDOM:
			get_response(buf, buflen, _getCOptD(hContact, "ResponseNum", 0));
			if (_isregex(buf)) {
				if (_regmatch(message, buf))
					bCorrectResponse = TRUE;
			} else {
				if (_tcsstr_cc(message, buf, _getOptB("ResponseCC", defaultResponseCC)) &&
					(_tcslen(message) == _tcslen(buf)))
					bCorrectResponse = TRUE;
			}
			break;
		
		case SPAMOTRON_MODE_PLAIN:
			_getOptS(buf, buflen, "Response", defaultResponse);
			i = get_response_num(buf);
			while (i-- > 0) {
				get_response(buf, buflen, i-1);
				if (_isregex(buf)) {
					if (_regmatch(message, buf)) {
						bCorrectResponse = TRUE;
						break;
					}
				} else {
					if (_tcsstr_cc(message, buf, _getOptB("ResponseCC", defaultResponseCC)) &&
						(_tcslen(message) == _tcslen(buf))) {
						bCorrectResponse = TRUE;
						break;
					}
				}
			}
			break;

		case SPAMOTRON_MODE_MATH:
			if (message == NULL)
				break;
			_itot(_getCOptD(hContact, "ResponseMath", -1), buf, 10);
			if (_tcsstr(message, buf) && (_tcslen(buf) == _tcslen(message))) {
				bCorrectResponse = TRUE;
			}
			break;
	}

	if (bCorrectResponse)
	{
		_setCOptB(hContact, "Verified", 1);
		if (_getOptB("HideUnverified", defaultHideUnverified))
			db_unset(hContact, "CList", "Hidden");
		if (_getOptB("AddPermanently", defaultAddPermanently))
			db_unset(hContact, "CList", "NotOnList");
		db_unset(hContact, "CList", "Delete");
		db_unset(hContact, "CList", "ResponseNum");
		if (_getOptB("ReplyOnSuccess", defaultReplyOnSuccess)) {
			tmp = mir_u2a(_getOptS(buf, buflen, "SuccessResponse", defaultSuccessResponse));
			response = mir_utf8encode(tmp);
			mir_free(tmp);
			CallContactService(hContact, PSS_MESSAGE, PREF_UTF,	(LPARAM)response);
			mir_free(response);
		}
		_notify(hContact, POPUP_APPROVED, TranslateT("Contact %s approved."), NULL);

		// Resubmit pending authorization request
		if (_getCOptB(hContact, "AuthEventPending", FALSE)) {
			DBVARIANT _dbv;
			TCHAR AuthEventModule[100];
			char* szAuthEventModule;
			if (db_get(hContact, PLUGIN_NAME, "AuthEvent", &_dbv) == 0) {
				DBEVENTINFO *_dbei = (DBEVENTINFO *)malloc(sizeof(DBEVENTINFO));
				if (_dbei != NULL) {
					memcpy(&_dbei->cbBlob, _dbv.pbVal, sizeof(DWORD));
					_dbei->eventType = EVENTTYPE_AUTHREQUEST;
					_getCOptS(AuthEventModule, 100, hContact, "AuthEventModule", _T("ICQ"));
					szAuthEventModule = mir_u2a(AuthEventModule);
					_dbei->szModule = szAuthEventModule;
					_dbei->timestamp = dbei->timestamp;
					_dbei->flags = 0;
					_dbei->cbSize = sizeof(DBEVENTINFO);
					_dbei->pBlob = _dbv.pbVal + sizeof(DWORD);
					db_event_add(hContact,_dbei);
					db_unset(hContact, PLUGIN_NAME, "AuthEvent");
					db_unset(hContact, PLUGIN_NAME, "AuthEventPending");
					db_unset(hContact, PLUGIN_NAME, "AuthEventModule");
					mir_free(szAuthEventModule);
					free(_dbei);
				}
				db_free(&_dbv);
			}
		}

		// User approved, learn from previous messages
		if (bayesEnabled && _getOptB("BayesAutolearnApproved", defaultBayesAutolearnApproved))
			bayes_approve_contact(hContact);

		// Mark previous messages unread if option set
		if (_getOptB("KeepBlockedMsg", defaultKeepBlockedMsg) && 
			_getOptB("MarkMsgUnreadOnApproval", defaultMarkMsgUnreadOnApproval) &&
			hContact != NULL) {
			// We will mark unread all blocked messages for the most recent day
			MarkUnread(hContact);
		}

		return 1;
	}


	
	/*** Check for rejection ***/

	// Completely reject if challenge was already sent today for MaxMsgContactCountPerDay times
	// and the option is turned on.
	if (isOneDay(dbei->timestamp, _getCOptD(hContact, "MsgSentTime", 0)) &&
		_getOptD("MaxMsgContactCountPerDay", defaultMaxMsgContactCountPerDay) > 0 &&
		_getCOptD(hContact, "MsgSent", 0) >= _getOptD("MaxMsgContactCountPerDay", defaultMaxMsgContactCountPerDay)) {
			_notify(hContact, POPUP_BLOCKED, TranslateT("Message from %s rejected because it reached a maximum for challenge requests per day."), message);
			if (bayesEnabled)
				queue_message(hContact, dbei->timestamp, message);
			return 1;
	}

	// Completely reject if duplicate incoming message found
	if (_getOptD("MaxSameMsgCountPerDay", defaultMaxSameMsgCountPerDay) > 0 &&
		_getCOptD(hContact, "SameMsgCount", 0) >= _getOptD("MaxSameMsgCountPerDay", defaultMaxSameMsgCountPerDay) &&
		_tcscmp(message, _getCOptS(buf, buflen, hContact, "LastInMsg", _T(""))) == 0) {
			_notify(hContact, POPUP_BLOCKED, TranslateT("Message from %s rejected because it reached a maximum for same responses per day."), message);
			if (bayesEnabled)
				queue_message(hContact, dbei->timestamp, message);
			return 1;
	}

	// Completely reject if incoming message contains any word from DontReplyMsgWordlist option
	if (_getOptB("DontReplyMsg", defaultDontReplyMsg) &&
		Contains(message, _getOptS(buf, buflen, "DontReplyMsgWordlist", defaultDontReplyMsgWordlist))) {
		_notify(hContact, POPUP_BLOCKED, TranslateT("Message from %s dropped because it has a word from black list."), message);
		return 1;
	}

	
	/*** Bayes checks ***/

	// Drop if score > spam score
	if (bayesEnabled && _getOptB("BayesBlockMsg", defaultBayesBlockMsg))
		if (get_msg_score(message) >= (double)_getOptD("BayesSpamScore", defaultBayesSpamScore) * SCORE_C) {
			_notify(hContact, POPUP_BLOCKED, TranslateT("Message from %s dropped because of high spam score."), message);
			if (bayesEnabled && _getOptB("BayesAutolearnNotApproved", defaultBayesAutolearnNotApproved))
				queue_message(hContact, dbei->timestamp, message);
			return 1;
		}

	// Accept if score < ham score
	if (bayesEnabled && _getOptB("BayesAutoApprove", defaultBayesAutoApprove)) 
		if (get_msg_score(message) <= (double)_getOptD("BayesHamScore", defaultBayesHamScore) * SCORE_C) {
			_notify(hContact, POPUP_APPROVED, TranslateT("Contact %s approved."), message);
			_setCOptB(hContact, "Verified", 1);
			if (_getOptB("HideUnverified", defaultHideUnverified))
				db_unset(hContact, "CList", "Hidden");
			if (_getOptB("AddPermanently", defaultAddPermanently))
				db_unset(hContact, "CList", "NotOnList");
			db_unset(hContact, "CList", "Delete");
			if (bayesEnabled && 
				_getOptB("BayesAutolearnApproved", defaultBayesAutolearnApproved) &&
				_getOptB("BayesAutolearnAutoApproved", defaultBayesAutolearnAutoApproved)) {
				queue_message(hContact, dbei->timestamp, message);
				bayes_approve_contact(hContact);
			}
			return 0;
		}

	// Accept if event is EVENTTYPE_AUTHREQUEST and ReplyOnAuth is NOT set
		if (dbei->eventType == EVENTTYPE_AUTHREQUEST && !_getOptB("ReplyOnAuth", defaultReplyOnAuth))
			return 0;
	// Accept if event is EVENTTYPE_MESSAGE and ReplyOnMsg is NOT set
		if (dbei->eventType == EVENTTYPE_MESSAGE && !_getOptB("ReplyOnMsg", defaultReplyOnMsg))
			return 0;
		
	/*** Send Challenge ***/

	challengeW = (TCHAR *)malloc(maxmsglen*sizeof(TCHAR));
	tmpW = (TCHAR *)malloc(maxmsglen*sizeof(TCHAR));
	switch (_getOptB("Mode", defaultMode))
	{
		case SPAMOTRON_MODE_PLAIN:
			if (dbei->eventType == EVENTTYPE_AUTHREQUEST)
				_getOptS(challengeW, maxmsglen, "AuthChallenge", defaultAuthChallenge);
			else
				_getOptS(challengeW, maxmsglen, "Challenge", defaultChallenge);
			ReplaceVars(challengeW, maxmsglen);
			tmp = mir_u2a(challengeW);
			challenge = mir_utf8encode(tmp);
			mir_free(tmp);
			CallContactService(hContact, PSS_MESSAGE, PREF_UTF, (LPARAM)challenge);
			mir_free(challenge);
			_notify(hContact, POPUP_CHALLENGE, TranslateT("Sending plain challenge to %s."), message);
			break;
		
		case SPAMOTRON_MODE_ROTATE:
			if (dbei->eventType == EVENTTYPE_AUTHREQUEST)
				_getOptS(challengeW, maxmsglen, "AuthChallenge", defaultAuthChallenge);
			else
				_getOptS(challengeW, maxmsglen, "Challenge", defaultChallenge);
			_getOptS(buf, buflen, "Response", defaultResponse);
			if (_getCOptD(hContact, "ResponseNum", 0) >= (unsigned int)(get_response_num(buf)-1)) {
				_setCOptD(hContact, "ResponseNum", -1);
			}
			_setCOptD(hContact, "ResponseNum", _getCOptD(hContact, "ResponseNum", -1) + 1);
			ReplaceVarsNum(challengeW, maxmsglen, _getCOptD(hContact, "ResponseNum", 0));

			tmp = mir_u2a(challengeW);
			challenge = mir_utf8encode(tmp);
			mir_free(tmp);
			CallContactService(hContact, PSS_MESSAGE, PREF_UTF, (LPARAM)challenge);
			mir_free(challenge);
			_notify(hContact, POPUP_CHALLENGE, TranslateT("Sending round-robin challenge to %s."), message);
			break;

		case SPAMOTRON_MODE_RANDOM:
			if (dbei->eventType == EVENTTYPE_AUTHREQUEST)
				_getOptS(challengeW, maxmsglen, "AuthChallenge", defaultAuthChallenge);
			else
				_getOptS(challengeW, maxmsglen, "Challenge", defaultChallenge);
			_getOptS(buf, buflen, "Response", defaultResponse);
			srand(time(NULL));
			_setCOptD(hContact, "ResponseNum", rand() % get_response_num(buf));
			ReplaceVarsNum(challengeW, maxmsglen, _getCOptD(hContact, "ResponseNum", 0));
			tmp = mir_u2a(challengeW);
			challenge = mir_utf8encode(tmp);
			mir_free(tmp);
			CallContactService(hContact, PSS_MESSAGE, PREF_UTF, (LPARAM)challenge);
			mir_free(challenge);
			_notify(hContact, POPUP_CHALLENGE, TranslateT("Sending random challenge to %s."), message);
			break;

		case SPAMOTRON_MODE_MATH:
			a = (rand() % 10) + 1;
			b = (rand() % 10) + 1;
			mir_sntprintf(mexpr, sizeof(mexpr), _T("%d + %d"), a, b);
			if (dbei->eventType == EVENTTYPE_AUTHREQUEST)
				_getOptS(challengeW, maxmsglen, "AuthChallengeMath", defaultAuthChallengeMath);
			else
				_getOptS(challengeW, maxmsglen, "ChallengeMath", defaultChallengeMath);
			ReplaceVar(challengeW, maxmsglen, _T("%mathexpr%"), mexpr);
			_setCOptD(hContact, "ResponseMath", a + b);
			tmp = mir_u2a(challengeW);
			challenge = mir_utf8encode(tmp);
			mir_free(tmp);
			CallContactService(hContact, PSS_MESSAGE, PREF_UTF, (LPARAM)challenge);
			mir_free(challenge);
			_notify(hContact, POPUP_CHALLENGE, TranslateT("Sending math expression challenge to %s."), message);
			break;
	}
	free(challengeW);
	free(tmpW);

	// As a workaround for temporary NotOnList contact not being deleted from server-side list
	// (which was added by the ICQ server itself upon first outgoing challenge request message)
	// we need to set Delete setting, so that contacts gets deleted on next restart/connect.
	db_set_b(hContact, "CList", "Delete", 1);

	// Queue user message in Bayes db
	if (bayesEnabled && message != NULL)
		queue_message(hContact, dbei->timestamp, message);


	/*** Do any post-send procedures we need to do ***/

	// Increment MsgSent if it was sent the same day. Otherwise set it to 1.
	if (isOneDay(dbei->timestamp, _getCOptD(hContact, "MsgSentTime",0)))
		_setCOptD(hContact, "MsgSent", _getCOptD(hContact, "MsgSent", 0)+1);
	else 
		_setCOptD(hContact, "MsgSent", 1);
	_setCOptD(hContact, "MsgSentTime", dbei->timestamp);

	// Save Last Msg and update SameMsgCount
	if (message != NULL) {
		if (_tcscmp(_getCOptS(buf, buflen, hContact, "LastInMsg", _T("")), message) == 0)
			_setCOptD(hContact, "SameMsgCount", 1+_getCOptD(hContact, "SameMsgCount", 0));
		else 
			_setCOptD(hContact, "SameMsgCount", 1);
		_setCOptTS(hContact, "LastInMsg", message);
	}

	if (message != NULL)
		mir_free(message);

	// Finally silently save the message to contact history if corresponding option is set
	if (_getOptB("KeepBlockedMsg", defaultKeepBlockedMsg)) {
		if (dbei->eventType == EVENTTYPE_AUTHREQUEST) {
			// Save the request to database so that it can be automatically submitted on user approval
			PBYTE eventdata = (PBYTE)malloc(sizeof(DWORD) + dbei->cbBlob);
			if (eventdata != NULL && dbei->cbBlob > 0) {
				memcpy(eventdata, &dbei->cbBlob, sizeof(DWORD));
				memcpy(eventdata + sizeof(DWORD), dbei->pBlob, dbei->cbBlob);
				db_set_blob(hContact, PLUGIN_NAME, "AuthEvent", eventdata, sizeof(DWORD) + dbei->cbBlob);
				_setCOptS(hContact, "AuthEventModule", dbei->szModule);
				_setCOptB(hContact, "AuthEventPending", TRUE);
				free(eventdata);
			}
		} else {
			if (_getOptB("MarkMsgUnreadOnApproval", defaultMarkMsgUnreadOnApproval)) {
				DBVARIANT _dbv;
				DWORD dbei_size = 3*sizeof(DWORD) + sizeof(WORD) + dbei->cbBlob + (DWORD)strlen(dbei->szModule)+1;
				PBYTE eventdata = (PBYTE)malloc(dbei_size);
				PBYTE pos = eventdata;
				if (eventdata != NULL && dbei->cbBlob > 0) {
					if (db_get(hContact, PLUGIN_NAME, "LastMsgEvents", &_dbv) == 0) {
						eventdata = (PBYTE)realloc(eventdata, dbei_size + _dbv.cpbVal);
						pos = eventdata;
						memcpy(eventdata, _dbv.pbVal, _dbv.cpbVal);
						pos += _dbv.cpbVal;
						db_free(&_dbv);
					}
					memcpy(pos, &dbei->eventType, sizeof(WORD));
					memcpy(pos+sizeof(WORD), &dbei->flags, sizeof(DWORD));
					memcpy(pos+sizeof(WORD)+sizeof(DWORD), &dbei->timestamp, sizeof(DWORD));
					memcpy(pos+sizeof(WORD)+sizeof(DWORD)*2, dbei->szModule, strlen(dbei->szModule)+1);
					memcpy(pos+sizeof(WORD)+sizeof(DWORD)*2+strlen(dbei->szModule)+1, &dbei->cbBlob, sizeof(DWORD));
					memcpy(pos+sizeof(WORD)+sizeof(DWORD)*3+strlen(dbei->szModule)+1, dbei->pBlob, dbei->cbBlob);
					db_set_blob(hContact, PLUGIN_NAME, "LastMsgEvents", eventdata, (pos - eventdata) + dbei_size);
					free(eventdata);
				}
				
			} else {
				dbei->flags |= DBEF_READ;
				db_event_add(hContact, dbei);
			}
		}
	}
	return 1;
}