long CMUSHclientDoc::DeleteTimer(LPCTSTR TimerName) { CString strTimerName = TimerName; CTimer * timer_item; // trim spaces from name, make lower-case CheckObjectName (strTimerName, false); if (!GetTimerMap ().Lookup (strTimerName, timer_item)) return eTimerNotFound; // can't if executing a script if (timer_item->bExecutingScript) return eItemInUse; // the timer seems to exist - delete its pointer delete timer_item; // now delete its entry if (!GetTimerMap ().RemoveKey (strTimerName)) return eTimerNotFound; SortTimers (); if (!m_CurrentPlugin) // plugin mods don't really count SetModifiedFlag (TRUE); // document has changed return eOK; } // end of CMUSHclientDoc::DeleteTimer
long CMUSHclientDoc::DeleteTimerGroup(LPCTSTR GroupName) { CString strTimerName; CTimer * timer_item; POSITION pos; // no group name, affect nothing if (strlen (GroupName) == 0) return 0; vector<string> vToDelete; // count timers for (pos = GetTimerMap ().GetStartPosition(); pos; ) { GetTimerMap ().GetNextAssoc (pos, strTimerName, timer_item); if (timer_item->strGroup == GroupName) { // can't if executing a script if (timer_item->bExecutingScript) continue; delete timer_item; // remember to delete from timer map vToDelete.push_back ((LPCTSTR) strTimerName); } } // end of timers // now delete from map, do it this way in case deleting whilst looping throws things out for (vector<string>::const_iterator it = vToDelete.begin (); it != vToDelete.end (); it++) GetTimerMap ().RemoveKey (it->c_str ()); if (!vToDelete.empty ()) { SortTimers (); if (!m_CurrentPlugin) // plugin mods don't really count SetModifiedFlag (TRUE); // document has changed } return vToDelete.size (); } // end of DeleteTimerGroup
long CMUSHclientDoc::DeleteTemporaryTimers() { long iCount = 0; POSITION pos; CString strTimerName; CTimer * timer_item; for (pos = GetTimerMap ().GetStartPosition(); pos; ) { GetTimerMap ().GetNextAssoc (pos, strTimerName, timer_item); if (timer_item->bTemporary && !timer_item->bExecutingScript) { delete timer_item; GetTimerMap ().RemoveKey (strTimerName); iCount++; } } // end of deleting timers if (iCount) SortTimers (); return iCount; } // end of CMUSHclientDoc::DeleteTemporaryTimers
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
long CMUSHclientDoc::DoAfterSpecial(double Seconds, LPCTSTR SendText, short SendTo) { int iHours, iMinutes; // sanity check if (Seconds < 0.1) return eTimeInvalid; // fiddle seconds into hours/mins/seconds iHours = Seconds / 3600; Seconds = Seconds - (iHours * 3600); iMinutes = Seconds / 60; Seconds = Seconds - (iMinutes * 60); // a really big number would make hours > 23 if (iHours > 23) return eTimeInvalid; // check they are sending to somewhere valid if (SendTo < 0 || SendTo >= eSendToLast) return eOptionOutOfRange; CString strTimerName; CTimer * timer_item; // this is a temporary unlabelled timer, make up a name strTimerName.Format ("*timer%s", (LPCTSTR) App.GetUniqueString ()); if (iHours < 0 || iHours > 23) return eTimeInvalid; if (iMinutes < 0 || iMinutes > 59) return eTimeInvalid; if (Seconds < 0 || Seconds > 59.9999) return eTimeInvalid; // create new timer item and insert in timer map GetTimerMap ().SetAt (strTimerName, timer_item = new CTimer); timer_item->nUpdateNumber = App.GetUniqueNumber (); // for concurrency checks timer_item->iEveryHour = iHours; timer_item->iEveryMinute = iMinutes; timer_item->fEverySecond = Seconds; timer_item->iType = CTimer::eInterval; timer_item->strContents = SendText; timer_item->bEnabled = true; timer_item->bOneShot = true; timer_item->bTemporary = true; timer_item->bActiveWhenClosed = true; timer_item->iSendTo = SendTo; ResetOneTimer (timer_item); SortTimers (); return eOK; } // end of CMUSHclientDoc::DoAfterSpecial
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