2004-05-22 00:05:20 +00:00
|
|
|
/**
|
|
|
|
* extmodule.cpp
|
|
|
|
* This file is part of the YATE Project http://YATE.null.ro
|
|
|
|
*
|
|
|
|
* Some parts of this code have been stolen shamelessly from app_agi.
|
|
|
|
* I think that AGI is great idea.
|
|
|
|
*
|
|
|
|
* External module handler
|
2004-11-29 03:56:41 +00:00
|
|
|
*
|
|
|
|
* Yet Another Telephony Engine - a fully featured software PBX and IVR
|
|
|
|
* Copyright (C) 2004 Null Team
|
|
|
|
*
|
|
|
|
* 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
2004-05-22 00:05:20 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <telengine.h>
|
|
|
|
#include <telephony.h>
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <errno.h>
|
|
|
|
|
|
|
|
|
|
|
|
using namespace TelEngine;
|
|
|
|
|
|
|
|
static Configuration s_cfg;
|
2004-06-26 23:10:50 +00:00
|
|
|
static ObjList s_chans;
|
|
|
|
static ObjList s_modules;
|
2004-05-22 00:05:20 +00:00
|
|
|
|
|
|
|
class ExtModReceiver;
|
2004-09-08 15:54:56 +00:00
|
|
|
class ExtModChan;
|
2004-05-22 00:05:20 +00:00
|
|
|
|
|
|
|
class ExtModSource : public ThreadedSource
|
|
|
|
{
|
|
|
|
public:
|
2004-09-08 15:54:56 +00:00
|
|
|
ExtModSource(int fd, ExtModChan* chan);
|
2004-05-22 00:05:20 +00:00
|
|
|
~ExtModSource();
|
|
|
|
virtual void run();
|
|
|
|
private:
|
|
|
|
int m_fd;
|
|
|
|
unsigned m_brate;
|
|
|
|
unsigned m_total;
|
2004-09-08 15:54:56 +00:00
|
|
|
ExtModChan* m_chan;
|
2004-05-22 00:05:20 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class ExtModConsumer : public DataConsumer
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
ExtModConsumer(int fd);
|
|
|
|
~ExtModConsumer();
|
2004-09-29 00:15:52 +00:00
|
|
|
virtual void Consume(const DataBlock &data, unsigned long timestamp);
|
2004-05-22 00:05:20 +00:00
|
|
|
private:
|
|
|
|
int m_fd;
|
|
|
|
unsigned m_total;
|
|
|
|
};
|
|
|
|
|
|
|
|
class ExtModChan : public DataEndpoint
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
enum {
|
2004-06-03 22:26:29 +00:00
|
|
|
NoChannel,
|
|
|
|
DataNone,
|
2004-05-22 00:05:20 +00:00
|
|
|
DataRead,
|
|
|
|
DataWrite,
|
|
|
|
DataBoth
|
|
|
|
};
|
2004-09-08 15:54:56 +00:00
|
|
|
static ExtModChan* build(const char *file, const char *args, int type);
|
2004-05-22 00:05:20 +00:00
|
|
|
~ExtModChan();
|
2004-11-01 12:41:38 +00:00
|
|
|
virtual void disconnected(const char *reason);
|
2004-09-08 15:54:56 +00:00
|
|
|
inline ExtModReceiver* receiver() const
|
|
|
|
{ return m_recv; }
|
|
|
|
inline void setRecv(ExtModReceiver* recv)
|
|
|
|
{ m_recv = recv; }
|
|
|
|
inline void setRunning(bool running)
|
|
|
|
{ m_running = running; }
|
|
|
|
inline bool running() const
|
|
|
|
{ return m_running; }
|
2004-05-22 00:05:20 +00:00
|
|
|
private:
|
2004-09-08 15:54:56 +00:00
|
|
|
ExtModChan(const char *file, const char *args, int type);
|
2004-05-22 00:05:20 +00:00
|
|
|
ExtModReceiver *m_recv;
|
2004-06-26 23:10:50 +00:00
|
|
|
int m_type;
|
2004-09-08 15:54:56 +00:00
|
|
|
bool m_running;
|
2004-05-22 00:05:20 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class MsgHolder : public GenObject
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
MsgHolder(Message &msg);
|
|
|
|
Message &m_msg;
|
|
|
|
bool m_ret;
|
|
|
|
String m_id;
|
|
|
|
bool decode(const char *s);
|
|
|
|
};
|
|
|
|
|
|
|
|
class ExtModReceiver : public MessageReceiver
|
|
|
|
{
|
|
|
|
public:
|
2004-09-08 15:54:56 +00:00
|
|
|
static ExtModReceiver* build(const char *script, const char *args,
|
2004-05-22 00:05:20 +00:00
|
|
|
int ain = -1, int aout = -1, ExtModChan *chan = 0);
|
2004-10-19 22:11:59 +00:00
|
|
|
static ExtModReceiver* find(const String &script);
|
2004-05-22 00:05:20 +00:00
|
|
|
~ExtModReceiver();
|
|
|
|
virtual bool received(Message &msg, int id);
|
|
|
|
void processLine(const char *line);
|
2004-06-03 22:26:29 +00:00
|
|
|
bool outputLine(const char *line);
|
2004-05-24 00:38:23 +00:00
|
|
|
void reportError(const char *line);
|
2004-09-08 15:54:56 +00:00
|
|
|
bool start();
|
2004-05-22 00:05:20 +00:00
|
|
|
void run();
|
2004-09-08 15:54:56 +00:00
|
|
|
void cleanup();
|
|
|
|
void die(bool clearChan = true);
|
2004-09-25 18:22:40 +00:00
|
|
|
inline void use()
|
|
|
|
{ m_use++; }
|
|
|
|
bool unuse();
|
2004-10-20 00:08:15 +00:00
|
|
|
inline const String &scriptFile() const
|
|
|
|
{ return m_script; }
|
|
|
|
inline const String &commandArg() const
|
|
|
|
{ return m_args; }
|
2004-05-22 00:05:20 +00:00
|
|
|
private:
|
2004-09-08 15:54:56 +00:00
|
|
|
ExtModReceiver(const char *script, const char *args,
|
|
|
|
int ain = -1, int aout = -1, ExtModChan *chan = 0);
|
2004-06-06 01:27:21 +00:00
|
|
|
bool create(const char *script, const char *args);
|
2004-09-08 15:54:56 +00:00
|
|
|
bool m_dead;
|
2004-09-25 18:22:40 +00:00
|
|
|
int m_use;
|
2004-05-22 00:05:20 +00:00
|
|
|
pid_t m_pid;
|
|
|
|
int m_in, m_out, m_ain, m_aout;
|
|
|
|
ExtModChan *m_chan;
|
|
|
|
String m_script, m_args;
|
|
|
|
ObjList m_waiting;
|
2004-09-10 21:53:59 +00:00
|
|
|
ObjList m_reenter;
|
2004-05-24 00:38:23 +00:00
|
|
|
ObjList m_relays;
|
2004-05-22 00:05:20 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class ExtThread : public Thread
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
ExtThread(ExtModReceiver *receiver) : Thread("ExtModule"), m_receiver(receiver)
|
|
|
|
{ }
|
|
|
|
virtual void run()
|
|
|
|
{ m_receiver->run(); }
|
2004-09-08 15:54:56 +00:00
|
|
|
virtual void cleanup()
|
|
|
|
{ m_receiver->cleanup(); }
|
2004-05-22 00:05:20 +00:00
|
|
|
private:
|
|
|
|
ExtModReceiver *m_receiver;
|
|
|
|
};
|
|
|
|
|
|
|
|
class ExtModHandler : public MessageHandler
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
ExtModHandler(const char *name) : MessageHandler(name) { }
|
|
|
|
virtual bool received(Message &msg);
|
|
|
|
};
|
|
|
|
|
2004-10-19 22:11:59 +00:00
|
|
|
class ExtModCommand : public MessageHandler
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
ExtModCommand(const char *name) : MessageHandler(name) { }
|
|
|
|
virtual bool received(Message &msg);
|
|
|
|
};
|
|
|
|
|
2004-05-22 00:05:20 +00:00
|
|
|
class ExtModulePlugin : public Plugin
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
ExtModulePlugin();
|
|
|
|
~ExtModulePlugin();
|
|
|
|
virtual void initialize();
|
2004-11-01 00:07:00 +00:00
|
|
|
virtual bool isBusy() const;
|
2004-05-22 00:05:20 +00:00
|
|
|
private:
|
|
|
|
ExtModHandler *m_handler;
|
|
|
|
};
|
|
|
|
|
2004-05-24 00:38:23 +00:00
|
|
|
|
2004-09-08 15:54:56 +00:00
|
|
|
ExtModSource::ExtModSource(int fd, ExtModChan* chan)
|
|
|
|
: m_fd(fd), m_brate(16000), m_total(0), m_chan(chan)
|
2004-05-22 00:05:20 +00:00
|
|
|
{
|
|
|
|
Debug(DebugAll,"ExtModSource::ExtModSource(%d) [%p]",fd,this);
|
2004-06-03 22:26:29 +00:00
|
|
|
if (m_fd >= 0) {
|
2004-09-08 15:54:56 +00:00
|
|
|
chan->setRunning(true);
|
2004-05-22 00:05:20 +00:00
|
|
|
start("ExtModSource");
|
2004-06-03 22:26:29 +00:00
|
|
|
}
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ExtModSource::~ExtModSource()
|
|
|
|
{
|
|
|
|
Debug(DebugAll,"ExtModSource::~ExtModSource() [%p] total=%u",this,m_total);
|
2004-09-08 15:54:56 +00:00
|
|
|
m_chan->setRunning(false);
|
2004-05-22 00:05:20 +00:00
|
|
|
if (m_fd >= 0) {
|
|
|
|
::close(m_fd);
|
|
|
|
m_fd = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ExtModSource::run()
|
|
|
|
{
|
|
|
|
DataBlock data(0,480);
|
|
|
|
int r = 0;
|
|
|
|
unsigned long long tpos = Time::now();
|
|
|
|
do {
|
|
|
|
r = ::read(m_fd,data.data(),data.length());
|
|
|
|
if (r < 0) {
|
|
|
|
if (errno == EINTR) {
|
|
|
|
r = 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (r < (int)data.length())
|
|
|
|
data.assign(data.data(),r);
|
|
|
|
long long dly = tpos - Time::now();
|
|
|
|
if (dly > 0) {
|
2004-11-29 21:01:04 +00:00
|
|
|
DDebug("ExtModSource",DebugAll,"Sleeping for %lld usec",dly);
|
2004-05-22 00:05:20 +00:00
|
|
|
::usleep((unsigned long)dly);
|
|
|
|
}
|
2004-09-29 00:15:52 +00:00
|
|
|
Forward(data,m_total);
|
2004-05-22 00:05:20 +00:00
|
|
|
m_total += r;
|
|
|
|
tpos += (r*1000000ULL/m_brate);
|
|
|
|
} while (r > 0);
|
|
|
|
Debug(DebugAll,"ExtModSource [%p] end of data total=%u",this,m_total);
|
2004-09-08 15:54:56 +00:00
|
|
|
m_chan->setRunning(false);
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ExtModConsumer::ExtModConsumer(int fd)
|
|
|
|
: m_fd(fd), m_total(0)
|
|
|
|
{
|
|
|
|
Debug(DebugAll,"ExtModConsumer::ExtModConsumer(%d) [%p]",fd,this);
|
|
|
|
}
|
|
|
|
|
|
|
|
ExtModConsumer::~ExtModConsumer()
|
|
|
|
{
|
|
|
|
Debug(DebugAll,"ExtModConsumer::~ExtModConsumer() [%p] total=%u",this,m_total);
|
|
|
|
if (m_fd >= 0) {
|
|
|
|
::close(m_fd);
|
|
|
|
m_fd = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-09-29 00:15:52 +00:00
|
|
|
void ExtModConsumer::Consume(const DataBlock &data, unsigned long timestamp)
|
2004-05-22 00:05:20 +00:00
|
|
|
{
|
|
|
|
if ((m_fd >= 0) && !data.null()) {
|
|
|
|
::write(m_fd,data.data(),data.length());
|
|
|
|
m_total += data.length();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-09-08 15:54:56 +00:00
|
|
|
ExtModChan* ExtModChan::build(const char *file, const char *args, int type)
|
|
|
|
{
|
|
|
|
ExtModChan* chan = new ExtModChan(file,args,type);
|
|
|
|
if (!chan->m_recv) {
|
|
|
|
chan->destruct();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return chan;
|
|
|
|
}
|
|
|
|
|
2004-06-25 22:03:36 +00:00
|
|
|
ExtModChan::ExtModChan(const char *file, const char *args, int type)
|
2004-06-26 23:10:50 +00:00
|
|
|
: DataEndpoint("ExtModule"), m_recv(0), m_type(type)
|
2004-05-22 00:05:20 +00:00
|
|
|
{
|
|
|
|
Debug(DebugAll,"ExtModChan::ExtModChan(%d) [%p]",type,this);
|
|
|
|
int wfifo[2] = { -1, -1 };
|
|
|
|
int rfifo[2] = { -1, -1 };
|
2004-06-26 23:10:50 +00:00
|
|
|
switch (m_type) {
|
2004-05-22 00:05:20 +00:00
|
|
|
case DataWrite:
|
|
|
|
case DataBoth:
|
|
|
|
::pipe(wfifo);
|
|
|
|
setConsumer(new ExtModConsumer(wfifo[1]));
|
|
|
|
getConsumer()->deref();
|
|
|
|
}
|
2004-06-26 23:10:50 +00:00
|
|
|
switch (m_type) {
|
2004-05-22 00:05:20 +00:00
|
|
|
case DataRead:
|
|
|
|
case DataBoth:
|
|
|
|
::pipe(rfifo);
|
2004-09-08 15:54:56 +00:00
|
|
|
setSource(new ExtModSource(rfifo[0],this));
|
2004-05-22 00:05:20 +00:00
|
|
|
getSource()->deref();
|
|
|
|
}
|
2004-06-26 23:10:50 +00:00
|
|
|
s_chans.append(this);
|
2004-09-08 15:54:56 +00:00
|
|
|
m_recv = ExtModReceiver::build(file,args,wfifo[0],rfifo[1],this);
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ExtModChan::~ExtModChan()
|
|
|
|
{
|
2004-09-25 18:22:40 +00:00
|
|
|
Debugger debug(DebugAll,"ExtModChan::~ExtModChan()"," [%p]",this);
|
2004-06-26 23:10:50 +00:00
|
|
|
s_chans.remove(this,false);
|
2004-09-25 18:22:40 +00:00
|
|
|
setSource();
|
|
|
|
setConsumer();
|
2004-09-08 15:54:56 +00:00
|
|
|
if (m_recv)
|
|
|
|
m_recv->die(false);
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
|
2004-11-01 12:41:38 +00:00
|
|
|
void ExtModChan::disconnected(const char *reason)
|
2004-05-22 00:05:20 +00:00
|
|
|
{
|
2004-11-01 12:41:38 +00:00
|
|
|
Debugger debug("ExtModChan::disconnected()"," '%s' [%p]",reason,this);
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
MsgHolder::MsgHolder(Message &msg)
|
|
|
|
: m_msg(msg), m_ret(false)
|
|
|
|
{
|
2004-06-26 23:10:50 +00:00
|
|
|
// the address of this object should be unique
|
2004-09-10 21:53:59 +00:00
|
|
|
m_id = (unsigned int)this;
|
|
|
|
m_id << (unsigned int)random();
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool MsgHolder::decode(const char *s)
|
|
|
|
{
|
|
|
|
return (m_msg.decode(s,m_ret,m_id) == -2);
|
|
|
|
}
|
|
|
|
|
2004-09-08 15:54:56 +00:00
|
|
|
ExtModReceiver* ExtModReceiver::build(const char *script, const char *args,
|
|
|
|
int ain, int aout, ExtModChan *chan)
|
|
|
|
{
|
|
|
|
ExtModReceiver* recv = new ExtModReceiver(script,args,ain,aout,chan);
|
|
|
|
if (!recv->start()) {
|
|
|
|
recv->destruct();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return recv;
|
|
|
|
}
|
|
|
|
|
2004-10-19 22:11:59 +00:00
|
|
|
ExtModReceiver* ExtModReceiver::find(const String &script)
|
|
|
|
{
|
|
|
|
ObjList *l = &s_modules;
|
|
|
|
for (; l; l=l->next()) {
|
|
|
|
ExtModReceiver *r = static_cast<ExtModReceiver *>(l->get());
|
2004-10-20 00:08:15 +00:00
|
|
|
if (r && (r->scriptFile() == script))
|
2004-10-19 22:11:59 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2004-09-25 18:22:40 +00:00
|
|
|
bool ExtModReceiver::unuse()
|
|
|
|
{
|
|
|
|
int u = --m_use;
|
|
|
|
if (!u)
|
|
|
|
destruct();
|
|
|
|
return (u <= 0);
|
|
|
|
}
|
|
|
|
|
2004-05-22 00:05:20 +00:00
|
|
|
ExtModReceiver::ExtModReceiver(const char *script, const char *args, int ain, int aout, ExtModChan *chan)
|
2004-09-25 18:22:40 +00:00
|
|
|
: m_dead(false), m_use(0), m_pid(-1), m_in(-1), m_out(-1), m_ain(ain), m_aout(aout),
|
2004-05-22 00:05:20 +00:00
|
|
|
m_chan(chan), m_script(script), m_args(args)
|
|
|
|
{
|
|
|
|
Debug(DebugAll,"ExtModReceiver::ExtModReceiver(\"%s\",\"%s\") [%p]",script,args,this);
|
2004-10-19 22:11:59 +00:00
|
|
|
m_script.trimBlanks();
|
|
|
|
m_args.trimBlanks();
|
2004-06-26 23:10:50 +00:00
|
|
|
s_modules.append(this);
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
|
2004-09-08 15:54:56 +00:00
|
|
|
|
2004-05-22 00:05:20 +00:00
|
|
|
ExtModReceiver::~ExtModReceiver()
|
|
|
|
{
|
2004-09-08 15:54:56 +00:00
|
|
|
Debug(DebugAll,"ExtModReceiver::~ExtModReceiver() [%p] pid=%d",this,m_pid);
|
2004-10-19 15:31:20 +00:00
|
|
|
/* One destruction is plenty enough */
|
|
|
|
m_use = -100;
|
2004-06-26 23:10:50 +00:00
|
|
|
s_modules.remove(this,false);
|
2004-06-06 01:27:21 +00:00
|
|
|
die();
|
2004-09-08 15:54:56 +00:00
|
|
|
if (m_pid > 0)
|
|
|
|
Debug(DebugWarn,"ExtModReceiver::~ExtModReceiver() [%p] pid=%d",this,m_pid);
|
2004-06-06 01:27:21 +00:00
|
|
|
}
|
|
|
|
|
2004-09-08 15:54:56 +00:00
|
|
|
bool ExtModReceiver::start()
|
2004-06-06 01:27:21 +00:00
|
|
|
{
|
2004-09-08 15:54:56 +00:00
|
|
|
if (m_pid < 0) {
|
2004-11-01 00:07:00 +00:00
|
|
|
ExtThread *ext = new ExtThread(this);
|
|
|
|
ext->startup();
|
2004-09-08 15:54:56 +00:00
|
|
|
while (m_pid < 0)
|
|
|
|
Thread::yield();
|
|
|
|
}
|
|
|
|
return (m_pid > 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void ExtModReceiver::die(bool clearChan)
|
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
2004-10-19 15:31:20 +00:00
|
|
|
Debugger debug(DebugAll,"ExtModReceiver::die()"," pid=%d dead=%s [%p]",
|
|
|
|
m_pid,m_dead ? "yes" : "no",this);
|
|
|
|
#else
|
|
|
|
Debug(DebugAll,"ExtModReceiver::die() pid=%d dead=%s [%p]",
|
|
|
|
m_pid,m_dead ? "yes" : "no",this);
|
2004-09-08 15:54:56 +00:00
|
|
|
#endif
|
|
|
|
if (m_dead)
|
|
|
|
return;
|
|
|
|
m_dead = true;
|
2004-09-25 18:22:40 +00:00
|
|
|
use();
|
|
|
|
/* Make sure we release all pending messages and not accept new ones */
|
|
|
|
if (!Engine::exiting())
|
|
|
|
m_relays.clear();
|
|
|
|
else {
|
|
|
|
ObjList *p = &m_relays;
|
|
|
|
for (; p; p=p->next())
|
|
|
|
p->setDelete(false);
|
|
|
|
}
|
|
|
|
if (m_waiting.get()) {
|
|
|
|
m_waiting.clear();
|
|
|
|
Thread::yield();
|
|
|
|
}
|
|
|
|
|
|
|
|
ExtModChan *chan = m_chan;
|
|
|
|
m_chan = 0;
|
2004-10-19 15:31:20 +00:00
|
|
|
if (chan)
|
|
|
|
chan->setRecv(0);
|
2004-09-25 18:22:40 +00:00
|
|
|
|
2004-09-08 15:54:56 +00:00
|
|
|
/* Give the external script a chance to die gracefully */
|
|
|
|
if (m_out != -1) {
|
|
|
|
::close(m_out);
|
|
|
|
m_out = -1;
|
|
|
|
}
|
|
|
|
if (m_pid > 0) {
|
|
|
|
Debug(DebugAll,"ExtModReceiver::die() waiting for pid=%d to die",m_pid);
|
|
|
|
for (int i=0; i<100; i++) {
|
|
|
|
Thread::yield();
|
|
|
|
if (m_pid <= 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (m_pid > 0)
|
|
|
|
Debug(DebugInfo,"ExtModReceiver::die() pid=%d did not exit?",m_pid);
|
2004-09-25 18:22:40 +00:00
|
|
|
|
2004-09-08 15:54:56 +00:00
|
|
|
/* Now terminate the process and close its stdout pipe */
|
2004-06-06 01:27:21 +00:00
|
|
|
if (m_in != -1) {
|
|
|
|
::close(m_in);
|
|
|
|
m_in = -1;
|
|
|
|
}
|
2004-09-25 18:22:40 +00:00
|
|
|
if (m_pid > 0)
|
|
|
|
::kill(m_pid,SIGTERM);
|
|
|
|
if (chan && clearChan)
|
|
|
|
chan->disconnect();
|
|
|
|
unuse();
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ExtModReceiver::received(Message &msg, int id)
|
|
|
|
{
|
2004-06-06 01:27:21 +00:00
|
|
|
if (m_pid <= 0)
|
|
|
|
return false;
|
2004-06-03 22:26:29 +00:00
|
|
|
/* Check if the message was generated by ourselves - avoid reentrance */
|
2004-09-10 21:53:59 +00:00
|
|
|
if (m_reenter.find(&msg))
|
2004-06-03 22:26:29 +00:00
|
|
|
return false;
|
|
|
|
|
2004-09-25 18:22:40 +00:00
|
|
|
use();
|
2004-05-22 00:05:20 +00:00
|
|
|
MsgHolder h(msg);
|
2004-06-03 22:26:29 +00:00
|
|
|
m_waiting.append(&h)->setDelete(false);
|
2004-11-29 21:01:04 +00:00
|
|
|
DDebug(DebugAll,"ExtMod [%p] queued message '%s' [%p]",this,msg.c_str(),&msg);
|
2004-05-22 00:05:20 +00:00
|
|
|
outputLine(msg.encode(h.m_id));
|
|
|
|
while (m_waiting.find(&h))
|
|
|
|
Thread::yield();
|
2004-11-29 21:01:04 +00:00
|
|
|
DDebug(DebugAll,"ExtMod [%p] message '%s' [%p] returning %s",this,msg.c_str(),&msg, h.m_ret ? "true" : "false");
|
2004-09-25 18:22:40 +00:00
|
|
|
unuse();
|
2004-05-22 00:05:20 +00:00
|
|
|
return h.m_ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ExtModReceiver::create(const char *script, const char *args)
|
|
|
|
{
|
|
|
|
String tmp(script);
|
|
|
|
int pid;
|
|
|
|
int ext2yate[2];
|
|
|
|
int yate2ext[2];
|
|
|
|
int x;
|
|
|
|
if (script[0] != '/') {
|
|
|
|
tmp = s_cfg.getValue("general","scripts_dir","scripts/") + tmp;
|
|
|
|
}
|
|
|
|
script = tmp.c_str();
|
|
|
|
if (::pipe(ext2yate)) {
|
|
|
|
Debug(DebugWarn, "Unable to create ext->yate pipe: %s",strerror(errno));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (pipe(yate2ext)) {
|
|
|
|
Debug(DebugWarn, "unable to create yate->ext pipe: %s", strerror(errno));
|
|
|
|
::close(ext2yate[0]);
|
|
|
|
::close(ext2yate[1]);
|
|
|
|
return false;
|
|
|
|
}
|
2004-08-19 22:53:55 +00:00
|
|
|
pid = ::fork();
|
2004-05-22 00:05:20 +00:00
|
|
|
if (pid < 0) {
|
|
|
|
Debug(DebugWarn, "Failed to fork(): %s", strerror(errno));
|
2004-09-08 15:54:56 +00:00
|
|
|
::close(yate2ext[0]);
|
|
|
|
::close(yate2ext[1]);
|
|
|
|
::close(ext2yate[0]);
|
|
|
|
::close(ext2yate[1]);
|
2004-05-22 00:05:20 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!pid) {
|
2004-06-06 01:27:21 +00:00
|
|
|
/* In child - terminate all other threads if needed */
|
2004-05-22 00:05:20 +00:00
|
|
|
Thread::preExec();
|
2004-08-23 14:20:07 +00:00
|
|
|
/* Try to immunize child from ^C and ^\ */
|
|
|
|
::signal(SIGINT,SIG_IGN);
|
|
|
|
::signal(SIGQUIT,SIG_IGN);
|
|
|
|
/* And restore default handlers for other signals */
|
|
|
|
::signal(SIGTERM,SIG_DFL);
|
|
|
|
::signal(SIGHUP,SIG_DFL);
|
2004-05-22 00:05:20 +00:00
|
|
|
/* Redirect stdin and out */
|
|
|
|
::dup2(yate2ext[0], STDIN_FILENO);
|
|
|
|
::dup2(ext2yate[1], STDOUT_FILENO);
|
|
|
|
/* Set audio in/out handlers */
|
|
|
|
if (m_ain != -1)
|
|
|
|
::dup2(m_ain, STDERR_FILENO+1);
|
|
|
|
else
|
|
|
|
::close(STDERR_FILENO+1);
|
|
|
|
if (m_aout != -1)
|
|
|
|
::dup2(m_aout, STDERR_FILENO+2);
|
|
|
|
else
|
|
|
|
::close(STDERR_FILENO+2);
|
2004-06-06 01:27:21 +00:00
|
|
|
/* Close everything but stdin/out/err/audio */
|
2004-05-22 00:05:20 +00:00
|
|
|
for (x=STDERR_FILENO+3;x<1024;x++)
|
|
|
|
::close(x);
|
|
|
|
/* Execute script */
|
2004-06-03 22:26:29 +00:00
|
|
|
if (debugAt(DebugInfo))
|
|
|
|
::fprintf(stderr, "Execing '%s' '%s'\n", script, args);
|
2004-05-22 00:05:20 +00:00
|
|
|
::execl(script, script, args, (char *)NULL);
|
|
|
|
::fprintf(stderr, "Failed to execute '%s': %s\n", script, strerror(errno));
|
2004-06-06 00:27:50 +00:00
|
|
|
/* Shit happened. Die as quick and brutal as possible */
|
|
|
|
::_exit(1);
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
Debug(DebugInfo,"Launched External Script %s", script);
|
|
|
|
m_in = ext2yate[0];
|
|
|
|
m_out = yate2ext[1];
|
|
|
|
|
|
|
|
/* close what we're not using in the parent */
|
|
|
|
close(ext2yate[1]);
|
|
|
|
close(yate2ext[0]);
|
|
|
|
m_pid = pid;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2004-09-08 15:54:56 +00:00
|
|
|
void ExtModReceiver::cleanup()
|
|
|
|
{
|
|
|
|
#ifdef DEBUG
|
|
|
|
Debugger debug(DebugAll,"ExtModReceiver::cleanup()"," [%p]",this);
|
|
|
|
#endif
|
|
|
|
/* We must call waitpid from here - same thread we started the child */
|
|
|
|
if (m_pid > 0) {
|
|
|
|
/* No thread switching if possible */
|
|
|
|
if (m_out != -1) {
|
|
|
|
::close(m_out);
|
|
|
|
m_out = -1;
|
|
|
|
}
|
|
|
|
Thread::yield();
|
|
|
|
int w = ::waitpid(m_pid, 0, WNOHANG);
|
|
|
|
if (w == 0) {
|
|
|
|
Debug(DebugWarn, "Process %d has not exited on closing stdin - we'll kill it",m_pid);
|
|
|
|
::kill(m_pid,SIGTERM);
|
|
|
|
Thread::yield();
|
|
|
|
w = ::waitpid(m_pid, 0, WNOHANG);
|
|
|
|
}
|
|
|
|
if (w == 0)
|
|
|
|
Debug(DebugWarn, "Process %d has still not exited yet?",m_pid);
|
|
|
|
else if (w < 0)
|
|
|
|
Debug(DebugMild, "Failed waitpid on %d: %s",m_pid,strerror(errno));
|
|
|
|
m_pid = 0;
|
|
|
|
}
|
2004-09-25 18:22:40 +00:00
|
|
|
unuse();
|
2004-09-08 15:54:56 +00:00
|
|
|
}
|
|
|
|
|
2004-05-22 00:05:20 +00:00
|
|
|
void ExtModReceiver::run()
|
|
|
|
{
|
|
|
|
if (!create(m_script.safe(),m_args.safe())) {
|
2004-09-08 15:54:56 +00:00
|
|
|
m_pid = 0;
|
2004-05-22 00:05:20 +00:00
|
|
|
return;
|
|
|
|
}
|
2004-09-25 18:22:40 +00:00
|
|
|
use();
|
2004-05-22 00:05:20 +00:00
|
|
|
char buffer[1024];
|
|
|
|
int posinbuf = 0;
|
2004-11-29 21:01:04 +00:00
|
|
|
DDebug(DebugAll,"ExtModReceiver::run() entering loop [%p]",this);
|
2004-05-22 00:05:20 +00:00
|
|
|
for (;;) {
|
2004-09-25 18:22:40 +00:00
|
|
|
use();
|
2004-09-08 15:54:56 +00:00
|
|
|
int readsize = (m_in >= 0) ? ::read(m_in,buffer+posinbuf,sizeof(buffer)-posinbuf-1) : 0;
|
2004-11-29 21:01:04 +00:00
|
|
|
DDebug(DebugAll,"ExtModReceiver::run() read %d",readsize);
|
2004-09-25 18:22:40 +00:00
|
|
|
if (unuse())
|
|
|
|
return;
|
2004-05-22 00:05:20 +00:00
|
|
|
if (!readsize) {
|
2004-09-08 15:54:56 +00:00
|
|
|
Debug("ExtModule",DebugInfo,"Read EOF on %d [%p]",m_in,this);
|
|
|
|
if (m_chan && m_chan->running())
|
2004-06-03 22:26:29 +00:00
|
|
|
::usleep(1000000);
|
2004-09-08 15:54:56 +00:00
|
|
|
break;
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
else if (readsize < 0) {
|
2004-09-08 15:54:56 +00:00
|
|
|
Debug("ExtModule",DebugWarn,"Read error %d on %d [%p]",errno,m_in,this);
|
|
|
|
break;
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
int totalsize = readsize + posinbuf;
|
|
|
|
buffer[totalsize]=0;
|
|
|
|
for (;;) {
|
|
|
|
char *eoline = ::strchr(buffer,'\n');
|
|
|
|
if (!eoline && ((int)::strlen(buffer) < totalsize))
|
|
|
|
eoline=buffer+::strlen(buffer);
|
|
|
|
if (!eoline)
|
|
|
|
break;
|
|
|
|
*eoline=0;
|
2004-09-25 18:22:40 +00:00
|
|
|
use();
|
2004-05-22 00:05:20 +00:00
|
|
|
if (buffer[0])
|
|
|
|
processLine(buffer);
|
2004-09-25 18:22:40 +00:00
|
|
|
if (unuse())
|
|
|
|
return;
|
2004-05-22 00:05:20 +00:00
|
|
|
totalsize -= eoline-buffer+1;
|
|
|
|
::memmove(buffer,eoline+1,totalsize+1);
|
|
|
|
}
|
|
|
|
posinbuf = totalsize;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-06-03 22:26:29 +00:00
|
|
|
bool ExtModReceiver::outputLine(const char *line)
|
2004-05-22 00:05:20 +00:00
|
|
|
{
|
2004-11-29 21:01:04 +00:00
|
|
|
DDebug("ExtModReceiver",DebugAll,"outputLine '%s'", line);
|
2004-06-03 22:26:29 +00:00
|
|
|
if (m_out < 0)
|
|
|
|
return false;
|
2004-05-22 00:05:20 +00:00
|
|
|
::write(m_out,line,::strlen(line));
|
|
|
|
char nl = '\n';
|
|
|
|
::write(m_out,&nl,sizeof(nl));
|
2004-06-03 22:26:29 +00:00
|
|
|
return true;
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
|
2004-05-24 00:38:23 +00:00
|
|
|
void ExtModReceiver::reportError(const char *line)
|
|
|
|
{
|
|
|
|
Debug("ExtModReceiver",DebugWarn,"Error: '%s'", line);
|
|
|
|
outputLine("Error in: " + String(line));
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool startSkip(String &s, const char *keyword)
|
|
|
|
{
|
|
|
|
if (s.startsWith(keyword,false)) {
|
|
|
|
s >> keyword;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2004-05-22 00:05:20 +00:00
|
|
|
void ExtModReceiver::processLine(const char *line)
|
|
|
|
{
|
2004-11-29 21:01:04 +00:00
|
|
|
DDebug("ExtModReceiver",DebugAll,"processLine '%s'", line);
|
2004-05-22 00:05:20 +00:00
|
|
|
ObjList *p = &m_waiting;
|
|
|
|
for (; p; p=p->next()) {
|
|
|
|
MsgHolder *msg = static_cast<MsgHolder *>(p->get());
|
|
|
|
if (msg && msg->decode(line)) {
|
2004-11-29 21:01:04 +00:00
|
|
|
DDebug("ExtModReceiver",DebugInfo,"Matched message");
|
2004-05-22 00:05:20 +00:00
|
|
|
p->remove(false);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
2004-05-24 00:38:23 +00:00
|
|
|
String id(line);
|
|
|
|
if (startSkip(id,"%%>install:")) {
|
|
|
|
int prio = 100;
|
|
|
|
id >> prio >> ":";
|
|
|
|
bool ok = true;
|
|
|
|
ObjList *p = &m_relays;
|
|
|
|
for (; p; p=p->next()) {
|
|
|
|
MessageRelay *r = static_cast<MessageRelay *>(p->get());
|
|
|
|
if (r && (*r == id)) {
|
|
|
|
ok = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (ok) {
|
|
|
|
MessageRelay *r = new MessageRelay(id,this,0,prio);
|
|
|
|
m_relays.append(r);
|
|
|
|
Engine::install(r);
|
|
|
|
}
|
|
|
|
Debug("ExtModReceiver",DebugAll,"Install '%s', prio %d %s", id.c_str(),prio,ok ? "ok" : "failed");
|
|
|
|
String out("%%<install:");
|
|
|
|
out << prio << ":" << id << ":" << ok;
|
|
|
|
outputLine(out);
|
2004-05-22 00:05:20 +00:00
|
|
|
return;
|
|
|
|
}
|
2004-05-24 00:38:23 +00:00
|
|
|
else if (startSkip(id,"%%>uninstall:")) {
|
|
|
|
int prio = 0;
|
|
|
|
bool ok = false;
|
|
|
|
ObjList *p = &m_relays;
|
|
|
|
for (; p; p=p->next()) {
|
|
|
|
MessageRelay *r = static_cast<MessageRelay *>(p->get());
|
|
|
|
if (r && (*r == id)) {
|
|
|
|
prio = r->priority();
|
|
|
|
p->remove();
|
|
|
|
ok = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Debug("ExtModReceiver",DebugAll,"Uninstall '%s' %s", id.c_str(),ok ? "ok" : "failed");
|
|
|
|
String out("%%<uninstall:");
|
|
|
|
out << prio << ":" << id << ":" << ok;
|
|
|
|
outputLine(out);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Message m("");
|
|
|
|
if (m.decode(line,id) == -2) {
|
2004-11-29 21:01:04 +00:00
|
|
|
DDebug("ExtModReceiver",DebugAll,"Created message [%p]",this);
|
2004-06-03 22:26:29 +00:00
|
|
|
m.userData(m_chan);
|
2004-09-10 21:53:59 +00:00
|
|
|
/* Copy the user data pointer from waiting message with same id */
|
|
|
|
ObjList *p = &m_waiting;
|
|
|
|
for (; p; p=p->next()) {
|
|
|
|
MsgHolder *h = static_cast<MsgHolder *>(p->get());
|
|
|
|
if (h && (h->m_id == id)) {
|
|
|
|
void *ud = h->m_msg.userData();
|
|
|
|
Debug("ExtModReceiver",DebugAll,"Copying data pointer %p from %p",ud,&(h->m_msg));
|
|
|
|
m.userData(ud);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* Temporary add to the reenter list to avoid reentrance */
|
|
|
|
m_reenter.append(&m)->setDelete(false);
|
2004-05-24 00:38:23 +00:00
|
|
|
outputLine(m.encode(Engine::dispatch(m),id));
|
2004-09-10 21:53:59 +00:00
|
|
|
m_reenter.remove(&m,false);
|
2004-05-24 00:38:23 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
reportError(line);
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
bool ExtModHandler::received(Message &msg)
|
|
|
|
{
|
|
|
|
String dest(msg.getValue("callto"));
|
|
|
|
if (dest.null())
|
|
|
|
return false;
|
2004-06-26 23:10:50 +00:00
|
|
|
Regexp r("^external/\\([^/]*\\)/\\([^ ]*\\)\\(.*\\)$");
|
2004-05-22 00:05:20 +00:00
|
|
|
if (!dest.matches(r))
|
|
|
|
return false;
|
|
|
|
DataEndpoint *dd = static_cast<DataEndpoint *>(msg.userData());
|
|
|
|
String t = dest.matchString(1);
|
|
|
|
int typ = 0;
|
2004-06-03 22:26:29 +00:00
|
|
|
if (t == "nochan")
|
|
|
|
typ = ExtModChan::NoChannel;
|
|
|
|
else if (t == "nodata")
|
2004-05-22 00:05:20 +00:00
|
|
|
typ = ExtModChan::DataNone;
|
2004-06-03 22:26:29 +00:00
|
|
|
else if (t == "play")
|
2004-05-22 00:05:20 +00:00
|
|
|
typ = ExtModChan::DataRead;
|
2004-06-03 22:26:29 +00:00
|
|
|
else if (t == "record")
|
2004-05-22 00:05:20 +00:00
|
|
|
typ = ExtModChan::DataWrite;
|
2004-06-03 22:26:29 +00:00
|
|
|
else if (t == "playrec")
|
2004-05-22 00:05:20 +00:00
|
|
|
typ = ExtModChan::DataBoth;
|
|
|
|
else {
|
2004-10-22 02:45:19 +00:00
|
|
|
Debug(DebugGoOn,"Invalid ExtModule method '%s', use 'nochan', 'nodata', 'play', 'record' or 'playrec'",
|
2004-05-22 00:05:20 +00:00
|
|
|
t.c_str());
|
|
|
|
return false;
|
|
|
|
}
|
2004-06-03 22:26:29 +00:00
|
|
|
if (typ == ExtModChan::NoChannel) {
|
2004-09-08 15:54:56 +00:00
|
|
|
ExtModReceiver *r = ExtModReceiver::build(dest.matchString(2).c_str(),
|
2004-06-26 23:10:50 +00:00
|
|
|
dest.matchString(3).trimBlanks().c_str());
|
2004-09-08 15:54:56 +00:00
|
|
|
return r ? r->received(msg,1) : false;
|
2004-06-03 22:26:29 +00:00
|
|
|
}
|
2004-05-22 00:05:20 +00:00
|
|
|
if (typ != ExtModChan::DataNone && !dd) {
|
2004-09-08 15:54:56 +00:00
|
|
|
Debug(DebugGoOn,"ExtMod '%s' call found but no data channel!",t.c_str());
|
2004-05-22 00:05:20 +00:00
|
|
|
return false;
|
|
|
|
}
|
2004-09-08 15:54:56 +00:00
|
|
|
ExtModChan *em = ExtModChan::build(dest.matchString(2).c_str(),
|
|
|
|
dest.matchString(3).c_str(),typ);
|
2004-05-22 00:05:20 +00:00
|
|
|
if (!em) {
|
2004-09-08 15:54:56 +00:00
|
|
|
Debug(DebugGoOn,"Failed to create ExtMod for '%s'",dest.matchString(2).c_str());
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (!(em->receiver() && em->receiver()->received(msg,1))) {
|
|
|
|
Debug(DebugWarn,"ExtMod '%s' did not handle call message",dest.matchString(2).c_str());
|
|
|
|
em->deref();
|
2004-05-22 00:05:20 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if (dd && dd->connect(em))
|
|
|
|
em->deref();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2004-10-19 22:11:59 +00:00
|
|
|
bool ExtModCommand::received(Message &msg)
|
|
|
|
{
|
|
|
|
String line(msg.getValue("line"));
|
2004-10-20 00:08:15 +00:00
|
|
|
if (!line.startsWith("external",true))
|
2004-10-19 22:11:59 +00:00
|
|
|
return false;
|
2004-10-20 00:08:15 +00:00
|
|
|
line >> "external";
|
2004-10-19 22:11:59 +00:00
|
|
|
line.trimBlanks();
|
2004-10-20 00:08:15 +00:00
|
|
|
if (line.null()) {
|
|
|
|
msg.retValue() = "";
|
|
|
|
ObjList *l = &s_modules;
|
|
|
|
for (; l; l=l->next()) {
|
|
|
|
ExtModReceiver *r = static_cast<ExtModReceiver *>(l->get());
|
|
|
|
if (r)
|
|
|
|
msg.retValue() << r->scriptFile() << " " << r->commandArg() << "\n";
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
2004-10-19 22:11:59 +00:00
|
|
|
int blank = line.find(' ');
|
2004-10-20 00:08:15 +00:00
|
|
|
if (blank <= 0) {
|
|
|
|
if (line == "stop")
|
|
|
|
return false;
|
|
|
|
ExtModReceiver *r = ExtModReceiver::build(line,0);
|
|
|
|
msg.retValue() = r ? "External start attempt\n" : "External command failed!\n";
|
|
|
|
return true;
|
|
|
|
}
|
2004-12-01 14:25:30 +00:00
|
|
|
if (line.startSkip("stop")) {
|
2004-10-20 00:08:15 +00:00
|
|
|
if (line.null())
|
|
|
|
return false;
|
2004-10-19 22:11:59 +00:00
|
|
|
ExtModReceiver *r = ExtModReceiver::find(line);
|
|
|
|
if (r) {
|
|
|
|
r->destruct();
|
2004-10-20 00:08:15 +00:00
|
|
|
msg.retValue() = "External command stopped\n";
|
2004-10-19 22:11:59 +00:00
|
|
|
}
|
2004-10-20 00:08:15 +00:00
|
|
|
else
|
|
|
|
msg.retValue() = "External not running\n";
|
|
|
|
return true;
|
2004-10-19 22:11:59 +00:00
|
|
|
}
|
2004-10-20 00:08:15 +00:00
|
|
|
ExtModReceiver *r = ExtModReceiver::build(line.substr(0,blank),line.substr(blank+1));
|
|
|
|
msg.retValue() = r ? "External start attempt\n" : "External command failed\n";
|
|
|
|
return true;
|
2004-10-19 22:11:59 +00:00
|
|
|
}
|
|
|
|
|
2004-05-22 00:05:20 +00:00
|
|
|
ExtModulePlugin::ExtModulePlugin()
|
|
|
|
: m_handler(0)
|
|
|
|
{
|
|
|
|
Output("Loaded module ExtModule");
|
|
|
|
}
|
|
|
|
|
|
|
|
ExtModulePlugin::~ExtModulePlugin()
|
|
|
|
{
|
|
|
|
Output("Unloading module ExtModule");
|
2004-06-26 23:10:50 +00:00
|
|
|
s_modules.clear();
|
|
|
|
// the receivers destroyed above should also clear chans but better be sure
|
|
|
|
s_chans.clear();
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
|
2004-11-01 00:07:00 +00:00
|
|
|
bool ExtModulePlugin::isBusy() const
|
|
|
|
{
|
|
|
|
return (s_chans.count() != 0);
|
|
|
|
}
|
|
|
|
|
2004-05-22 00:05:20 +00:00
|
|
|
void ExtModulePlugin::initialize()
|
|
|
|
{
|
|
|
|
Output("Initializing module ExtModule");
|
|
|
|
s_cfg = Engine::configFile("extmodule");
|
|
|
|
s_cfg.load();
|
|
|
|
if (!m_handler) {
|
|
|
|
m_handler = new ExtModHandler("call");
|
|
|
|
Engine::install(m_handler);
|
2004-10-19 22:11:59 +00:00
|
|
|
Engine::install(new ExtModCommand("command"));
|
2004-05-22 00:05:20 +00:00
|
|
|
NamedList *list = s_cfg.getSection("scripts");
|
|
|
|
if (list)
|
|
|
|
{
|
|
|
|
unsigned int len = list->length();
|
|
|
|
for (unsigned int i=0; i<len; i++) {
|
|
|
|
NamedString *n = list->getParam(i);
|
2004-09-08 15:54:56 +00:00
|
|
|
if (n)
|
|
|
|
ExtModReceiver::build(n->name(),*n);
|
2004-05-22 00:05:20 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
INIT_PLUGIN(ExtModulePlugin);
|
|
|
|
|
|
|
|
/* vi: set ts=8 sw=4 sts=4 noet: */
|