Index: trunk/FACT++/src/InterpreterV8.cc
===================================================================
--- trunk/FACT++/src/InterpreterV8.cc	(revision 15153)
+++ trunk/FACT++/src/InterpreterV8.cc	(revision 15156)
@@ -146,6 +146,4 @@
     HandleScope handle_scope;
 
-    TryCatch exception;
-
     Handle<Function> func = Handle<Function>::Cast(args[1]);
 
@@ -155,8 +153,11 @@
 
     Time t;
-    while (!exception.HasCaught())
+    while (1)
     {
         const Handle<Value> rc = func->Call(func, args.Length()-2, argv);
-        if (!rc.IsEmpty() && !rc->IsUndefined())
+        if (rc.IsEmpty())
+            return Undefined();
+
+        if (!rc->IsUndefined())
             return handle_scope.Close(rc);
 
@@ -170,7 +171,4 @@
         usleep(1000);
     }
-
-    if (exception.HasCaught())
-        return exception.ReThrow();
 
     if (timeout<0)
@@ -331,5 +329,5 @@
 
     if (args.Length()==3 && !args[2]->IsInt32() && !args[2]->IsUndefined())
-        return ThrowException(String::New("Argument 3 not an int32 and not null."));
+        return ThrowException(String::New("Argument 3 not an int32 and not undefined."));
 
     // Using a Javascript function has the advantage that it is fully
@@ -692,27 +690,25 @@
         const String::AsciiValue file(args[i]);
         if (*file == NULL)
-            return ThrowException(String::New("File name missing"));
-
-        TryCatch exception;
-        const bool rc = ExecuteFile(*file);
-        if (exception.HasCaught())
-        {
-            // If this is called from the main thread, re-throw
-            if (fThreadId==V8::GetCurrentThreadId())
-                return exception.ReThrow();
-
-            // Otherwise, handle the exception...
-            HandleException(exception, "include");
-        }
-        if (!rc)
-        {
-            // ...and stop the thread immediately (if this is not done,
-            // the other threads might still proceed);
-            V8::TerminateExecution(fThreadId);
-            return ThrowException(Null());
-        }
-    }
-
-    return Undefined();//Boolean::New(true);
+            return ThrowException(String::New("File name missing."));
+
+        if (strlen(*file)==0)
+            return ThrowException(String::New("File name empty."));
+
+        ifstream fin(*file); // izstream does not work: WHY?
+        if (!fin)
+            return ThrowException(String::New(errno!=0?strerror(errno):"Insufficient memory for decompression"));
+
+        string buffer;
+        getline(fin, buffer, '\0');
+
+        if ((fin.fail() && !fin.eof()) || fin.bad())
+            return ThrowException(String::New(strerror(errno)));
+
+        const Handle<Value> rc = ExecuteCode(buffer, *file);
+        if (rc.IsEmpty())
+            return Undefined();
+    }
+
+    return Undefined();
 }
 
@@ -743,5 +739,6 @@
     {
         string buffer;
-        if (!getline(fin, buffer, '\0'))
+        getline(fin, buffer, '\0');
+        if ((fin.fail() && !fin.eof()) || fin.bad())
             return ThrowException(String::New(strerror(errno)));
 
@@ -767,4 +764,121 @@
 
     return handle_scope.Close(arr);
+}
+
+// ==========================================================================
+//                                 Mail
+// ==========================================================================
+
+Handle<Value> InterpreterV8::ConstructorMail(const Arguments &args)
+{
+    if (!args.IsConstructCall())
+        return ThrowException(String::New("Mail must be called as constructor"));
+
+    HandleScope handle_scope;
+
+    Handle<Object> self = args.This();
+    self->Set(String::New("send"), FunctionTemplate::New(WrapSendMail)->GetFunction(), ReadOnly);
+    return handle_scope.Close(self);
+}
+
+vector<string> InterpreterV8::ValueToArray(const Handle<Value> &val)
+{
+    vector<string> rc;
+    if (val->IsString())
+    {
+        rc.push_back(*String::AsciiValue(val->ToString()));
+        return rc;
+    }
+
+    if (val->IsArray())
+    {
+        Handle<Array> arr = Handle<Array>::Cast(val);
+        for (uint32_t i=0; i<arr->Length(); i++)
+        {
+            Handle<Value> obj = arr->Get(i);
+            if (obj.IsEmpty())
+                continue;
+
+            if (!obj->IsString())
+                return vector<string>();
+
+            rc.push_back(*String::AsciiValue(obj->ToString()));
+        }
+    }
+
+    return rc;
+}
+
+Handle<Value> InterpreterV8::FuncSendMail(const Arguments& args)
+{
+    HandleScope handle_scope;
+
+    if (args.Length()>1)
+        return ThrowException(String::New("Only one argument allowed."));
+
+    if (args.Length()==1 && !args[0]->IsBoolean())
+        return ThrowException(String::New("Argument must be a boolean."));
+
+    const bool block = args.Length()==0 || args[0]->BooleanValue();
+
+    const Handle<Value> sub = args.This()->Get(String::New("subject"));
+    const Handle<Value> rec = args.This()->Get(String::New("recipient"));
+    const Handle<Value> txt = args.This()->Get(String::New("text"));
+    const Handle<Value> att = args.This()->Get(String::New("attachment"));
+    const Handle<Value> bcc = args.This()->Get(String::New("bcc"));
+    const Handle<Value> cc  = args.This()->Get(String::New("cc"));
+
+    if (sub->IsUndefined())
+        return ThrowException(String::New("Required property 'subject' missing."));
+
+    const vector<string> vrec = ValueToArray(rec);
+    const vector<string> vtxt = ValueToArray(txt);
+    const vector<string> vatt = ValueToArray(att);
+    const vector<string> vbcc = ValueToArray(bcc);
+    const vector<string> vcc  = ValueToArray(cc);
+
+    if (vrec.size()==0)
+        return ThrowException(String::New("Required property 'recipient' must be a string or an array of strings."));
+    if (vtxt.size()==0)
+        return ThrowException(String::New("Required property 'text' must be a string or an array of strings."));
+    if (vatt.size()==0 && !att->IsUndefined())
+        return ThrowException(String::New("Property 'attachment' must be a string or an array of strings."));
+    if (vbcc.size()==0 && !bcc->IsUndefined())
+        return ThrowException(String::New("Property 'bcc' must be a string or an array of strings."));
+    if (vcc.size()==0 && !cc->IsUndefined())
+        return ThrowException(String::New("Property 'cc' must be a string or an array of strings."));
+
+    if (!sub->IsString())
+        return ThrowException(String::New("Property 'subject' must be a string."));
+
+    const string subject = *String::AsciiValue(sub->ToString());
+
+
+    FILE *pipe = popen(("from=no-reply@fact-project.org mailx -~ "+vrec[0]).c_str(), "w");
+    if (!pipe)
+        return ThrowException(String::New(strerror(errno)));
+
+    fprintf(pipe, "%s", ("~s"+subject+"\n").c_str());
+    for (auto it=vrec.begin()+1; it<vrec.end(); it++)
+        fprintf(pipe, "%s", ("~t"+*it+"\n").c_str());
+    for (auto it=vbcc.begin(); it<vbcc.end(); it++)
+        fprintf(pipe, "%s", ("~b"+*it+"\n").c_str());
+    for (auto it=vcc.begin(); it<vcc.end(); it++)
+        fprintf(pipe, "%s", ("~c"+*it+"\n").c_str());
+    for (auto it=vatt.begin(); it<vatt.end(); it++)
+        fprintf(pipe, "%s", ("~@"+*it+"\n").c_str());  // Must not contain white spaces
+
+    for (auto it=vtxt.begin(); it<vtxt.end(); it++)
+        fwrite((*it+"\n").c_str(), it->length()+1, 1, pipe);
+
+    fprintf(pipe, "\n---\nsent by dimctrl");
+
+    if (!block)
+        return Undefined();
+
+    const int rc = pclose(pipe);
+
+    const Locker lock;
+    return handle_scope.Close(Integer::New(WEXITSTATUS(rc)));
 }
 
@@ -1275,4 +1389,5 @@
     }
 
+    // This hides the location of the exception, which is wanted.
     if (exception.HasCaught())
         return exception.ReThrow();
@@ -1972,4 +2087,7 @@
 
     const Handle<Value> result = ExecuteCode(code);
+
+    // This hides the location of the exception in the internal code,
+    // which is wanted.
     if (exception.HasCaught())
         exception.ReThrow();
@@ -1978,5 +2096,5 @@
 }
 
-Handle<Value> InterpreterV8::ExecuteCode(const string &code, const string &file, bool main)
+Handle<Value> InterpreterV8::ExecuteCode(const string &code, const string &file)
 {
     HandleScope handle_scope;
@@ -1985,66 +2103,27 @@
     const Handle<String> origin = String::New(file.c_str());
     if (source.IsEmpty())
-        return Handle<Value>();
+        return Undefined();
 
     const Handle<Script> script = Script::Compile(source, origin);
     if (script.IsEmpty())
-        return Handle<Value>();
-
-    if (main && JsGetCurrentState().index!=3)
-        JsSetState(3);
-
-    TryCatch exception;
-
-    const Handle<Value> result = script->Run();
-    if (exception.HasCaught())
-    {
-        if (file=="internal" || (fThreadId==V8::GetCurrentThreadId() && !main))
-            return exception.ReThrow();
-
-        HandleException(exception, "code");
-        return Handle<Value>();
-    }
+        return Undefined();
+
+    //if (main && JsGetCurrentState().index!=3)
+    //    JsSetState(3);
+
+    const Handle<Value> rc = script->Run();
+    if (rc.IsEmpty())
+        return Undefined();
 
     // If all went well and the result wasn't undefined then print
     // the returned value.
-    if (!result.IsEmpty() && !result->IsUndefined() && file!="internal")
-        JsResult(*String::AsciiValue(result));
-
-    return handle_scope.Close(result);
-}
-
-bool InterpreterV8::ExecuteFile(const string &name, bool main)
-{
-    ifstream fin(name.c_str());
-    if (!fin)
-    {
-        JsException("Error - Could not open file '"+name+"'");
-        return false;
-    }
-
-    string buffer;
-    if (!getline(fin, buffer, '\0'))
-        return true;
-
-    if (fin.fail())
-    {
-        JsException("Error - reading file.");
-        return false;
-    }
-
-    return !ExecuteCode(buffer, name, main).IsEmpty();
-}
-
-bool InterpreterV8::ExecuteConsole()
-{
-    // Just necessray for the Handle<Script>
-    const HandleScope handle_scope;
-
-    // A void script doing nothing than making sure that some JavaScript is executed
-    const Handle<Script> catcher = Script::Compile(String::New(";"), String::New(""));
-
-    // Unlocking is necessary for the preemption to work
-    const Unlocker global_unlock;
-
+    if (!rc->IsUndefined() && file!="internal")
+        JsResult(*String::AsciiValue(rc));
+
+    return handle_scope.Close(rc);
+}
+
+void InterpreterV8::ExecuteConsole()
+{
     JsSetState(3);
 
@@ -2057,4 +2136,11 @@
     while (1)
     {
+        // Create a local handle scope so that left-overs from single
+        // console inputs will not fill up the memory
+        const HandleScope handle_scope;
+
+        // Unlocking is necessary for the preemption to work
+        const Unlocker global_unlock;
+
         const string buffer = Tools::Trim(Readline::StaticPrompt(command.empty() ? "JS> " : " \\> "));
         if (buffer==".q")
@@ -2082,24 +2168,11 @@
         const Locker lock;
 
-        // Dump all pending exceptions. This is mainly to catch the 'null' exception
-        // thrown if a running JavaScript should be terminated from somewhere.
-        while (1)
-        {
-            TryCatch exception;
-            catcher->Run();
-            if (!exception.HasCaught())
-                break;
-        }
-
         // Catch exceptions during code compilation
         TryCatch exception;
 
         // Execute code which was entered
-        bool rc = ExecuteCode(command, "console", true).IsEmpty();
-        if (exception.HasCaught())
-        {
-            HandleException(exception, "compile");
-            rc = true;
-        }
+        ExecuteCode(command, "console");
+        if (!HandleException(exception, "console"))
+            lout << endl;
 
         // Stop all other threads
@@ -2114,8 +2187,4 @@
             usleep(1000);
 
-        // In case of an exception add an empty line to the output
-        if (rc)
-            lout << endl;
-
         // command has been executed, collect new command
         command = "";
@@ -2125,6 +2194,4 @@
 
     Readline::StaticPopHistory("java.his");
-
-    return true;
 }
 
@@ -2296,8 +2363,10 @@
     global->Set(String::New("Subscription"), sub, ReadOnly);
 
+#ifdef HAVE_SQL
     Handle<FunctionTemplate> db = FunctionTemplate::New(WrapDatabase);
     db->SetClassName(String::New("Database"));
     db->InstanceTemplate()->SetInternalFieldCount(1);
     global->Set(String::New("Database"), db, ReadOnly);
+#endif
 
     Handle<FunctionTemplate> thread = FunctionTemplate::New(WrapThread);
@@ -2319,4 +2388,10 @@
     fTemplateEvent = evt;
     fTemplateDescription = desc;
+
+#ifdef HAVE_MAIL
+    Handle<FunctionTemplate> mail = FunctionTemplate::New(ConstructorMail);
+    mail->SetClassName(String::New("Mail"));
+    global->Set(String::New("Mail"), mail, ReadOnly);
+#endif
 
 #ifdef HAVE_NOVA
@@ -2372,5 +2447,4 @@
     AddFormatToGlobal();
 
-    bool rc = true;
     if (!exception.HasCaught())
     {
@@ -2379,5 +2453,19 @@
         Locker::StartPreemption(10);
 
-        rc &= filename.empty() ? ExecuteConsole() : ExecuteFile(filename, true);
+        if (filename.empty())
+            ExecuteConsole();
+        else
+        {
+            // We call script->Run because it is the only way to
+            // catch exceptions.
+            const Handle<String> source = String::New(("include('"+filename+"');").c_str());
+            const Handle<String> origin = String::New("main");
+            const Handle<Script> script = Script::Compile(source, origin);
+            if (!script.IsEmpty())
+            {
+                JsSetState(3);
+                script->Run();
+            }
+        }
 
         Locker::StopPreemption();
@@ -2390,5 +2478,5 @@
 
     // Handle an exception
-    rc &= HandleException(exception, "main");
+    /*const bool rc =*/ HandleException(exception, "main");
 
     // IsProfilerPaused()
Index: trunk/FACT++/src/InterpreterV8.h
===================================================================
--- trunk/FACT++/src/InterpreterV8.h	(revision 15153)
+++ trunk/FACT++/src/InterpreterV8.h	(revision 15156)
@@ -58,10 +58,11 @@
 #ifdef HAVE_V8
     bool HandleException(v8::TryCatch &try_catch, const char *where);
-    bool ExecuteFile(const std::string &name, bool main=false);
-    bool ExecuteConsole();
-    v8::Handle<v8::Value> ExecuteCode(const std::string &code, const std::string &file="internal", bool main=false);
+    void ExecuteConsole();
+    v8::Handle<v8::Value> ExecuteCode(const std::string &code, const std::string &file="internal");
     v8::Handle<v8::Value> ExecuteInternal(const std::string &code);
 
     void Thread(int &id, v8::Persistent<v8::Function> func, uint32_t ms);
+
+    std::vector<std::string> ValueToArray(const v8::Handle<v8::Value> &val);
 
     v8::Handle<v8::Value> FuncWait(const v8::Arguments& args);
@@ -75,4 +76,5 @@
     v8::Handle<v8::Value> FuncOut(const v8::Arguments& args);
     v8::Handle<v8::Value> FuncFile(const v8::Arguments& args);
+    v8::Handle<v8::Value> FuncSendMail(const v8::Arguments& args);
     v8::Handle<v8::Value> FuncInclude(const v8::Arguments& args);
     v8::Handle<v8::Value> FuncExit(const v8::Arguments& args);
@@ -96,4 +98,6 @@
     static v8::Handle<v8::Value> Constructor(const v8::Arguments &args);
 
+    static v8::Handle<v8::Value> ConstructorMail(const v8::Arguments &args);
+
 #ifdef HAVE_NOVA
     static double GetDataMember(const v8::Arguments &args, const char *name);
@@ -120,4 +124,5 @@
     static v8::Handle<v8::Value> WrapInclude(const v8::Arguments &args)  { if (This) return This->FuncInclude(args);  else return v8::Undefined(); }
     static v8::Handle<v8::Value> WrapFile(const v8::Arguments &args)     { if (This) return This->FuncFile(args);     else return v8::Undefined(); }
+    static v8::Handle<v8::Value> WrapSendMail(const v8::Arguments &args) { if (This) return This->FuncSendMail(args); else return v8::Undefined(); }
     static v8::Handle<v8::Value> WrapLog(const v8::Arguments &args)      { if (This) return This->FuncLog(args);      else return v8::Undefined(); }
     static v8::Handle<v8::Value> WrapAlarm(const v8::Arguments &args)    { if (This) return This->FuncAlarm(args);    else return v8::Undefined(); }
