1 /*
2  * Copyright (C) 2008 iptego GmbH
3  *
4  * This file is part of SEMS, a free SIP media server.
5  *
6  * SEMS is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version. This program is released under
10  * the GPL with the additional exemption that compiling, linking,
11  * and/or using OpenSSL is allowed.
12  *
13  * For a license to use the SEMS software under conditions
14  * other than those described here, or to purchase support for this
15  * software, please contact iptel.org by e-mail at the following addresses:
16  *    info@iptel.org
17  *
18  * SEMS is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26  */
27 #ifndef _DSM_MODULE_H
28 #define _DSM_MODULE_H
29 #include "DSMStateEngine.h"
30 #include "AmSipMsg.h"
31 #include "AmArg.h"
32 #include "AmSession.h"
33 
34 class DSMSession;
35 
36 #include <string>
37 using std::string;
38 
39 #include <typeinfo>
40 
41 // script modules interface
42 // factory only: it produces actions and conditions from script statements.
43 class DSMModule {
44 
45  public:
46   DSMModule();
47   virtual ~DSMModule();
48 
49   virtual DSMAction* getAction(const string& from_str) = 0;
50   virtual DSMCondition* getCondition(const string& from_str) = 0;
51 
preload()52   virtual int preload() { return 0; }
onInvite(const AmSipRequest & req,DSMSession * sess)53   virtual bool onInvite(const AmSipRequest& req, DSMSession* sess) { return true; }
onBeforeDestroy(DSMSession * sc_sess,AmSession * sess)54   virtual void onBeforeDestroy(DSMSession* sc_sess, AmSession* sess) { }
processSdpOffer(AmSdp & offer)55   virtual void processSdpOffer(AmSdp& offer) { }
processSdpAnswer(const AmSdp & offer,AmSdp & answer)56   virtual void processSdpAnswer(const AmSdp& offer, AmSdp& answer) { }
57 };
58 
59 typedef map<string,string> EventParamT;
60 
61 typedef void* (*SCFactoryCreate)();
62 
63 #define SCSTR(x) #x
64 #define SCXSTR(x) SCSTR(x)
65 
66 #define SC_FACTORY_EXPORT      sc_factory_create
67 #define SC_FACTORY_EXPORT_STR  SCXSTR(SC_FACTORY_EXPORT)
68 
69 #if  __GNUC__ < 3
70 #define EXPORT_SC_FACTORY(fctname,class_name,args...)	\
71   extern "C" void* fctname()				\
72   {							\
73     return new class_name(##args);			\
74   }
75 #else
76 #define EXPORT_SC_FACTORY(fctname,class_name,...)	\
77   extern "C" void* fctname()				\
78   {							\
79     return new class_name(__VA_ARGS__);			\
80   }
81 #endif
82 
83 #define SC_EXPORT(class_name)			\
84   EXPORT_SC_FACTORY(SC_FACTORY_EXPORT,class_name)
85 
86 class SCStrArgAction
87 : public DSMAction {
88  protected:
89   string arg;
90  public:
91   SCStrArgAction(const string& m_arg);
92 };
93 
94 #define DEF_ACTION_1P(CL_Name)						\
95   class CL_Name								\
96   : public SCStrArgAction {						\
97   public:								\
98   CL_Name(const string& arg) : SCStrArgAction(arg) { }			\
99     bool execute(AmSession* sess, DSMSession* sc_sess,			\
100 		 DSMCondition::EventType event,				\
101 		 map<string,string>* event_params);			\
102   };									\
103 
104 
105 #define DEF_SCModSEStrArgAction(CL_Name)				\
106   class CL_Name								\
107   : public SCStrArgAction {						\
108     bool is_evaluated;							\
109   public:								\
110   CL_Name(const string& arg) : SCStrArgAction(arg),			\
111       is_evaluated(false) { }						\
112     bool execute(AmSession* sess, DSMSession* sc_sess,			\
113 		 DSMCondition::EventType event,				\
114 		 map<string,string>* event_params);			\
115     SEAction getSEAction(std::string&,					\
116 			 AmSession* sess, DSMSession* sc_sess,		\
117 			 DSMCondition::EventType event,			\
118 			 map<string,string>* event_params);		\
119   };									\
120 
121 #define DEF_ACTION_2P(CL_Name)						\
122   class CL_Name								\
123   : public DSMAction {							\
124     string par1;							\
125     string par2;							\
126   public:								\
127     CL_Name(const string& arg);						\
128     bool execute(AmSession* sess, DSMSession* sc_sess,			\
129 		 DSMCondition::EventType event,				\
130 		 map<string,string>* event_params);			\
131   };									\
132 
133 /* bool xsplit(const string& arg, char sep, bool optional, string& par1, string& par2); */
134 
135 #define SPLIT_ARGS(sep, optional)					\
136     size_t p = 0;							\
137     char last_c = ' ';							\
138     bool quot=false;							\
139     char quot_c = ' ';							\
140     bool sep_found = false;						\
141     while (p<arg.size()) {						\
142       if (quot) {							\
143 	if (last_c != '\\' && arg[p]==quot_c)				\
144 	  quot=false;							\
145       } else {								\
146 	if (last_c != '\\'  && (arg[p]=='\'' || arg[p]=='\"')) {	\
147 	  quot = true;							\
148 	  quot_c = arg[p];						\
149 	} else {							\
150 	  if (arg[p] == sep) {						\
151 	    sep_found = true;						\
152 	    break;							\
153 	  }								\
154 	}								\
155       }									\
156       p++;								\
157       last_c = arg[p];							\
158     }									\
159 									\
160     if ((!optional) && (!sep_found)) {					\
161       ERROR("expected two parameters separated with '%c' in expression '%s' for %s\n", \
162 	    sep,arg.c_str(),typeid(this).name());			\
163       return;								\
164     }									\
165 									\
166     par1 = trim(arg.substr(0,p), " \t");				\
167     if (sep_found) 							\
168       par2 = trim(arg.substr(p+1), " \t");				\
169 									\
170     if (par1.length() && par1[0]=='\'') {				\
171       par1 = trim(par1, "\'");						\
172       size_t rpos = 0;							\
173       while ((rpos=par1.find("\\\'")) != string::npos)			\
174 	par1.erase(rpos, 1);						\
175     } else if (par1.length() && par1[0]=='\"') {			\
176       par1 = trim(par1, "\"");						\
177       size_t rpos = 0;							\
178       while ((rpos=par1.find("\\\"")) != string::npos)			\
179 	par1.erase(rpos, 1);						\
180     }									\
181 									\
182     if (par2.length() && par2[0]=='\'') {				\
183       par2 = trim(par2, "\'");						\
184       size_t rpos = 0;							\
185       while ((rpos=par2.find("\\\'")) != string::npos)			\
186 	par2.erase(rpos, 1);						\
187     } else if (par2.length() && par2[0]=='\"') {			\
188       par2 = trim(par2, "\"");						\
189       size_t rpos = 0;							\
190       while ((rpos=par2.find("\\\"")) != string::npos)			\
191 	par2.erase(rpos, 1);						\
192     }									\
193 									\
194     if ((!optional) && ((par1.empty())||(par2.empty()))) {		\
195       ERROR("expected two parameters separated with '%c' in expression '%s' for %s\n", \
196 	    sep,arg.c_str(),typeid(this).name());			\
197       return;								\
198     }
199 
200 
201 #define CONST_ACTION_2P(CL_name, _sep, _optional)			\
202   CL_name::CL_name(const string& arg) {					\
203     SPLIT_ARGS(_sep, _optional);					\
204   }
205 
206 
207 #define EXEC_ACTION_START(act_name)					\
208   bool act_name::execute(AmSession* sess, DSMSession* sc_sess,		\
209 			 DSMCondition::EventType event,			\
210 			 map<string,string>* event_params) {
211 
212 
213 #define EXEC_ACTION_END				\
214   return false;					\
215   }
216 
217 #define EXEC_ACTION_STOP			\
218   return false;
219 
220 string resolveVars(const string s, AmSession* sess,
221 		   DSMSession* sc_sess, map<string,string>* event_params,
222 		   bool eval_ops = false);
223 
224 void splitCmd(const string& from_str,
225 		string& cmd, string& params);
226 
227 
228 #define DEF_CMD(cmd_name, class_name) \
229 				      \
230   if (cmd == cmd_name) {	      \
231     class_name * a =		      \
232       new class_name(params);	      \
233     a->name = from_str;		      \
234     return a;			      \
235   }
236 
237 #define DEF_SCCondition(cond_name)		\
238   class cond_name				\
239   : public DSMCondition {			\
240     string arg;					\
241     bool inv;					\
242     						\
243   public:					\
244     						\
245   cond_name(const string& arg, bool inv)				\
246     : arg(arg), inv(inv) { }						\
247     bool match(AmSession* sess, DSMSession* sc_sess, DSMCondition::EventType event, \
248 	       map<string,string>* event_params);			\
249   };
250 
251 #define DEF_CONDITION_2P(cond_name)					\
252   class cond_name							\
253   : public DSMCondition {						\
254     string par1;							\
255     string par2;							\
256     bool inv;								\
257   public:								\
258     cond_name(const string& arg, bool inv);				\
259     bool match(AmSession* sess, DSMSession* sc_sess, DSMCondition::EventType event, \
260 	       map<string,string>* event_params);			\
261   };
262 
263 #define CONST_CONDITION_2P(cond_name, _sep, _optional)			\
264   cond_name::cond_name(const string& arg, bool inv)			\
265   : inv(inv) {								\
266     SPLIT_ARGS(_sep, _optional);					\
267   }
268 
269 #define MATCH_CONDITION_START(cond_clsname)				\
270   bool cond_clsname::match(AmSession* sess, DSMSession* sc_sess,	\
271 			   DSMCondition::EventType event,		\
272 			   map<string,string>* event_params) {
273 
274 #define MATCH_CONDITION_END }
275 
276 #define DECLARE_MODULE(mod_cls_name)			\
277   class mod_cls_name					\
278   : public DSMModule {					\
279 							\
280   public:						\
281     mod_cls_name() { }					\
282  ~mod_cls_name() { }					\
283 							\
284  DSMAction* getAction(const string& from_str);		\
285  DSMCondition* getCondition(const string& from_str);	\
286 };
287 
288 #define DECLARE_MODULE_BEGIN(mod_cls_name)		\
289   class mod_cls_name					\
290   : public DSMModule {					\
291 							\
292   public:						\
293     mod_cls_name() { }					\
294  ~mod_cls_name() { }					\
295 							\
296  DSMAction* getAction(const string& from_str);		\
297  DSMCondition* getCondition(const string& from_str);
298 
299 
300 
301 #define DECLARE_MODULE_END \
302   }
303 
304 #define MOD_ACTIONEXPORT_BEGIN(mod_cls_name)				\
305   DSMAction* mod_cls_name::getAction(const string& from_str) {		\
306   string cmd;								\
307   string params;							\
308   splitCmd(from_str, cmd, params);
309 
310 #define MOD_ACTIONEXPORT_END			\
311   return NULL;					\
312   }
313 
314 #define MOD_CONDITIONEXPORT_NONE(mod_cls_name)				\
315   DSMCondition* mod_cls_name::getCondition(const string& from_str) {	\
316     return NULL;							\
317   }
318 
319 
320 #define MOD_CONDITIONEXPORT_BEGIN(mod_cls_name)				\
321   DSMCondition* mod_cls_name::getCondition(const string& from_str) {	\
322   string cmd;								\
323   string params;							\
324   splitCmd(from_str, cmd, params);
325 
326 #define MOD_CONDITIONEXPORT_END \
327   return NULL;			\
328   }				\
329 
330 
331 #endif
332