long CMUSHclientDoc::SetTriggerOption(LPCTSTR TriggerName, LPCTSTR OptionName, LPCTSTR Value) { CString strTriggerName = TriggerName; CString strValue = Value; CTrigger * trigger_item; // trim spaces from name, make lower-case CheckObjectName (strTriggerName, false); if (!GetTriggerMap ().Lookup (strTriggerName, trigger_item)) return eTriggerNotFound; CString strOptionName = OptionName; strOptionName.MakeLower(); strOptionName.TrimLeft (); strOptionName.TrimRight (); int iItem; int iResult = FindBaseOption (strOptionName, TriggerOptionsTable, iItem); bool bChanged; if (iResult == eOK) { // this is a numeric option // for boolean options, accept "y" or "n" if (TriggerOptionsTable [iItem].iMinimum == 0 && TriggerOptionsTable [iItem].iMaximum == 0) { if (strValue == "Y" || strValue == "y") Value = "1"; else if (strValue == "N" || strValue == "n") Value = "0"; } if (!IsNumber (Value, true)) return eOptionOutOfRange; long iValue = atol (Value); if (m_CurrentPlugin && (TriggerOptionsTable [iItem].iFlags & OPT_PLUGIN_CANNOT_WRITE)) return ePluginCannotSetOption; // not available to plugin if (TriggerOptionsTable [iItem].iFlags & OPT_CANNOT_WRITE) return ePluginCannotSetOption; // not available for writing at all iResult = SetBaseOptionItem (iItem, TriggerOptionsTable, NUMITEMS (TriggerOptionsTable), (char *) trigger_item, iValue, bChanged); if (bChanged) { if (!m_CurrentPlugin) // plugin mods don't really count SetModifiedFlag (TRUE); // document has changed trigger_item->nUpdateNumber = App.GetUniqueNumber (); // for concurrency checks } if (strOptionName == "sequence") SortTriggers (); return iResult; } // end of found else { // not numeric option, try alpha int iResult = FindBaseAlphaOption (strOptionName, TriggerAlphaOptionsTable, iItem); if (iResult == eOK) { // alpha option if (m_CurrentPlugin && (TriggerAlphaOptionsTable [iItem].iFlags & OPT_PLUGIN_CANNOT_WRITE)) return ePluginCannotSetOption; // not available to plugin if (TriggerAlphaOptionsTable [iItem].iFlags & OPT_CANNOT_WRITE) return ePluginCannotSetOption; // not available for writing at all // ------ preliminary validation before setting the option // cannot have null match text if (strOptionName == "match" || strOptionName == "ignore_case" || strOptionName == "multi_line") { if (strValue.IsEmpty ()) return eTriggerCannotBeEmpty; t_regexp * regexp = NULL; CString strRegexp; if (trigger_item->bRegexp) strRegexp = strValue; else strRegexp = ConvertToRegularExpression (strValue); // compile regular expression try { regexp = regcomp (strRegexp, (trigger_item->ignore_case ? PCRE_CASELESS : 0) | (trigger_item->bMultiLine ? PCRE_MULTILINE : 0) | (m_bUTF_8 ? PCRE_UTF8 : 0) ); } // end of try catch(CException* e) { e->Delete (); return eBadRegularExpression; } // end of catch delete trigger_item->regexp; // get rid of old one trigger_item->regexp = regexp; } // end of option "match" else if (strOptionName == "script") { // get trigger dispatch ID if (GetScriptEngine () && !strValue.IsEmpty ()) { DISPID dispid = DISPID_UNKNOWN; CString strMessage; dispid = GetProcedureDispid (strValue, "trigger", TriggerName, strMessage); if (dispid == DISPID_UNKNOWN) return eScriptNameNotLocated; trigger_item->dispid = dispid; // update dispatch ID } } // end of option "script" // set the option now iResult = SetBaseAlphaOptionItem (iItem, TriggerAlphaOptionsTable, NUMITEMS (TriggerAlphaOptionsTable), (char *) trigger_item, strValue, bChanged); if (bChanged) { if (!m_CurrentPlugin) // plugin mods don't really count SetModifiedFlag (TRUE); // document has changed trigger_item->nUpdateNumber = App.GetUniqueNumber (); // for concurrency checks } return iResult; } // end of found alpha option } // end of not numeric option return eUnknownOption; } // end of SetTriggerOption
// general MXP error message routine - appends a newline, and also writes to debug void CMUSHclientDoc::MXP_error (const int iLevel, const long iMessageNumber, CString strMessage) { char * sLevel [] = { " ", "E", // error "W", // warning "I", // info "A", // all }; char * p = "?"; // turn error level into a character if (iLevel >= 0 && iLevel < NUMITEMS (sLevel)) p = sLevel [iLevel]; if (iLevel == DBG_ERROR) { m_iMXPerrors++; MXP_Restore_Mode (); // an error cancels secure-once mode } // end of error // call script if required if (m_dispidOnMXP_Error != DISPID_UNKNOWN) { long nInvocationCount = 0; CString strType = "MXP Error"; CString strReason = "processing MXP error"; if (GetScriptEngine () && GetScriptEngine ()->IsLua ()) { list<double> nparams; list<string> sparams; nparams.push_back (iMessageNumber); // error number nparams.push_back (m_LineList.GetCount ()); // line sparams.push_back (p); // level (a character) sparams.push_back ((LPCTSTR) strMessage); // message bool result; GetScriptEngine ()->ExecuteLua (m_dispidOnMXP_Error, m_strOnMXP_Error, eWorldAction, strType, strReason, nparams, sparams, nInvocationCount, NULL, NULL, NULL, &result); if (result) return; } // end of Lua else { // WARNING - arguments should appear in REVERSE order to what the sub expects them! enum { eErrorMessage, eLineNumber, eMessageNumber, eErrorLevel, eArgCount, // this MUST be last }; COleVariant args [eArgCount]; DISPPARAMS params = { args, NULL, eArgCount, 0 }; args [eErrorLevel] = p; args [eMessageNumber] = iMessageNumber; args [eLineNumber] = (long) m_LineList.GetCount (); args [eErrorMessage] = strMessage; COleVariant result; ExecuteScript (m_dispidOnMXP_Error, m_strOnMXP_Error, eWorldAction, strType, strReason, params, nInvocationCount, &result); // if the function returns a non-zero result, don't display the message if (result.vt != VT_EMPTY) { result.ChangeType (VT_I4); // make a long if (result.vt == VT_I4) // conversion successful if (result.lVal) // return if non-zero return; } } // not Lua } // end of script callback wanted // tell each plugin about the error tag if (m_bPluginProcessesError) SendToAllPluginCallbacks (ON_PLUGIN_MXP_ERROR, CFormat ("%s,%ld,%ld,%s", (LPCTSTR) p, iMessageNumber, (long) m_LineList.GetCount (), (LPCTSTR) strMessage)); CString strTitle = MXP_ERROR_WINDOW; strTitle += " - "; strTitle += m_mush_name; if (iLevel > m_iMXPdebugLevel) // only show required level return; CString str = CFormat ("%s %5i: (%5i) %s%s", p, // error level iMessageNumber, // actual error number m_LineList.GetCount (), // which line (LPCTSTR) strMessage, // what message ENDLINE); AppendToTheNotepad (strTitle, str, // start new line false, // append eNotepadMXPdebug); }
bool CMUSHclientDoc::MXP_StartTagScript (const CString & strName, const CString & strArguments, CArgumentList & ArgumentList) { // don't make it too easy to dummy up AFK replies if (strName == "afk") return false; if (!SendToAllPluginCallbacks (ON_PLUGIN_MXP_OPENTAG, CFormat ("%s,%s", (LPCTSTR) strName, (LPCTSTR) strArguments) ), true) return true; // see if main script wants to do anything if (m_dispidOnMXP_OpenTag == DISPID_UNKNOWN) return false; long nInvocationCount = 0; long iCount = ArgumentList.GetCount (); CString strType = "MXP open tag"; CString strReason = TFormat ("opening MXP tag %s", (LPCTSTR) strName); if (GetScriptEngine () && GetScriptEngine ()->IsLua ()) { list<double> nparams; list<string> sparams; sparams.push_back ((LPCTSTR) strName); // name of tag sparams.push_back ((LPCTSTR) strArguments); // all arguments map <string, string> table; CArgument * pArgument; POSITION pos; // put the arguments into the table for (iCount = 0, pos = ArgumentList.GetHeadPosition (); pos; iCount++) { pArgument = ArgumentList.GetNext (pos); CString strName = pArgument->strName; // empty ones we will put there by position if (strName.IsEmpty ()) strName = CFormat ("%i", pArgument->iPosition); table [(LPCTSTR) strName] = pArgument->strValue; } // end of looping through each argument bool result; GetScriptEngine ()->ExecuteLua (m_dispidOnMXP_OpenTag, m_strOnMXP_OpenTag, eWorldAction, strType, strReason, nparams, sparams, nInvocationCount, NULL, &table, NULL, &result); return result; } // end of Lua COleSafeArray sa; // for wildcard list if (iCount) // cannot create empty array dimension { sa.CreateOneDim (VT_VARIANT, iCount); CArgument * pArgument; POSITION pos; // put the arguments into the array for (iCount = 0, pos = ArgumentList.GetHeadPosition (); pos; iCount++) { pArgument = ArgumentList.GetNext (pos); // the array must be a bloody array of variants, or VBscript kicks up COleVariant v; // empty ones we will put there by position if (pArgument->strName.IsEmpty ()) v = CFormat ("%i=%s", pArgument->iPosition, (LPCTSTR) pArgument->strValue); else v = CFormat ("%s=%s", (LPCTSTR) pArgument->strName, (LPCTSTR) pArgument->strValue); sa.PutElement (&iCount, &v); } // end of looping through each argument } // end of having at least one // WARNING - arguments should appear in REVERSE order to what the sub expects them! enum { eArgumentArray, eArguments, eTagName, eArgCount, // this MUST be last }; COleVariant args [eArgCount]; DISPPARAMS params = { args, NULL, eArgCount, 0 }; args [eTagName] = strName; args [eArguments] = strArguments; args [eArgumentArray] = sa; COleVariant result; ExecuteScript (m_dispidOnMXP_OpenTag, m_strOnMXP_OpenTag, eWorldAction, strType, strReason, params, nInvocationCount, &result); // if the function returns a non-zero result, don't go ahead if (result.vt != VT_EMPTY) { result.ChangeType (VT_I4); // make a long if (result.vt == VT_I4) // conversion successful if (result.lVal) // return if non-zero return true; } return false; } // end of CMUSHclientDoc::MXP_StartTagScript
long CMUSHclientDoc::AddTriggerEx(LPCTSTR TriggerName, LPCTSTR MatchText, LPCTSTR ResponseText, long Flags, short Colour, short Wildcard, LPCTSTR SoundFileName, LPCTSTR ScriptName, short SendTo, short Sequence) { CString strTriggerName = TriggerName; CTrigger * trigger_item; DISPID dispid = DISPID_UNKNOWN; long nStatus; bool bReplace = false; // allow blank names, assign one :) if (strTriggerName.IsEmpty ()) strTriggerName.Format ("*trigger%s", (LPCTSTR) App.GetUniqueString ()); else // return if bad name if (nStatus = CheckObjectName (strTriggerName)) return nStatus; // if it already exists, error if (GetTriggerMap ().Lookup (strTriggerName, trigger_item)) if (Flags & eReplace) bReplace = true; else return eTriggerAlreadyExists; // cannot have null match text if (strlen (MatchText) == 0) return eTriggerCannotBeEmpty; // check sequence if (Sequence < 0 || Sequence > 10000) return eTriggerSequenceOutOfRange; // check send to if (SendTo < 0 || SendTo >= eSendToLast) return eTriggerSendToInvalid; // must have a label for 'send to label' if (SendTo == eSendToVariable) if (CheckObjectName (strTriggerName)) return eTriggerLabelNotSpecified; // get trigger dispatch ID if (GetScriptEngine () && strlen (ScriptName) != 0) { CString strMessage; dispid = GetProcedureDispid (ScriptName, "trigger", TriggerName, strMessage); if (dispid == DISPID_UNKNOWN) return eScriptNameNotLocated; } t_regexp * regexp = NULL; CString strRegexp; if (Flags & eTriggerRegularExpression) strRegexp = MatchText; else strRegexp = ConvertToRegularExpression (MatchText); // compile regular expression try { regexp = regcomp (strRegexp, (Flags & eIgnoreCase ? PCRE_CASELESS : 0) | (m_bUTF_8 ? PCRE_UTF8 : 0)); } // end of try catch(CException* e) { e->Delete (); return eBadRegularExpression; } // end of catch // trigger replacement wanted if (bReplace) { // the trigger seems to exist - delete its pointer delete trigger_item; // now delete its entry GetTriggerMap ().RemoveKey (strTriggerName); } // create new trigger item and insert in trigger map GetTriggerMap ().SetAt (strTriggerName, trigger_item = new CTrigger); if ((Flags & eTemporary) == 0) if (!m_CurrentPlugin) // plugin mods don't really count SetModifiedFlag (TRUE); trigger_item->nUpdateNumber = App.GetUniqueNumber (); // for concurrency checks trigger_item->strInternalName = strTriggerName; // for deleting one-shot triggers trigger_item->trigger = MatchText; trigger_item->contents = ResponseText; trigger_item->colour = Colour; trigger_item->ignore_case = (Flags & eIgnoreCase) != 0; trigger_item->bOmitFromOutput = (Flags & eOmitFromOutput) != 0; trigger_item->bKeepEvaluating = (Flags & eKeepEvaluating) != 0; trigger_item->omit_from_log = (Flags & eOmitFromLog) != 0; trigger_item->bEnabled = (Flags & eEnabled) != 0; trigger_item->bRegexp = (Flags & eTriggerRegularExpression) != 0; trigger_item->bExpandVariables = (Flags & eExpandVariables) != 0; trigger_item->bTemporary = (Flags & eTemporary) != 0; trigger_item->bLowercaseWildcard = (Flags & eLowercaseWildcard) != 0; trigger_item->bOneShot = (Flags & eTriggerOneShot) != 0; trigger_item->strProcedure = ScriptName; trigger_item->strLabel = TriggerName; trigger_item->iClipboardArg = Wildcard; trigger_item->sound_to_play = SoundFileName; trigger_item->dispid = dispid; trigger_item->regexp = regexp; trigger_item->iSendTo = SendTo; trigger_item->iSequence = Sequence; trigger_item->strVariable = TriggerName; // kludge if (Colour < 0 || Colour >= MAX_CUSTOM) trigger_item->colour = SAMECOLOUR; if (Wildcard < 0 || Wildcard > 10) trigger_item->iClipboardArg = 0; SortTriggers (); return eOK; } // end of CMUSHclientDoc::AddTriggerEx
void CMUSHclientDoc::CheckTimerList (CTimerMap & TimerMap) { CTimer * timer_item; CString strTimerName; CmcDateTime tNow = CmcDateTime::GetTimeNow(); CmcDateTimeSpan tsOneDay (1, 0, 0, 0); // check for deleted chat sessions for (POSITION chatpos = m_ChatList.GetHeadPosition (); chatpos; ) { POSITION oldpos = chatpos; CChatSocket * pSocket = m_ChatList.GetNext (chatpos); if (pSocket->m_bDeleteMe) { m_ChatList.RemoveAt (oldpos); delete pSocket; break; // list is no longer valid } } set <string> firedTimersList; POSITION pos; // iterate through all timers for this document - first build list of them for (pos = TimerMap.GetStartPosition(); pos; ) { TimerMap.GetNextAssoc (pos, strTimerName, timer_item); if (!timer_item->bEnabled) // ignore un-enabled timers continue; // no timer activity whilst closed or in the middle of connecting, or if not enabled if (!timer_item->bActiveWhenClosed) if (m_iConnectPhase != eConnectConnectedToMud) continue; // if not ready to fire yet, ignore it if (timer_item->tFireTime > tNow) continue; firedTimersList.insert ((LPCTSTR) strTimerName); // add to list of fired timers } // now process list, checking timer still exists in case a script deleted one // see: http://www.gammon.com.au/forum/?id=10358 for (set <string>::iterator it = firedTimersList.begin (); it != firedTimersList.end (); it++) { // get next fired timer from list strTimerName = it->c_str (); // check still exists, get pointer if so if (!TimerMap.Lookup (strTimerName, timer_item)) continue; timer_item->nMatched++; // count timer matches timer_item->tWhenFired = tNow; // when it fired m_iTimersFiredCount++; m_iTimersFiredThisSessionCount++; // TRACE1 ("Fired at = %10.8f\n", timer_item->tWhenFired.m_dt); if (timer_item->strLabel.IsEmpty ()) Trace ("Fired unlabelled timer "); else Trace ("Fired timer %s", (LPCTSTR) timer_item->strLabel); // TRACE1 ("Fire time = %10.8f\n", timer_item->tFireTime.m_dt); // update fire time - before calling the script, in case it takes a long time if (timer_item->iType == CTimer::eAtTime) timer_item->tFireTime += tsOneDay; else timer_item->tFireTime += CmcDateTimeSpan (0, // add the interval timer_item->iEveryHour, timer_item->iEveryMinute, timer_item->fEverySecond); // in case clock changes or some such thing, make sure timer will be due to // fire in the future, not the past, or it might go mad and keep firing if (timer_item->tFireTime <= tNow) ResetOneTimer (timer_item); // if one-shot, disable it, so if the timer routine finds it again while // it is still executing (eg. due to a syntax error dialog box) then // it won't fire again. if (timer_item->bOneShot) timer_item->bEnabled = false; // send timer message, if this timer list is "active" CString strExtraOutput; timer_item->bExecutingScript = true; // cannot be deleted now m_iCurrentActionSource = eTimerFired; SendTo (timer_item->iSendTo, timer_item->strContents, timer_item->bOmitFromOutput, // omit from output timer_item->bOmitFromLog, // omit from log TFormat ("Timer: %s", (LPCTSTR) timer_item->strLabel), timer_item->strVariable, strExtraOutput ); m_iCurrentActionSource = eUnknownActionSource; timer_item->bExecutingScript = false; // can be deleted now // display any stuff sent to output window if (!strExtraOutput.IsEmpty ()) DisplayMsg (strExtraOutput, strExtraOutput.GetLength (), COMMENT); // invoke script subroutine, if any if (!timer_item->strProcedure.IsEmpty ()) if (CheckScriptingAvailable ("Timer", timer_item->dispid, timer_item->strProcedure)) continue; if (timer_item->dispid != DISPID_UNKNOWN) // if we have a dispatch id { CString strType = "timer"; CString strReason = TFormat ("processing timer \"%s\"", (LPCTSTR) timer_item->strLabel); // get unlabelled timer's internal name const char * pLabel = timer_item->strLabel; if (pLabel [0] == 0) pLabel = GetTimerRevMap () [timer_item].c_str (); if (GetScriptEngine () && GetScriptEngine ()->IsLua ()) { list<double> nparams; list<string> sparams; sparams.push_back (pLabel); timer_item->bExecutingScript = true; // cannot be deleted now GetScriptEngine ()->ExecuteLua (timer_item->dispid, timer_item->strProcedure, eTimerFired, strType, strReason, nparams, sparams, timer_item->nInvocationCount); timer_item->bExecutingScript = false; // can be deleted now } // end of Lua else { // prepare for the arguments (so far, 1 which is the timer name) // WARNING - arguments should appear in REVERSE order to what the sub expects them! enum { eTimerName, eArgCount, // this MUST be last }; COleVariant args [eArgCount]; DISPPARAMS params = { args, NULL, eArgCount, 0 }; // args [eTimerName] = strTimerName; args [eTimerName] = pLabel; timer_item->bExecutingScript = true; // cannot be deleted now ExecuteScript (timer_item->dispid, timer_item->strProcedure, eTimerFired, strType, strReason, params, timer_item->nInvocationCount); timer_item->bExecutingScript = false; // can be deleted now } // not Lua } // end of having a dispatch ID // If they passed the wrong arguments to the timer routine, the dialog box // might appear, and the timer be deleted, before we get a chance to // do this code, in which case the timer has gone. // Just get it again to be sure ... [#430] if (!TimerMap.Lookup (strTimerName, timer_item)) return; // if one-shot timer, delete from list if (timer_item->bOneShot) { TimerMap.RemoveKey (strTimerName); delete timer_item; SortTimers (); } } // end of processing each timer } // end of CMUSHclientDoc::CheckTimerMap
bool CMUSHclientDoc::ExecuteAliasScript (CAlias * alias_item, const CString strCurrentLine) { if (CheckScriptingAvailable ("Alias", alias_item->dispid, alias_item->strProcedure)) return false; if (alias_item->dispid != DISPID_UNKNOWN) // if we have a dispatch id { CString strType = "alias"; CString strReason = TFormat ("processing alias \"%s\"", (LPCTSTR) alias_item->strLabel); // get unlabelled alias's internal name const char * pLabel = alias_item->strLabel; if (pLabel [0] == 0) pLabel = GetAliasRevMap () [alias_item].c_str (); if (GetScriptEngine () && GetScriptEngine ()->IsLua ()) { list<double> nparams; list<string> sparams; sparams.push_back (pLabel); sparams.push_back ((LPCTSTR) strCurrentLine); alias_item->bExecutingScript = true; // cannot be deleted now GetScriptEngine ()->ExecuteLua (alias_item->dispid, alias_item->strProcedure, eDontChangeAction, strType, strReason, nparams, sparams, alias_item->nInvocationCount, alias_item->regexp); alias_item->bExecutingScript = false; // can be deleted now return true; } // end of Lua // prepare for the arguments, so far, 3 which are: // 1. alias name, // 2. expanded line // 3. replacement string // WARNING - arguments should appear in REVERSE order to what the sub expects them! enum { eWildcards, eInputLine, eAliasName, eArgCount, // this MUST be last }; COleSafeArray sa; // for wildcard list COleVariant args [eArgCount]; DISPPARAMS params = { args, NULL, eArgCount, 0 }; args [eAliasName] = pLabel; args [eInputLine] = strCurrentLine; // --------------- set up wildcards array --------------------------- sa.Clear (); // nb - to be consistent with %1, %2 etc. we will make array 1-relative sa.CreateOneDim (VT_VARIANT, MAX_WILDCARDS, NULL, 1); long i; for (i = 1; i < MAX_WILDCARDS; i++) { COleVariant v (alias_item->wildcards [i].c_str ()); sa.PutElement (&i, &v); } // i should be MAX_WILDCARDS (10) now ;) COleVariant v (alias_item->wildcards [0].c_str ()); // the whole matching line sa.PutElement (&i, &v); args [eWildcards] = sa; alias_item->bExecutingScript = true; // cannot be deleted now ExecuteScript (alias_item->dispid, alias_item->strProcedure, eDontChangeAction, // don't change current action strType, strReason, params, alias_item->nInvocationCount); alias_item->bExecutingScript = false; // can be deleted now return true; } // end of having a dispatch ID return false; } // end of CMUSHclientDoc::ExecuteAliasScript
void CMUSHclientDoc::Help(LPCTSTR Name) { map<string, string> lua_specials; // special Lua help lua_specials ["lua"] = "lua"; lua_specials ["lua b"] = "lua_base"; lua_specials ["lua c"] = "lua_coroutines"; lua_specials ["lua d"] = "lua_debug"; lua_specials ["lua i"] = "lua_io"; lua_specials ["lua m"] = "lua_math"; lua_specials ["lua o"] = "lua_os"; lua_specials ["lua p"] = "lua_package"; lua_specials ["lua r"] = "lua_rex"; lua_specials ["lua s"] = "lua_string"; lua_specials ["lua t"] = "lua_tables"; lua_specials ["lua u"] = "lua_utils"; CString m_strFilter = Name; m_strFilter.MakeLower (); m_strFilter.TrimLeft (); m_strFilter.TrimRight (); // a special case - b is used twice if (m_strFilter == "lua bc") { ShowHelp ("DOC_", "lua_bc"); return; } CString strFunction; string sFirst5 = m_strFilter.Left (5); map<string, string>::const_iterator it = lua_specials.find (sFirst5); if (it != lua_specials.end ()) { ShowHelp ("DOC_", it->second.c_str ()); return; } else if (!m_strFilter.IsEmpty ()) { // first find direct match on a Lua function if (LuaFunctionsSet.find ((LPCTSTR) m_strFilter) != LuaFunctionsSet.end ()) { ShowHelp ("LUA_", m_strFilter); return; } // then try a world function for (int i = 0; InternalFunctionsTable [i].sFunction [0]; i++) { strFunction = InternalFunctionsTable [i].sFunction; strFunction.MakeLower (); if (strFunction == m_strFilter) { ShowHelp ("FNC_", InternalFunctionsTable [i].sFunction); // back to proper capitalization return; } } } // end of non-empty name bool bLua = false; if (GetScriptEngine () && GetScriptEngine ()->L) bLua = true; // not exact match, show list matching filter ShowFunctionslist (m_strFilter, bLua); } // end of CMUSHclientDoc::Help
long CMUSHclientDoc::SetTimerOption(LPCTSTR TimerName, LPCTSTR OptionName, LPCTSTR Value) { CString strTimerName = TimerName; CString strValue = Value; CTimer * Timer_item; // trim spaces from name, make lower-case CheckObjectName (strTimerName, false); if (!GetTimerMap ().Lookup (strTimerName, Timer_item)) return eTimerNotFound; CString strOptionName = OptionName; strOptionName.MakeLower(); strOptionName.TrimLeft (); strOptionName.TrimRight (); int iItem; int iResult = FindBaseOption (strOptionName, TimerOptionsTable, iItem); bool bChanged; if (iResult == eOK) { // this is a numeric option // for boolean options, accept "y" or "n" if (TimerOptionsTable [iItem].iMinimum == 0 && TimerOptionsTable [iItem].iMaximum == 0) { if (strValue == "Y" || strValue == "y") Value = "1"; else if (strValue == "N" || strValue == "n") Value = "0"; } long iValue = 0; double fValue = 0; if (strOptionName == "second") fValue = atof (Value); else { if (!IsNumber (Value, true)) return eOptionOutOfRange; iValue = atol (Value); } if (m_CurrentPlugin && (TimerOptionsTable [iItem].iFlags & OPT_PLUGIN_CANNOT_WRITE)) return ePluginCannotSetOption; // not available to plugin if (TimerOptionsTable [iItem].iFlags & OPT_CANNOT_WRITE) return ePluginCannotSetOption; // not available for writing at all iResult = SetBaseOptionItem (iItem, TimerOptionsTable, NUMITEMS (TimerOptionsTable), (char *) Timer_item, iValue, bChanged); if (bChanged) { if (!m_CurrentPlugin) // plugin mods don't really count SetModifiedFlag (TRUE); // document has changed Timer_item->nUpdateNumber = App.GetUniqueNumber (); // for concurrency checks } if (iResult == eOK && Timer_item->iType == CTimer::eInterval) { // need to set "every" time, not "at" time if (strOptionName == "hour") { Timer_item->iEveryHour = iValue; ResetOneTimer (Timer_item); } // end of option "hour" else if (strOptionName == "minute") { Timer_item->iEveryMinute = iValue; ResetOneTimer (Timer_item); } // end of option "minute" else if (strOptionName == "second") { Timer_item->fEverySecond = fValue; ResetOneTimer (Timer_item); } // end of option "second" } // end of need to fiddle with hour/minute/second // need to reset if we are changing this if (strOptionName == "at_time" && bChanged) { // copy from at to every or vice-versa if (Timer_item->iType == CTimer::eInterval) { Timer_item->iEveryHour = Timer_item->iAtHour; Timer_item->iEveryMinute = Timer_item->iAtHour; Timer_item->fEverySecond = Timer_item->fAtSecond; } else { Timer_item->iAtHour = Timer_item->iEveryHour; Timer_item->iAtMinute = Timer_item->iEveryHour; Timer_item->fAtSecond = Timer_item->fEverySecond; } ResetOneTimer (Timer_item); } return iResult; } // end of found else { // not numeric option, try alpha int iResult = FindBaseAlphaOption (strOptionName, TimerAlphaOptionsTable, iItem); if (iResult == eOK) { // alpha option if (m_CurrentPlugin && (TimerAlphaOptionsTable [iItem].iFlags & OPT_PLUGIN_CANNOT_WRITE)) return ePluginCannotSetOption; // not available to plugin if (TimerAlphaOptionsTable [iItem].iFlags & OPT_CANNOT_WRITE) return ePluginCannotSetOption; // not available for writing at all // ------ preliminary validation before setting the option if (strOptionName == "script") { // get Timer dispatch ID if (GetScriptEngine () && !strValue.IsEmpty ()) { DISPID dispid = DISPID_UNKNOWN; CString strMessage; dispid = GetProcedureDispid (strValue, "Timer", TimerName, strMessage); if (dispid == DISPID_UNKNOWN) return eScriptNameNotLocated; Timer_item->dispid = dispid; // update dispatch ID } } // end of option "script" // set the option now iResult = SetBaseAlphaOptionItem (iItem, TimerAlphaOptionsTable, NUMITEMS (TimerAlphaOptionsTable), (char *) Timer_item, strValue, bChanged); if (bChanged) { if (!m_CurrentPlugin) // plugin mods don't really count SetModifiedFlag (TRUE); // document has changed Timer_item->nUpdateNumber = App.GetUniqueNumber (); // for concurrency checks } return iResult; } // end of found alpha option } // end of not numeric option return eUnknownOption; } // end of SetTimerOption
long CMUSHclientDoc::AddTimer(LPCTSTR TimerName, short Hour, short Minute, double Second, LPCTSTR ResponseText, long Flags, LPCTSTR ScriptName) { CString strTimerName = TimerName; CTimer * timer_item; DISPID dispid = DISPID_UNKNOWN; long nStatus; bool bReplace = false; if (strTimerName.IsEmpty ()) strTimerName.Format ("*timer%s", (LPCTSTR) App.GetUniqueString ()); else // return if bad name if (nStatus = CheckObjectName (strTimerName)) return nStatus; // if it already exists, error if (GetTimerMap ().Lookup (strTimerName, timer_item)) if (Flags & eReplace) bReplace = true; else return eTimerAlreadyExists; if (Hour < 0 || Hour > 23) return eTimeInvalid; if (Minute < 0 || Minute > 59) return eTimeInvalid; if (Second < 0.0 || Second > 59.9999) return eTimeInvalid; // can't have a zero time for "every" timers if (((Hour == 0) && (Minute == 0) && (Second == 0.0)) && !(Flags & eAtTime)) return eTimeInvalid; // get timer dispatch ID if (GetScriptEngine () && strlen (ScriptName) != 0) { CString strMessage; dispid = GetProcedureDispid (ScriptName, "timer", TimerName, strMessage); if (dispid == DISPID_UNKNOWN) return eScriptNameNotLocated; } // timer replacement wanted if (bReplace) { // the timer seems to exist - delete its pointer delete timer_item; // now delete its entry GetTimerMap ().RemoveKey (strTimerName); } // create new timer item and insert in timer map GetTimerMap ().SetAt (strTimerName, timer_item = new CTimer); if ((Flags & eTemporary) == 0) if (!m_CurrentPlugin) // plugin mods don't really count SetModifiedFlag (TRUE); timer_item->nUpdateNumber = App.GetUniqueNumber (); // for concurrency checks if (Flags & eAtTime) { timer_item->iAtHour = Hour; timer_item->iAtMinute = Minute; timer_item->fAtSecond = Second; timer_item->iType = CTimer::eAtTime; } else { timer_item->iEveryHour = Hour; timer_item->iEveryMinute = Minute; timer_item->fEverySecond = Second; timer_item->iType = CTimer::eInterval; } timer_item->strContents = ResponseText; timer_item->bEnabled = (Flags & eEnabled) != 0; timer_item->bOneShot = (Flags & eOneShot) != 0; timer_item->bTemporary = (Flags & eTemporary) != 0; timer_item->bActiveWhenClosed = (Flags & eActiveWhenClosed) != 0; timer_item->strProcedure = ScriptName; timer_item->strLabel = TimerName; timer_item->dispid = dispid; if (Flags & eTimerSpeedWalk) timer_item->iSendTo = eSendToSpeedwalk; else if (Flags & eTimerNote) timer_item->iSendTo = eSendToOutput; ResetOneTimer (timer_item); SortTimers (); return eOK; } // end of CMUSHclientDoc::AddTimer