purple.c

Go to the documentation of this file.
00001 /* OpenSER PURPLE MODULE
00002  * 
00003  * Copyright (C) 2008 Atos Worldline
00004  * Contact: Eric PTAK <eric.ptak@atosorigin.com>
00005  *
00006  * This program is free software: you can redistribute it and/or modify
00007  * it under the terms of the GNU General Public License as published by
00008  * the Free Software Foundation, either version 2 of the License, or
00009  * (at your option) any later version.
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
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 /* TM functions */
00061 struct tm_binds tmb;
00062 
00063 /* functions imported from pua module*/
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 /* libxml imported functions */
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",        /* module's name */
00097         DEFAULT_DLFLAGS, /* dlopen flags */
00098         cmds,            /* exported functions */
00099         params,          /* module parameters */
00100         0,               /* exported statistics */
00101         0,               /* exported MI functions */
00102         0,               /* exported pseudo-variables */
00103         procs,           /* extra processes */
00104         init,            /* module initialization function */
00105         0,               /* response function */
00106         destroy,         /* destroy function */
00107    0,               /* per-child init function */
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    /* import DB stuff */
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    /* import the TM auto-loading function */
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    /* let the auto-loading function load all TM stuff */
00151 
00152    if(load_tm(&tmb)==-1) {
00153       LM_ERR("can't load tm functions\n");
00154       return -1;
00155    }
00156 
00157    /* bind libxml wrapper functions */
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    /* bind pua */
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 // if(pua.register_puacb(PURPLE_PUBLISH, publish_reply_handler, NULL)< 0) {
00209 //    LM_ERR("Could not register callback\n");
00210 //    return -1;
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    /* extract body */
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    //if (mime != (TYPE_TEXT << 16) + SUBTYPE_PLAIN && mime != (TYPE_MESSAGE << 16) + SUBTYPE_CPIM) {
00256    if ((mime >> 16) != TYPE_TEXT) {
00257       LM_ERR("invalid content-type 0x%x\n", mime);
00258       return -1;
00259    }
00260 
00261    /* extract sender */
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    /* extract recipient */
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    /* extract body */
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    /* extract sender */
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, &note) < 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    /*extractiong the information from the sip message body*/
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    }/* else the status is open so no type attr should be added */
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, &note) < 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    /* extract sender */
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    /* extract recipient */
00465    to.len = 0;
00466    /*
00467    if (msg->new_uri.len > 0) {
00468       LM_DBG("using new URI as destination\n");
00469       to = msg->new_uri;
00470    } else if (msg->first_line.u.request.uri.s 
00471          && msg->first_line.u.request.uri.len > 0) {
00472       LM_DBG("using R-URI as destination\n");
00473       to = msg->first_line.u.request.uri;
00474    } else */
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 

Generated on Thu May 24 08:00:53 2012 for Kamailio - The Open Source SIP Server by  doxygen 1.5.6