/* * Baltisot * Copyright (C) 1999-2008 Nicolas "Pixel" Noble * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #include #include #include #ifndef LUATASK_OMIT_HTTPCLIENT #include #endif #ifndef LUATASK_OMIT_MAILCLIENT #include #endif #ifndef LUATASK_OMIT_COMMAND #include #endif htab * LuaTask::h = hcreate(1); LuaTask::LuaTask(Lua * __L, const String & _cmd, bool _destroy_VM) : L(__L), cmd(_cmd), nargs(0), c(0), b(0), destroy_VM(_destroy_VM) { LuaTask * top = gettop(); if (top) { WaitFor(top); } else { SetBurst(); } settop(this); stacktop = L->gettop() + 1; } LuaTask::LuaTask(Lua * __L, int _nargs, bool _destroy_VM) throw (GeneralException) : L(__L), cmd(""), nargs(_nargs), c(0), b(0), destroy_VM(_destroy_VM) { if (gettop()) throw GeneralException("Can't run a stack-based LuaTask when there are other tasks waiting."); SetBurst(); settop(this); stacktop = L->gettop() - nargs; } LuaTask::~LuaTask() { if (gettop() == this) { settop(0); } if (destroy_VM) L->weaken(); } LuaTask * LuaTask::gettop() { if (!hfind(h, (Uint8 *) &L, sizeof(L))) { hadd(h, (Uint8 *) &L, sizeof(L), 0); } return (LuaTask *) hstuff(h); } void LuaTask::settop(LuaTask * v) { if (!hfind(h, (Uint8 *) &L, sizeof(L))) return; if (v) { hstuff(h) = v; } else { hdel(h); } } String LuaTask::GetName() { return "LuaTask(" + cmd + ")"; } std::vector LuaTask::array_to_vector(int index) throw (GeneralException) { std::vector r; if (L->isnil(index)) return r; if (!L->istable(index)) { throw GeneralException("Argument isn't a table."); } L->push(); while(L->next(index) != 0) { r.push_back(L->tostring(-1)); L->pop(); } return r; } int LuaTask::Do() throw (GeneralException) { bool yielded; switch (current) { case 0: current = 1; if (cmd != "") { yielded = L->resume(cmd); } else { yielded = L->resume(nargs); } case 2: nargs = 0; #ifndef LUATASK_OMIT_HTTPCLIENT if (task == "HttpClient") { LuaBuffer o(b); o.pushdestruct(L); L->newtable(); HttpClient * x = dynamic_cast(c); int n = 1; for (t_headers::iterator i = x->reply_headers.begin(); i != x->reply_headers.end(); i++) { L->push((lua_Number) n++); L->push(*i); L->settable(); } L->push(x->GetStatus()); nargs = 3; } #endif #ifndef LUATASK_OMIT_MAILCLIENT if (task == "MailClient") { L->push(dynamic_cast(c)->GetStatus()); nargs = 1; delete b; b = 0; } #endif #ifndef LUATASK_OMIT_COMMAND if (task == "Command") { delete p; LuaBuffer o(b); o.pushdestruct(L); L->push((lua_Number) TaskMan::Estatus()); nargs = 2; } #endif if (task == "Yield") { nargs = 0; } if (task == "Delay") { nargs = 0; } if (c) delete c; c = 0; if (current != 1) yielded = L->resume(nargs); case 1: if (!yielded) return TASK_DONE; current = 2; if (L->gettop() >= 1) { task = L->tostring(1); if (task == "") { L->error("Must precise a task-type to execute."); return TASK_DONE; #ifndef LUATASK_OMIT_HTTPCLIENT } else if (task == "HttpClient") { t_headers headers; Variables vars; if (L->gettop() >= 4) { if (!L->istable(4)) { L->error("Incorrect parameters to HttpClient."); return TASK_DONE; } // read variables L->push(); while (L->next(4) != 0) { String v = L->tostring(-2) + "=" + L->tostring(-1); vars.Add(v); L->pop(); } } if (L->gettop() >= 3) { if (!L->istable(3)) { L->error("Incorrect parameters to HttpClient."); return TASK_DONE; } // read headers L->push(); while (L->next(3) != 0) { String h = L->tostring(-2) + ": " + L->tostring(-1); headers.push_back(h); L->pop(); } } if (L->gettop() <= 1) { L->error("Incorrect number of parameters to HttpClient."); } String url = L->tostring(2); b = new Buffer(true); c = new HttpClient(url, b, "", headers, vars); WaitFor(c); Suspend(TASK_ON_HOLD); #endif #ifndef LUATASK_OMIT_MAILCLIENT } else if (task == "MailClient") { String smtp, subject, from, body; MailClient::strings_t headers, tos, ccs, bccs, fakes; if (L->gettop() != 10) { L->error("Incorrect number of parameters to MailClient."); return TASK_DONE; } smtp = L->tostring(2); subject = L->tostring(3); from = L->tostring(4); try { headers = array_to_vector(5); tos = array_to_vector(6); ccs = array_to_vector(7); bccs = array_to_vector(8); fakes = array_to_vector(9); } catch (GeneralException e) { L->error("Incorrect parameters to MailClient."); } body = L->tostring(10); b = new Buffer(true); (*b) << body; c = new MailClient(smtp, subject, from, headers, tos, ccs, bccs, fakes, b); WaitFor(c); Suspend(TASK_ON_HOLD); #endif #ifndef LUATASK_OMIT_COMMAND } else if (task == "Command") { pid_t pid; int i; char * cmd; char ** args, ** ptr; cmd = L->tostring(2).strdup(); args = (char **) malloc(sizeof(char *) * (L->gettop())); args[0] = cmd; for (i = 3; i <= L->gettop(); i++) { args[i - 2] = L->tostring(i).strdup(); } args[L->gettop() - 1] = 0; b = new Buffer(true); p = new InPipe(); p->SetNonBlock(); if (!(pid = fork())) { p->Hook(); execvp(cmd, args); } c = new CopyJob(p, b); for (i = 3; i <= L->gettop(); i++) { free(args[i - 2]); } free(cmd); current = 3; WaitFor(pid); Suspend(TASK_ON_HOLD); #endif } else if (task == "Yield") { Yield(); return TASK_ON_HOLD; } else if (task == "Delay") { if (L->gettop() != 2) { L->error("Incorrect number of parameters to Delay"); } timeval delay_tv = { L->tonumber(), 0 }; WaitFor(delay_tv); return TASK_ON_HOLD; } else { L->error("Unknow requested task: " + task); return TASK_DONE; } } else { return TASK_DONE; } break; #ifndef LUATASK_OMIT_COMMAND case 3: current = 2; WaitFor(c); p->HalfClose(); return TASK_ON_HOLD; #endif } return TASK_ON_HOLD; } enum TaskMan_functions_t { TASKMAN_NB_TASKS = 0, TASKMAN_NB_ZOMBIES, TASKMAN_DELAYED_TASK, }; struct lua_functypes_t TaskMan_functions[] = { { TASKMAN_NB_TASKS, "NB_Tasks", 0, 0, { } }, { TASKMAN_NB_ZOMBIES, "NB_Zombies", 0, 0, { } }, { TASKMAN_DELAYED_TASK, "DelayedTask", 1, 2, { BLUA_STRING, BLUA_NUMBER } }, { -1, 0, 0, 0, 0 } }; class sLua_TaskMan : public Base { public: DECLARE_FUNCTION(TaskMan, TASKMAN_NB_TASKS); DECLARE_FUNCTION(TaskMan, TASKMAN_NB_ZOMBIES); DECLARE_FUNCTION(TaskMan, TASKMAN_DELAYED_TASK); private: static int TaskMan_proceed_statics(Lua * L, int n, int caller); }; void LuaTaskMan::pushstatics(Lua * L) throw (GeneralException) { CHECK_FUNCTIONS(TaskMan); PUSH_FUNCTION(TaskMan, TASKMAN_NB_TASKS); PUSH_FUNCTION(TaskMan, TASKMAN_NB_ZOMBIES); PUSH_FUNCTION(TaskMan, TASKMAN_DELAYED_TASK); } class DelayedTask : public Task { public: DelayedTask(Lua * __L, const String & _cmd, int _delay) : L(__L), cmd(_cmd), delay(_delay) { SetBurst(); } virtual int Do() throw (GeneralException) { timeval delay_tv = { delay, 0 }; switch(current) { case 0: WaitFor(delay_tv); current = 1; return TASK_ON_HOLD; case 1: RemoveTimeout(); new LuaTask(L, cmd); return TASK_DONE; } } private: Lua * L; String cmd; int delay; }; int sLua_TaskMan::TaskMan_proceed_statics(Lua * L, int n, int caller) { String cmd; int delay = 1; switch (caller) { case TASKMAN_NB_TASKS: L->push((lua_Number) TaskMan::nb_tasks()); break; case TASKMAN_NB_ZOMBIES: L->push((lua_Number) TaskMan::nb_zombies()); break; case TASKMAN_DELAYED_TASK: cmd = L->tostring(1); if (n == 2) delay = L->tonumber(2); new DelayedTask(L, cmd, delay); break; } return 1; }