Index: trunk/FACT++/src/InterpreterV8.cc
===================================================================
--- trunk/FACT++/src/InterpreterV8.cc	(revision 15428)
+++ trunk/FACT++/src/InterpreterV8.cc	(revision 15430)
@@ -1474,5 +1474,4 @@
 }
 
-
 void InterpreterV8::JsHandleState(const std::string &server, const State &state)
 {
@@ -1524,4 +1523,74 @@
     if (!HandleException(exception, "dim.onchange"))
         V8::TerminateExecution(fThreadId);
+}
+
+Handle<Value> InterpreterV8::FuncSetInterrupt(const Arguments &args)
+{
+    if (args.Length()!=1)
+        return ThrowException(String::New("Number of arguments must be 1."));
+
+    if (!args[0]->IsNull() && !args[0]->IsUndefined() && !args[0]->IsFunction())
+        return ThrowException(String::New("Argument not a function, null or undefined."));
+
+    if (args[0]->IsNull() || args[0]->IsUndefined())
+    {
+        fInterruptCallback.Dispose();
+        return Undefined();
+    }
+
+    // Returns the value if the setter intercepts the request. Otherwise, returns an empty handle.
+    fInterruptCallback = Persistent<Object>::New(args[0]->ToObject());
+    return Undefined();
+}
+
+int InterpreterV8::JsHandleInterrupt(const EventImp &evt)
+{
+    const Locker locker;
+
+    if (fThreadId<0)
+        return -42;
+
+    if (fInterruptCallback.IsEmpty())
+        return -42;
+
+    const HandleScope handle_scope;
+
+    fInterruptCallback->CreationContext()->Enter();
+
+    // -------------------------------------------------------------------
+
+    TryCatch exception;
+
+    const string str = evt.GetString();
+
+    const size_t p = str.find_last_of('\n');
+
+    const string irq = p==string::npos?str:str.substr(0, p);
+    const string usr = p==string::npos?"nobody":str.substr(p+1);
+
+    Local<Value> irq_str = String::New(irq.c_str());
+    Local<Value> usr_str = String::New(usr.c_str());
+    Local<Value> date = Date::New(evt.GetJavaDate());
+
+    int32_t rc = -42;
+    if (!date.IsEmpty())
+    {
+        const int id = V8::GetCurrentThreadId();
+        fThreadIds.insert(id);
+
+        Handle<Value> args[] = { irq_str, date, usr_str };
+        Handle<Function> fun = Handle<Function>(Function::Cast(*fInterruptCallback));
+
+        const Handle<Value> val = fun->Call(fun, 3, args);
+
+        rc = !val.IsEmpty() && val->IsInt32() ? val->Int32Value() : 0;
+
+        fThreadIds.erase(id);
+    }
+
+    if (!HandleException(exception, "interrupt"))
+        V8::TerminateExecution(fThreadId);
+
+    return rc<10 || rc>255 ? -42 : rc;
 }
 
@@ -2342,4 +2411,5 @@
     dimctrl->Set(String::New("setState"),    FunctionTemplate::New(WrapSetState),  ReadOnly);
     dimctrl->Set(String::New("getState"),    FunctionTemplate::New(WrapGetState),  ReadOnly);
+    dimctrl->Set(String::New("setInterruptHandler"), FunctionTemplate::New(WrapSetInterrupt), ReadOnly);
 
     Handle<ObjectTemplate> v8 = ObjectTemplate::New();
@@ -2522,4 +2592,7 @@
     fStateCallbacks.clear();
 
+    // Now we can dispose the persistent interrupt handler
+    fInterruptCallback.Dispose();
+
     // Now we can dispose all persistent handles from reverse maps
     for (auto it=fReverseMap.begin(); it!=fReverseMap.end(); it++)
Index: trunk/FACT++/src/InterpreterV8.h
===================================================================
--- trunk/FACT++/src/InterpreterV8.h	(revision 15428)
+++ trunk/FACT++/src/InterpreterV8.h	(revision 15430)
@@ -46,4 +46,7 @@
     // List of all states already set
     std::vector<std::pair<int, std::string>> fStates;
+
+    // Interrupt handler
+    v8::Persistent<v8::Object> fInterruptCallback;
 
     static v8::Handle<v8::FunctionTemplate> fTemplateLocal;
@@ -86,4 +89,5 @@
     v8::Handle<v8::Value> FuncGetServices(const v8::Arguments& args);
     v8::Handle<v8::Value> FuncNewState(const v8::Arguments& args);
+    v8::Handle<v8::Value> FuncSetInterrupt(const v8::Arguments& args);
     //v8::Handle<v8::Value> FuncOpen(const v8::Arguments& args);
     v8::Handle<v8::Value> FuncSubscription(const v8::Arguments& args);
@@ -142,4 +146,5 @@
     static v8::Handle<v8::Value> WrapGetDescription(const v8::Arguments &args){ if (This) return This->FuncGetDescription(args);else return v8::Undefined(); }
     static v8::Handle<v8::Value> WrapGetServices(const v8::Arguments &args){ if (This) return This->FuncGetServices(args);else return v8::Undefined(); }
+    static v8::Handle<v8::Value> WrapSetInterrupt(const v8::Arguments &args){ if (This) return This->FuncSetInterrupt(args);else return v8::Undefined(); }
     //static v8::Handle<v8::Value> WrapOpen(const v8::Arguments &args)     { if (This) return This->FuncOpen(args);     else return v8::Undefined(); }
     static v8::Handle<v8::Value> WrapSubscription(const v8::Arguments &args){ if (This) return This->FuncSubscription(args);else return v8::Undefined(); }
@@ -204,4 +209,5 @@
     virtual std::pair<uint64_t, EventImp *> JsGetEvent(const std::string &) { return std::make_pair(0, (EventImp*)0); };
 
+    int JsHandleInterrupt(const EventImp &);
     void JsHandleEvent(const EventImp &, uint64_t, const std::string &);
     void JsHandleState(const std::string &, const State &);
Index: trunk/FACT++/src/RemoteControl.h
===================================================================
--- trunk/FACT++/src/RemoteControl.h	(revision 15428)
+++ trunk/FACT++/src/RemoteControl.h	(revision 15430)
@@ -523,4 +523,5 @@
         fImp = &imp;
         fImp->SetStateCallback(bind(&InterpreterV8::JsHandleState, this, placeholders::_1, placeholders::_2));
+        fImp->SetInterruptHandler(bind(&InterpreterV8::JsHandleInterrupt, this, placeholders::_1));
     }
 };
Index: trunk/FACT++/src/StateMachineDimControl.cc
===================================================================
--- trunk/FACT++/src/StateMachineDimControl.cc	(revision 15428)
+++ trunk/FACT++/src/StateMachineDimControl.cc	(revision 15430)
@@ -130,4 +130,19 @@
     InterpreterV8::JsStop();
     return GetCurrentState();
+}
+
+int StateMachineDimControl::InterruptScript(const EventImp &evt)
+{
+    if (!fInterruptHandler)
+        return GetCurrentState();
+
+    string str = evt.GetString();
+
+    const size_t p = str.find_last_of('\n');
+    if (p!=string::npos)
+        str[p] = ':';
+
+    Info("Interrupt request received ["+str+"]");
+    return fInterruptHandler(evt);
 }
 
@@ -510,4 +525,8 @@
         (bind(&StateMachineDimControl::StopScript, this))
         ("Stop a runnning batch script or JavaScript");
+
+    AddEvent("INTERRUPT", "C")
+        (bind(&StateMachineDimControl::InterruptScript, this, placeholders::_1))
+        ("Send an interrupt request (IRQ) to a running JavaScript");
 }
 
@@ -565,4 +584,7 @@
         return !Dim::SendCommand("DIM_CONTROL/STOP", fUser);
 
+    if (conf.Has("interrupt"))
+        return !Dim::SendCommand("DIM_CONTROL/INTERRUPT", conf.Get<string>("interrupt")+"\n"+fUser);
+
     if (conf.Has("start"))
         return !Dim::SendCommand("DIM_CONTROL/START", conf.Get<string>("start")+" user='"+fUser+"'"+fArgumentsJS);
Index: trunk/FACT++/src/StateMachineDimControl.h
===================================================================
--- trunk/FACT++/src/StateMachineDimControl.h	(revision 15428)
+++ trunk/FACT++/src/StateMachineDimControl.h	(revision 15430)
@@ -36,4 +36,6 @@
     std::string fArgumentsJS;
 
+    std::function<int(const EventImp &)> fInterruptHandler;
+
     std::string Line(const std::string &txt, char fill);
 
@@ -46,4 +48,5 @@
     int StartScript(const EventImp &imp, const std::string &cmd);
     int StopScript();
+    int InterruptScript(const EventImp &imp);
 
     int HandleStateChange(const std::string &server, DimDescriptions *state);
@@ -72,4 +75,6 @@
     void SetStateCallback(const std::function<void(const std::string &, const State &)> &func) { fStateCallback = func; }
 
+    void SetInterruptHandler(const std::function<int(const EventImp &)> &func=std::function<int(const EventImp &)>()) { fInterruptHandler = func; }
+
 public:
     StateMachineDimControl(std::ostream &out=std::cout);
Index: trunk/FACT++/src/dimctrl.cc
===================================================================
--- trunk/FACT++/src/dimctrl.cc	(revision 15428)
+++ trunk/FACT++/src/dimctrl.cc	(revision 15430)
@@ -1,3 +1,5 @@
 #include "StateMachineDimControl.h"
+
+//#include <sys/stat.h>
 
 #include "RemoteControl.h"
@@ -43,7 +45,8 @@
     {
         control.add_options()
+            ("batch",   var<string>(), "Start a batch script with the given name at the given label (script.dim[:N]) on the dimctrl-server")
             ("start",   var<string>(), "Start a java script with the given name on the dimctrl-server")
-            ("batch",   var<string>(), "Start a batch script with the given name at the given label (script.dim[:N]) on the dimctrl-server")
             ("stop",    po_switch(),   "Stop a currently running script on the dimctrl-server")
+            ("interrupt", var<string>()->implicit_value(""), "Send an interrupt request (IRQ) to a running JavaScript.")
             ("restart", var<string>(), "Send 'EXIT 126' to the given server")
             ("msg",     var<string>(), "Send a message to the chat server.")
@@ -106,4 +109,6 @@
 int main(int argc, const char* argv[])
 {
+    //chmod(argv[0], 04775);
+
     Configuration conf(argv[0]);
     conf.SetPrintUsage(PrintUsage);
