00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include <stdio.h>
00021 #include <stdlib.h>
00022 #include <string.h>
00023 #include <unistd.h>
00024 #include <libxml/parser.h>
00025
00026 #include "../../db/db.h"
00027 #include "../../sr_module.h"
00028 #include "../../data_lump_rpl.h"
00029 #include "../../parser/msg_parser.h"
00030 #include "../../parser/parse_content.h"
00031 #include "../../parser/parse_from.h"
00032 #include "../tm/tm_load.h"
00033 #include "../pua/pua_bind.h"
00034 #include "../pua/pidf.h"
00035
00036 #include "purple.h"
00037 #include "purplepipe.h"
00038 #include "miniclient.h"
00039 #include "namespaces.h"
00040
00041 MODULE_VERSION
00042
00043 static int init(void);
00044 static void destroy(void);
00045 static void runprocs(int rank);
00046 static int func_send_message(struct sip_msg* msg);
00047 static int func_handle_publish(struct sip_msg* msg);
00048 static int func_handle_subscribe(struct sip_msg* msg, char* uri, char *expires);
00049 static int fixup_subscribe(void** param, int param_no);
00050
00051 int pipefds[2] = {-1, -1};
00052
00053 db_con_t *pa_db = NULL;
00054 db_func_t pa_dbf;
00055 str db_table = {"purplemap", 0};
00056 str db_url = {DEFAULT_RODB_URL, DEFAULT_RODB_URL_LEN};
00057 str httpProxy_host = {NULL, 0};
00058 int httpProxy_port = 3128;
00059
00060
00061 struct tm_binds tmb;
00062
00063
00064 pua_api_t pua;
00065 send_publish_t pua_send_publish;
00066 send_subscribe_t pua_send_subscribe;
00067 query_dialog_t pua_is_dialog;
00068
00069
00070 xmlNodeGetAttrContentByName_t XMLNodeGetAttrContentByName;
00071 xmlDocGetNodeByName_t XMLDocGetNodeByName;
00072 xmlNodeGetNodeByName_t XMLNodeGetNodeByName;
00073 xmlNodeGetNodeContentByName_t XMLNodeGetNodeContentByName;
00074
00075 static proc_export_t procs[] = {
00076 {"PURPLE Client", 0, 0, runprocs, 1 },
00077 {0, 0, 0, 0, 0}
00078 };
00079
00080 static cmd_export_t cmds[]={
00081 {"purple_send_message", (cmd_function)func_send_message, 0, 0, 0, REQUEST_ROUTE},
00082 {"purple_handle_publish", (cmd_function)func_handle_publish, 0, 0, 0, REQUEST_ROUTE},
00083 {"purple_handle_subscribe", (cmd_function)func_handle_subscribe, 2, fixup_subscribe, 0, REQUEST_ROUTE},
00084 {0, 0, 0, 0, 0, 0}
00085 };
00086
00087 static param_export_t params[]={
00088 {"db_url", STR_PARAM, &db_url.s},
00089 {"db_table", STR_PARAM, &db_table.s},
00090 {"httpProxy_host", STR_PARAM, &httpProxy_host.s},
00091 {"httpProxy_port", INT_PARAM, &httpProxy_port},
00092 {0, 0, 0}
00093 };
00094
00095 struct module_exports exports= {
00096 "purple",
00097 DEFAULT_DLFLAGS,
00098 cmds,
00099 params,
00100 0,
00101 0,
00102 0,
00103 procs,
00104 init,
00105 0,
00106 destroy,
00107 0,
00108 };
00109
00110
00111 static int init(void) {
00112 db_url.len = db_url.s ? strlen(db_url.s) : 0;
00113 db_table.len = db_table.s ? strlen(db_table.s) : 0;
00114 httpProxy_host.len = httpProxy_host.s ? strlen(httpProxy_host.s) : 0;
00115
00116 LM_DBG("db_url=%s/%d/%p\n", ZSW(db_url.s), db_url.len,db_url.s);
00117 load_tm_f load_tm;
00118 bind_pua_t bind_pua;
00119 bind_libxml_t bind_libxml;
00120 libxml_api_t libxml_api;
00121
00122 LM_DBG("initializing...\n");
00123
00124
00125 if (db_bind_mod(&db_url, &pa_dbf)) {
00126 LM_ERR("Database module not found\n");
00127 return -1;
00128 }
00129
00130 pa_db = pa_dbf.init(&db_url);
00131 if (!pa_db) {
00132 LM_ERR("connecting database\n");
00133 return -1;
00134 }
00135
00136 if (pa_dbf.use_table(pa_db, &db_table) < 0) {
00137 LM_ERR("in use_table\n");
00138 return -1;
00139 }
00140
00141 if (pa_db && pa_dbf.close)
00142 pa_dbf.close(pa_db);
00143
00144
00145
00146 if((load_tm=(load_tm_f)find_export("load_tm", 0, 0))==NULL) {
00147 LM_ERR("can't import load_tm\n");
00148 return -1;
00149 }
00150
00151
00152 if(load_tm(&tmb)==-1) {
00153 LM_ERR("can't load tm functions\n");
00154 return -1;
00155 }
00156
00157
00158 if((bind_libxml= (bind_libxml_t)find_export("bind_libxml_api", 1, 0))== NULL) {
00159 LM_ERR("can't import bind_libxml_api\n");
00160 return -1;
00161 }
00162 if(bind_libxml(&libxml_api)< 0) {
00163 LM_ERR("can not bind libxml api\n");
00164 return -1;
00165 }
00166
00167 XMLNodeGetAttrContentByName= libxml_api.xmlNodeGetAttrContentByName;
00168 XMLDocGetNodeByName= libxml_api.xmlDocGetNodeByName;
00169 XMLNodeGetNodeByName= libxml_api.xmlNodeGetNodeByName;
00170 XMLNodeGetNodeContentByName= libxml_api.xmlNodeGetNodeContentByName;
00171
00172 if(XMLNodeGetAttrContentByName== NULL || XMLDocGetNodeByName== NULL ||
00173 XMLNodeGetNodeByName== NULL || XMLNodeGetNodeContentByName== NULL)
00174 {
00175 LM_ERR("libxml wrapper functions could not be bound\n");
00176 return -1;
00177 }
00178
00179
00180 bind_pua= (bind_pua_t)find_export("bind_pua", 1,0);
00181 if (!bind_pua) {
00182 LM_ERR("Can't bind pua\n");
00183 return -1;
00184 }
00185
00186 if (bind_pua(&pua) < 0) {
00187 LM_ERR("Can't bind pua\n");
00188 return -1;
00189 }
00190 if(pua.send_publish == NULL) {
00191 LM_ERR("Could not import send_publish\n");
00192 return -1;
00193 }
00194 pua_send_publish= pua.send_publish;
00195
00196 if(pua.send_subscribe == NULL) {
00197 LM_ERR("Could not import send_subscribe\n");
00198 return -1;
00199 }
00200 pua_send_subscribe= pua.send_subscribe;
00201
00202 if(pua.is_dialog == NULL) {
00203 LM_ERR("Could not import send_subscribe\n");
00204 return -1;
00205 }
00206 pua_is_dialog= pua.is_dialog;
00207
00208
00209
00210
00211
00212
00213
00214 if (pipe(pipefds) < 0) {
00215 LM_ERR("pipe() failed\n");
00216 return -1;
00217 }
00218
00219 return 0;
00220 }
00221
00222 static void destroy(void) {
00223 LM_DBG("cleaning up...\n");
00224 close(pipefds[0]);
00225 }
00226
00227 static void runprocs(int rank) {
00228 LM_DBG("initializing child process with PID %d\n", (int) getpid());
00229 close(pipefds[1]);
00230
00231 miniclient_start(pipefds[0]);
00232 }
00233
00234
00235 static int func_send_message(struct sip_msg* msg) {
00236 str body, from_uri, dst, tagid;
00237 int mime;
00238
00239 LM_DBG("handling MESSAGE\n");
00240
00241
00242 if (!(body.s = get_body(msg))) {
00243 LM_ERR("failed to extract body\n");
00244 return -1;
00245 }
00246 if (!msg->content_length) {
00247 LM_ERR("no content-length found\n");
00248 return -1;
00249 }
00250 body.len = get_content_length(msg);
00251 if ((mime = parse_content_type_hdr(msg)) < 1) {
00252 LM_ERR("failed parse content-type\n");
00253 return -1;
00254 }
00255
00256 if ((mime >> 16) != TYPE_TEXT) {
00257 LM_ERR("invalid content-type 0x%x\n", mime);
00258 return -1;
00259 }
00260
00261
00262 if (parse_headers(msg, HDR_TO_F | HDR_FROM_F, 0) == -1 || !msg->to || !msg->from) {
00263 LM_ERR("no To/From headers\n");
00264 return -1;
00265 }
00266 if (parse_from_header(msg) < 0 || !msg->from->parsed) {
00267 LM_ERR("failed to parse From header\n");
00268 return -1;
00269 }
00270 from_uri = ((struct to_body *) msg->from->parsed)->uri;
00271 tagid = ((struct to_body *) msg->from->parsed)->tag_value;
00272 LM_DBG("message from <%.*s>\n", from_uri.len, from_uri.s);
00273
00274
00275 dst.len = 0;
00276 if (msg->new_uri.len > 0) {
00277 LM_DBG("using new URI as destination\n");
00278 dst = msg->new_uri;
00279 } else if (msg->first_line.u.request.uri.s
00280 && msg->first_line.u.request.uri.len > 0) {
00281 LM_DBG("using R-URI as destination\n");
00282 dst = msg->first_line.u.request.uri;
00283 } else if (msg->to->parsed) {
00284 LM_DBG("using TO-URI as destination\n");
00285 dst = ((struct to_body *) msg->to->parsed)->uri;
00286 } else {
00287 LM_ERR("failed to find a valid destination\n");
00288 return -1;
00289 }
00290
00291 if (purple_send_message_cmd(&from_uri, &dst, &body, &tagid) < 0) {
00292 LM_ERR("error sending message cmd via pipe\n");
00293 return -1;
00294 }
00295 else
00296 LM_DBG("message parsed and sent to pipe successfully\n");
00297 return 1;
00298 }
00299
00300 static int func_handle_publish(struct sip_msg* msg) {
00301 str body, from_uri, tagid, note;
00302 enum purple_publish_basic basic;
00303 PurpleStatusPrimitive primitive;
00304 xmlDocPtr sip_doc= NULL;
00305 xmlNodePtr sip_root= NULL;
00306 xmlNodePtr node = NULL;
00307 char* basicstr= NULL, *notestr, notebuff[512];
00308 int mime;
00309 note.s = notebuff;
00310 note.len = 0;
00311 notebuff[0] = 0;
00312
00313 LM_DBG("handling PUBLISH\n");
00314
00315
00316 if (!(body.s = get_body(msg))) {
00317 LM_ERR("failed to extract body\n");
00318 return -1;
00319 }
00320 if (!msg->content_length) {
00321 LM_ERR("no content-length found\n");
00322 return -1;
00323 }
00324 body.len = get_content_length(msg);
00325 mime = parse_content_type_hdr(msg);
00326
00327
00328 if (parse_headers(msg, HDR_TO_F | HDR_FROM_F, 0) == -1 || !msg->to || !msg->from) {
00329 LM_ERR("no To/From headers\n");
00330 return -1;
00331 }
00332 if (parse_from_header(msg) < 0 || !msg->from->parsed) {
00333 LM_ERR("failed to parse From header\n");
00334 return -1;
00335 }
00336 from_uri = ((struct to_body *) msg->from->parsed)->uri;
00337 tagid = ((struct to_body *) msg->from->parsed)->tag_value;
00338 LM_DBG("publish from <%.*s>\n", from_uri.len, from_uri.s);
00339
00340 if (mime == 0) {
00341 LM_DBG("no content-type\n");
00342 basic = PURPLE_BASIC_CLOSED;
00343 primitive = PURPLE_STATUS_OFFLINE;
00344 if (purple_send_publish_cmd(basic, primitive, &from_uri, &tagid, ¬e) < 0) {
00345 LM_ERR("error sending publish cmd via pipe\n");
00346 return -1;
00347 }
00348 LM_DBG("message parsed and sent to pipe successfully\n");
00349 return 1;
00350 }
00351
00352
00353 sip_doc= xmlParseMemory(body.s, body.len);
00354 if(sip_doc== NULL) {
00355 LM_ERR("while parsing xml memory\n");
00356 return -1;
00357 }
00358 sip_root= XMLDocGetNodeByName(sip_doc, "presence", NULL);
00359 if(sip_root== NULL) {
00360 LM_ERR("while extracting 'presence' node\n");
00361 goto error;
00362 }
00363
00364 node = XMLNodeGetNodeByName(sip_root, "basic", NULL);
00365 if(node== NULL) {
00366 LM_ERR("while extracting status basic node\n");
00367 goto error;
00368 }
00369 basicstr= (char*)xmlNodeGetContent(node);
00370 if(basicstr== NULL) {
00371 LM_ERR("while extracting status basic node content\n");
00372 goto error;
00373 }
00374 if(xmlStrcasecmp( (unsigned char*)basicstr,(unsigned char*) "closed")==0 ) {
00375 basic = PURPLE_BASIC_CLOSED;
00376 primitive = PURPLE_STATUS_OFFLINE;
00377 }
00378 else {
00379 basic = PURPLE_BASIC_OPEN;
00380 primitive = PURPLE_STATUS_AVAILABLE;
00381 }
00382
00383 node = NULL;
00384 node = XMLNodeGetNodeByName(sip_root, "note", "dm");
00385 if (node) {
00386 notestr = (char*) xmlNodeGetContent(node);
00387 if (notestr) {
00388 LM_DBG("found <dm:note>%s</dm:node>\n", notestr);
00389 if (xmlStrcasecmp((unsigned char*)notestr, (unsigned char*) "Busy")==0)
00390 primitive = PURPLE_STATUS_UNAVAILABLE;
00391 else if (xmlStrcasecmp((unsigned char*)notestr, (unsigned char*) "On the Phone")==0) {
00392 primitive = PURPLE_STATUS_UNAVAILABLE;
00393 note.len = sprintf(note.s, "On the Phone");
00394 }
00395 else if (xmlStrcasecmp((unsigned char*)notestr, (unsigned char*) "Away")==0)
00396 primitive = PURPLE_STATUS_AWAY;
00397 else if (xmlStrcasecmp((unsigned char*)notestr, (unsigned char*) "Idle")==0) {
00398 primitive = PURPLE_STATUS_AVAILABLE;
00399 note.len = sprintf(note.s, "Idle");
00400 }
00401 else
00402 note.len = sprintf(note.s, notestr);
00403 }
00404 }
00405
00406 node = NULL;
00407 node = XMLNodeGetNodeByName(sip_root, "user-input", "rpid");
00408 if (node) {
00409 notestr = (char*) xmlNodeGetContent(node);
00410 if (notestr) {
00411 LM_DBG("found <rpid:user-input>%s</rpid:user-input>\n", notestr);
00412 note.len = sprintf(note.s, "%s", notestr);
00413 }
00414 }
00415
00416 if (purple_send_publish_cmd(basic, primitive, &from_uri, &tagid, ¬e) < 0) {
00417 LM_ERR("error sending publish cmd via pipe\n");
00418 return -1;
00419 }
00420 LM_DBG("message parsed and sent to pipe successfully\n");
00421 return 1;
00422
00423 error:
00424 if(sip_doc)
00425 xmlFreeDoc(sip_doc);
00426 xmlCleanupParser();
00427 xmlMemoryDump();
00428
00429 return -1;
00430
00431 }
00432
00433 static int func_handle_subscribe(struct sip_msg* msg, char* uri, char* expires) {
00434 str from, to;
00435 int iexpires = -1;
00436 char ruri_buff[512], expires_buff[512];
00437 int ruri_len = 511, expires_len = 511;
00438
00439 if (pv_printf(msg, (pv_elem_t*)uri, ruri_buff, &ruri_len) < 0) {
00440 LM_ERR("cannot print ruri into the format\n");
00441 return -1;
00442 }
00443
00444 if (pv_printf(msg, (pv_elem_t*)expires, expires_buff, &expires_len) < 0) {
00445 LM_ERR("cannot print expires into the format\n");
00446 return -1;
00447 }
00448
00449 iexpires = atoi(expires_buff);
00450
00451
00452 LM_DBG("handling SUBSCRIBE %s (%s)\n", ruri_buff, expires_buff);
00453 if (parse_headers(msg, HDR_TO_F | HDR_FROM_F, 0) == -1 || !msg->to || !msg->from) {
00454 LM_ERR("no To/From headers\n");
00455 return -1;
00456 }
00457 if (parse_from_header(msg) < 0 || !msg->from->parsed) {
00458 LM_ERR("failed to parse From header\n");
00459 return -1;
00460 }
00461 from.len = 0;
00462 from = ((struct to_body *) msg->from->parsed)->uri;
00463
00464
00465 to.len = 0;
00466
00467
00468
00469
00470
00471
00472
00473
00474
00475 if (msg->to->parsed) {
00476 LM_DBG("using TO-URI as destination\n");
00477 to = ((struct to_body *) msg->to->parsed)->uri;
00478 } else {
00479 LM_ERR("failed to find a valid destination\n");
00480 return -1;
00481 }
00482
00483 if (purple_send_subscribe_cmd(&from, &to, iexpires) < 0) {
00484 LM_ERR("error sending subscribe cmd via pipe\n");
00485 return -1;
00486 }
00487 LM_DBG("subscribe parsed and sent to pipe successfully\n");
00488 return 1;
00489 }
00490
00491 static int fixup_subscribe(void** param, int param_no) {
00492 pv_elem_t *model;
00493 str s;
00494 if(*param) {
00495 s.s = (char*)(*param); s.len = strlen(s.s);
00496 if(pv_parse_format(&s, &model)<0) {
00497 LM_ERR("wrong format[%s]\n",(char*)(*param));
00498 return E_UNSPEC;
00499 }
00500 *param = (void*)model;
00501 return 1;
00502 }
00503 LM_ERR("null format\n");
00504 return E_UNSPEC;
00505 }
00506