1#pike __REAL_VERSION__ 2constant __version=0.1; 3constant __author="Marc Dirix <marc@electronics-design.nl"; 4constant __components=({"Public.pmod/Protocols.pmod/Yate.pmod"}); 5 6/* 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License as published by 9 * the Free Software Foundation; either version 2 of the License, or 10 * (at your option) any later version. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. 20 */ 21 22#define YATE_DEBUG 23 24class Engine 25{ 26 static Stdio.FILE yate_socket; 27 28 void create(void|string|object server, void|string role, void|int port) 29 { 30 31 if(server) 32 { 33 if(objectp(server)) 34 yate_socket=server; 35 else if(port) 36 { 37 if(!yate_socket->connect(server, port)) 38 error("Cannot open connection to: %s:%d\n",server,port); 39 } 40 else 41 { 42 if(!yate_socket->connect_unix(server)) 43 error("Cannot open connection to: %s\n",server); 44 } 45 } 46 if(role && sizeof(role)) 47 _yate_print("%%%%>connect:%s\n",role); 48 return; 49 } 50 51 /** 52 * Static function to output astring to Yate's stderr or logfile 53 * only if debugging was enabled. 54 * @param str String to output if yate_debug is set. 55 **/ 56 void debug(string str, mixed ... args) 57 { 58 #ifdef YATE_DEBUG 59 this->output(str, @args); 60 #endif 61 return; 62 } 63 64 /** 65 * Private function to convert a string to its Yate escaped format 66 * @param str String to escape 67 * @return Yate escaped string 68 */ 69 private string _yate_escape(string str) 70 { 71 return replace(str, 72 ({"%" , "\000" , "\001" , "\002" , "\003" , "\004" , "\005" , 73 "\006" , "\007" , "\008" , "\009" , "\010" , "\011" , "\012" , 74 "\013" , "\014" , "\015" , "\016" , "\017" , "\018" , "\019" , 75 "\020" , "\021" , "\022" , "\023" , "\024" , "\025" , "\026" , 76 "\027" , "\028" , "\029" , "\030" , "\031" , "\072" }), 77 ({"%%" , "%\100" , "%\101" , "%\102" , "%\103" , "%\104" , "%\105" , 78 "%\106" , "%\107" , "%\108" , "%\109" , "%\110" , "%\111" , "%\112" , 79 "%\113" , "%\114" , "%\115" , "%\116" , "%\117" , "%\118" , "%\119" , 80 "%\120" , "%\121" , "%\122" , "%\123" , "%\124" , "%\125" , "%\126" , 81 "%\127" , "%\128" , "%\129" , "%\130" , "%\131" , "%\172" })); 82 } 83 84 /** 85 * Static function to convert an Yate escaped string back to string 86 * @param str Yate escaped String 87 * @return unescaped string 88 */ 89 private string _yate_unescape(string str) 90 { 91 string outp=""; 92 for(int a=0 ; a < sizeof(str) ; a++ ) 93 { 94 int c=str[a]; 95 if(c == '%') 96 { 97 a++; 98 c=str[a]; 99 if ( c != '%' ) 100 c = c-64; 101 } 102 outp+=sprintf("%c",c); 103 } 104 return outp; 105 } 106 107 /* 108 * install a Yate message handler 109 * @param name Name of the messages to handle 110 * @param priority (optional) Priority to insert in chain, default 100 111 * @param filtname (optional) Name of parameter to filter for 112 * @param filtvalue (optional) Matching value of filtered parameter 113 */ 114 void install(string name, void|int priority, void|string filter_name, 115 void|string filter_value) 116 { 117 string filter=""; 118 name=_yate_escape(name); 119 if(zero_type(priority)) 120 int priority=100; 121 if(filter_name) 122 filter=":"+_yate_escape(filter_name)+":"+_yate_escape(filter_value||""); 123 _yate_print("%%%%>install:%d:%s:%s\n",priority,name,filter); 124 } 125 126 /* 127 * Uninstall a Yate message handler 128 * @param name Name of the messages to handle 129 */ 130 void uninstall(string name) 131 { 132 name=_yate_escape(name); 133 _yate_print("%%%%>install:%s\n",name); 134 } 135 136 137 /* 138 * Install a Yate message watcher 139 * @param name Name of the messages to watch 140 */ 141 void watch(string name) 142 { 143 name=_yate_escape(name); 144 _yate_print("%%%%>watch:%s\n",name); 145 } 146 147 /* 148 * Uninstall a Yate message watcher 149 * @param name Name of the messages to stop watching 150 */ 151 void unwatch(string name) 152 { 153 name=_yate_escape(name); 154 _yate_print("%%%%>unwatch:%s\n",name); 155 } 156 157 /* 158 * Dispatch the message to Yate for handling 159 * @param message Message object to dispatch 160 */ 161 void dispatch(mapping message) 162 { 163 if(!message->type) 164 message->type="outgoing"; 165 else if(message->type != "outgoing") 166 { 167 output("Pike bug: attempt to dispatch message type: %s\n",message->type); 168 return UNDEFINED; 169 } 170 string paramstring = ""; 171 int origin=time(); 172 if(message->params) 173 paramstring=_yate_mapping2string(message->params); 174 string id; 175 if(!message->id) 176 { 177 random_seed(getpid()); 178 id=(string) random(99999999); 179 } 180 _yate_print("%%%%>message:%s:%d:%s:%s%s\n",_yate_escape(id),origin, 181 _yate_escape(message->name),_yate_escape(message->retval||""), 182 paramstring); 183 } 184 185 186 void acknowledge(mapping message) 187 { 188 if(message->type != "incoming") 189 { 190 output("Pike bug: attempt to acknowledge message type: %s\n",message->type); 191 return; 192 } 193 if(!message->handled) 194 message->handled="false"; 195 string paramstring = ""; 196 if(message->params) 197 paramstring=_yate_mapping2string(message->params); 198 _yate_print("%%%%<message:%s:%s:%s:%s%s\n",_yate_escape(message->id), 199 _yate_escape(message->handled),_yate_escape(message->name), 200 _yate_escape(message->retval||""),paramstring); 201 } 202 203 void setlocal(string name, string value) 204 { 205 _yate_print("%%%%>setlocal:%s:%s\n",_yate_escape(name),_yate_escape(value)); 206 } 207 208 mapping getevent() 209 { 210 string rawmessage; 211 if(yate_socket) 212 { 213 if(!(rawmessage=yate_socket->gets())) 214 return UNDEFINED; 215 } 216 else 217 { 218 if(!(rawmessage=Stdio.stdin->gets())) 219 return UNDEFINED; 220 } 221 rawmessage=replace(rawmessage,"\n",""); 222 if(rawmessage == "") 223 return (["type":"empty"]); 224 array message_parts = rawmessage/":"; 225 mapping message=([]); 226 switch (message_parts[0]) 227 { 228 case "%%>message": 229 /*incoming message str_id:int_time:str_name:str_retval[:key=value...] */ 230 message->ack=0; 231#ifdef YATE_DEBUG 232 message->raw=rawmessage; 233#endif 234 message->type="incoming"; 235 message->id=_yate_unescape(message_parts[1]); 236 message->retval=_yate_unescape(message_parts[4]); 237 message->name=_yate_unescape(message_parts[3]); 238 message->origin=0+(int) message_parts[2]; 239 if(sizeof(message_parts) > 4) 240 message->params=_yate_array2mapping(message_parts[5..]); 241 break; 242 case "%%<message": 243 message->type="answer"; 244 message->id=_yate_unescape(message_parts[1]); 245 message->retval=_yate_unescape(message_parts[4]); 246 message->name=_yate_unescape(message_parts[3]); 247 message->handled=_yate_unescape(message_parts[2]); 248 if(sizeof(message_parts) > 4) 249 message->params=_yate_array2mapping(message_parts[5..]); 250 break; 251 case "%%<install": 252 case "%%<uninstall": 253 /* [un]install answer num_priority:str_name:bool_success */ 254 message->type=message_parts[0][3..]; 255 message->name=_yate_unescape(message_parts[2]); 256 message->handled=_yate_unescape(message_parts[3]); 257 message->priority=(int) message_parts[1]; 258 break; 259 case "%%<watch": 260 case "%%<unwatch": 261 /* [un]watch answer str_name:bool_success */ 262 message->type=message_parts[0][3..]; 263 message->name=_yate_unescape(message_parts[1]); 264 message->handled=_yate_unescape(message_parts[2]); 265 break; 266 case "%%<setlocal": 267 /* local parameter answer str_name:str_value:bool_success */ 268 message->type=message_parts[0][3..]; 269 message->name=_yate_unescape(message_parts[1]); 270 message->retval=_yate_unescape(message_parts[2]); 271 message->handled=_yate_unescape(message_parts[3]); 272 break; 273 case "Error in": 274 message->type="error"; 275 break; 276 default: 277 message->type="error"; 278 output("Unable to decode: %s",rawmessage); 279 } 280 return message; 281 } 282 283 void output(string str, mixed ... args) 284 { 285 if(yate_socket) 286 _yate_print("%%%%>output:"+str+"\n", @args); 287 else 288 Stdio.stderr->write(str+"\n", @args); 289 } 290 291 /* Internal function */ 292 private string _yate_mapping2string(mapping params) 293 { 294 string param=""; 295 foreach(indices(params), string key) 296 { 297 param+=":" + _yate_escape(key) + "=" + _yate_escape(params[key]); 298 } 299 return param; 300 } 301 /* Internal function */ 302 private mapping _yate_array2mapping(array message_params) 303 { 304 mapping params=([]); 305 foreach(message_params, string param) 306 { 307 if(has_value(param,"=")) 308 { 309 array p = param/"="; 310 params+=([_yate_unescape(p[0]):_yate_unescape(p[1])]); 311 } 312 else 313 params+=([_yate_unescape(param):""]); 314 } 315 return params; 316 } 317 /* Internal function */ 318 private void _yate_print(string str, mixed ... args) 319 { 320 if(yate_socket) 321 yate_socket->write(sprintf(str,@args)); 322 else 323 Stdio.stdout->write(sprintf(str,@args)); 324 } 325}; 326 327