t_mi.c

Go to the documentation of this file.
00001 /*
00002  * $Id: mi.c 5299 2008-12-04 18:12:33Z henningw $
00003  *
00004  * Header file for TM MI functions
00005  *
00006  * Copyright (C) 2001-2003 FhG Fokus
00007  * Copyright (C) 2006 Voice Sistem SRL
00008  *
00009  * This file is part of Kamailio, a free SIP server.
00010  *
00011  * Kamailio is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License as published by
00013  * the Free Software Foundation; either version 2 of the License, or
00014  * (at your option) any later version
00015  *
00016  * Kamailio is distributed in the hope that it will be useful,
00017  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019  * GNU General Public License for more details.
00020  *
00021  * You should have received a copy of the GNU General Public License 
00022  * along with this program; if not, write to the Free Software 
00023  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00024  *
00025  * History:
00026  * --------
00027  *  2006-12-04  created (bogdan)
00028  */
00029 
00037 #include <stdlib.h>
00038 #include "../../parser/parse_from.h"
00039 #include "../../modules/tm/ut.h"
00040 #include "../../lib/kmi/mi.h"
00041 #include "../../str_list.h"
00042 #include "tmx_mod.h"
00043 
00044 
00045 
00055 static inline int uri2su(str *uri, union sockaddr_union *to_su, int proto)
00056 {
00057         struct proxy_l *proxy;
00058 
00059         proxy = uri2proxy(uri, proto);
00060         if (!proxy) {
00061                 ser_error = E_BAD_ADDRESS;
00062                 LM_ERR("failed create a dst proxy\n");
00063                 return -1;
00064         }
00065 
00066         hostent2su(to_su, &proxy->host, proxy->addr_idx, 
00067                 (proxy->port) ? proxy->port : SIP_PORT);
00068         proto = proxy->proto;
00069 
00070         free_proxy(proxy);
00071         pkg_free(proxy);
00072         return proto;
00073 }
00074 
00075 /* should be replaced by tm's uri2dst instead */
00076 static inline struct socket_info *uri2sock(struct sip_msg* msg, str *uri,
00077                                                                         union sockaddr_union *to_su, int proto)
00078 {
00079         struct socket_info* send_sock;
00080 
00081         if ( (proto=uri2su(uri, to_su, proto))==-1 )
00082                 return 0;
00083 
00084         send_sock = get_send_socket(msg, to_su, proto);
00085         if (!send_sock) {
00086                 LM_ERR("no corresponding socket for af %d\n", to_su->s.sa_family);
00087                 ser_error = E_NO_SOCKET;
00088         }
00089 
00090         return send_sock;
00091 }
00092 
00093 
00094 /************** Helper functions (from previous FIFO impl) *****************/
00095 
00109 static inline struct mi_root* mi_check_msg(struct sip_msg* msg, str* method,
00110                                                                                 str* body, int* cseq, str* callid)
00111 {
00112         struct cseq_body *parsed_cseq;
00113 
00114         if (body && body->len && !msg->content_type)
00115                 return init_mi_tree( 400, "Content-Type missing", 19);
00116 
00117         if (body && body->len && msg->content_length)
00118                 return init_mi_tree( 400, "Content-Length disallowed", 24);
00119 
00120         if (!msg->to)
00121                 return init_mi_tree( 400, "To missing", 10);
00122 
00123         if (!msg->from)
00124                 return init_mi_tree( 400, "From missing", 12);
00125 
00126         /* we also need to know if there is from-tag and add it otherwise */
00127         if (parse_from_header(msg) < 0)
00128                 return init_mi_tree( 400, "Error in From", 13);
00129 
00130         if (msg->cseq && (parsed_cseq = get_cseq(msg))) {
00131                 if (str2int( &parsed_cseq->number, (unsigned int*)cseq)!=0)
00132                         return init_mi_tree( 400, "Bad CSeq number", 15);
00133 
00134                 if (parsed_cseq->method.len != method->len
00135                 || memcmp(parsed_cseq->method.s, method->s, method->len) !=0 )
00136                         return init_mi_tree( 400, "CSeq method mismatch", 20);
00137         } else {
00138                 *cseq = -1;
00139         }
00140 
00141         if (msg->callid) {
00142                 callid->s = msg->callid->body.s;
00143                 callid->len = msg->callid->body.len;
00144         } else {
00145                 callid->s = 0;
00146                 callid->len = 0;
00147         }
00148 
00149         return 0;
00150 }
00151 
00152 
00164 static inline char *get_hfblock( str *uri, struct hdr_field *hf, int *l, struct socket_info** send_sock)
00165 {
00166         struct str_list sl, *last, *new, *i, *foo;
00167         int hf_avail, frag_len, total_len;
00168         char *begin, *needle, *dst, *ret, *d;
00169         str *sock_name, *portname;
00170         union sockaddr_union to_su;
00171 
00172         ret=0; /* pessimist: assume failure */
00173         total_len=0;
00174         last=&sl;
00175         last->next=0;
00176         portname=sock_name=0;
00177 
00178         for (; hf; hf=hf->next) {
00179                 if (tm_skip_hf(hf)) continue;
00180 
00181                 begin=needle=hf->name.s; 
00182                 hf_avail=hf->len;
00183 
00184                 /* substitution loop */
00185                 while(hf_avail) {
00186                         d=memchr(needle, SUBST_CHAR, hf_avail);
00187                         if (!d || d+1>=needle+hf_avail) { /* nothing to substitute */
00188                                 new=append_str_list(begin, hf_avail, &last, &total_len); 
00189                                 if (!new) goto error;
00190                                 break;
00191                         } else {
00192                                 frag_len=d-begin;
00193                                 d++; /* d not at the second substitution char */
00194                                 switch(*d) {
00195                                         case SUBST_CHAR:        /* double SUBST_CHAR: IP */
00196                                                 /* string before substitute */
00197                                                 new=append_str_list(begin, frag_len, &last, &total_len); 
00198                                                 if (!new) goto error;
00199                                                 /* substitute */
00200                                                 if (!sock_name) {
00201                                                         if (*send_sock==0){
00202                                                                 *send_sock=uri2sock(0, uri, &to_su,PROTO_NONE);
00203                                                                 if (!*send_sock) {
00204                                                                         LM_ERR("send_sock failed\n");
00205                                                                         goto error;
00206                                                                 }
00207                                                         }
00208                                                         sock_name=&(*send_sock)->address_str;
00209                                                         portname=&(*send_sock)->port_no_str;
00210                                                 }
00211                                                 new=append_str_list(sock_name->s, sock_name->len,
00212                                                                 &last, &total_len );
00213                                                 if (!new) goto error;
00214                                                 /* inefficient - FIXME --andrei*/
00215                                                 new=append_str_list(":", 1, &last, &total_len);
00216                                                 if (!new) goto error;
00217                                                 new=append_str_list(portname->s, portname->len,
00218                                                                 &last, &total_len );
00219                                                 if (!new) goto error;
00220                                                 /* keep going ... */
00221                                                 begin=needle=d+1;hf_avail-=frag_len+2;
00222                                                 continue;
00223                                         default:
00224                                                 /* no valid substitution char -- keep going */
00225                                                 hf_avail-=frag_len+1;
00226                                                 needle=d;
00227                                 }
00228                         } /* possible substitute */
00229                 } /* substitution loop */
00230                 /* proceed to next header */
00231                 /* new=append_str_list(CRLF, CRLF_LEN, &last, &total_len );
00232                 if (!new) goto error; */
00233                 LM_DBG("one more hf processed\n");
00234         } /* header loop */
00235 
00236 
00237         /* construct a single header block now */
00238         ret=pkg_malloc(total_len);
00239         if (!ret) {
00240                 LM_ERR("no pkg mem for hf block\n");
00241                 goto error;
00242         }
00243         i=sl.next;
00244         dst=ret;
00245         while(i) {
00246                 foo=i;
00247                 i=i->next;
00248                 memcpy(dst, foo->s.s, foo->s.len);
00249                 dst+=foo->s.len;
00250                 pkg_free(foo);
00251         }
00252         *l=total_len;
00253         return ret;
00254 
00255 error:
00256         i=sl.next;
00257         while(i) {
00258                 foo=i;
00259                 i=i->next;
00260                 pkg_free(foo);
00261         }
00262         *l=0;
00263         return 0;
00264 }
00265 
00266 
00274 static inline void mi_print_routes( struct mi_node *node, dlg_t* dlg)
00275 {
00276 #define MI_ROUTE_PREFIX_S       "Route: "
00277 #define MI_ROUTE_PREFIX_LEN     (sizeof(MI_ROUTE_PREFIX_S)-1)
00278 #define MI_ROUTE_SEPARATOR_S    ", "
00279 #define MI_ROUTE_SEPARATOR_LEN  (sizeof(MI_ROUTE_SEPARATOR_S)-1)
00280         rr_t* ptr;
00281         int len;
00282         char *p, *s;
00283 
00284         ptr = dlg->hooks.first_route;
00285 
00286         if (ptr==NULL) {
00287                 add_mi_node_child( node, 0, 0, 0, ".",1);
00288                 return;
00289         }
00290 
00291         len = MI_ROUTE_PREFIX_LEN;
00292         for( ; ptr ; ptr=ptr->next)
00293                 len += ptr->len + MI_ROUTE_SEPARATOR_LEN*(ptr->next!=NULL);
00294         if (dlg->hooks.last_route)
00295                 len += dlg->hooks.last_route->len + 2;
00296 
00297 
00298         s = pkg_malloc( len );
00299         if (s==0) {
00300                 LM_ERR("no more pkg mem\n");
00301                 return;
00302         }
00303 
00304 
00305         p = s;
00306         memcpy( p, MI_ROUTE_PREFIX_S, MI_ROUTE_PREFIX_LEN);
00307         p += MI_ROUTE_PREFIX_LEN;
00308 
00309         for( ptr = dlg->hooks.first_route ; ptr ; ptr=ptr->next) {
00310                 memcpy( p, ptr->nameaddr.name.s, ptr->len);
00311                 p += ptr->len;
00312                 if (ptr->next) {
00313                         memcpy( p, MI_ROUTE_SEPARATOR_S, MI_ROUTE_SEPARATOR_LEN);
00314                         p += MI_ROUTE_SEPARATOR_LEN;
00315                 }
00316         }
00317 
00318         if (dlg->hooks.last_route) {
00319                 *(p++) = '<';
00320                 memcpy( p, dlg->hooks.last_route->s, dlg->hooks.last_route->len);
00321                 p += dlg->hooks.last_route->len;
00322                 *(p++) = '>';
00323         }
00324 
00325         add_mi_node_child( node, MI_DUP_VALUE, 0, 0, s, len);
00326         pkg_free(s);
00327 }
00328 
00329 
00338 static inline int mi_print_uris( struct mi_node *node, struct sip_msg* reply)
00339 {
00340         dlg_t* dlg;
00341 
00342         if (reply==0)
00343                 goto empty;
00344 
00345         dlg = (dlg_t*)shm_malloc(sizeof(dlg_t));
00346         if (!dlg) {
00347                 LM_ERR("no shm memory left\n");
00348                 return -1;
00349         }
00350 
00351         memset(dlg, 0, sizeof(dlg_t));
00352         if (_tmx_tmb.dlg_response_uac(dlg, reply, TARGET_REFRESH_UNKNOWN) < 0) {
00353                 LM_ERR("failed to create dialog\n");
00354                 _tmx_tmb.free_dlg(dlg);
00355                 return -1;
00356         }
00357 
00358         if (dlg->state != DLG_CONFIRMED) {
00359                 _tmx_tmb.free_dlg(dlg);
00360                 goto empty;
00361         }
00362 
00363         if (dlg->hooks.request_uri->s) {
00364                 add_mi_node_child( node, MI_DUP_VALUE, 0, 0,
00365                         dlg->hooks.request_uri->s, dlg->hooks.request_uri->len);
00366         } else {
00367                 add_mi_node_child( node, 0, 0, 0, ".",1);
00368         }
00369         if (dlg->hooks.next_hop->s) {
00370                 add_mi_node_child( node, MI_DUP_VALUE, 0, 0,
00371                         dlg->hooks.next_hop->s, dlg->hooks.next_hop->len);
00372         } else {
00373                 add_mi_node_child( node, 0, 0, 0, ".",1);
00374         }
00375 
00376         mi_print_routes( node, dlg);
00377 
00378         _tmx_tmb.free_dlg(dlg);
00379         return 0;
00380 empty:
00381         add_mi_node_child( node, 0, 0, 0, ".",1);
00382         add_mi_node_child( node, 0, 0, 0, ".",1);
00383         add_mi_node_child( node, 0, 0, 0, ".",1);
00384         return 0;
00385 }
00386 
00387 
00388 static void mi_uac_dlg_hdl( struct cell *t, int type, struct tmcb_params *ps )
00389 {
00390         struct mi_handler *mi_hdl;
00391         struct mi_root *rpl_tree;
00392         str text;
00393 
00394         LM_DBG("MI UAC generated status %d\n", ps->code);
00395         if (!*ps->param)
00396                 return;
00397 
00398         mi_hdl = (struct mi_handler *)(*ps->param);
00399 
00400         rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00401         if (rpl_tree==0)
00402                 goto done;
00403 
00404         if (ps->rpl==FAKED_REPLY) {
00405                 get_reply_status( &text, ps->rpl, ps->code);
00406                 if (text.s==0) {
00407                         LM_ERR("get_reply_status failed\n");
00408                         rpl_tree = 0;
00409                         goto done;
00410                 }
00411                 add_mi_node_child( &rpl_tree->node, MI_DUP_VALUE, 0, 0,
00412                         text.s, text.len);
00413                 pkg_free(text.s);
00414                 mi_print_uris( &rpl_tree->node, 0 );
00415                 add_mi_node_child( &rpl_tree->node, 0, 0, 0, ".",1);
00416         } else { 
00417                 addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "%d %.*s",
00418                         ps->rpl->first_line.u.reply.statuscode,
00419                         ps->rpl->first_line.u.reply.reason.len,
00420                         ps->rpl->first_line.u.reply.reason.s);
00421                 mi_print_uris( &rpl_tree->node, ps->rpl);
00422                 add_mi_node_child( &rpl_tree->node, MI_DUP_VALUE, 0, 0,
00423                         ps->rpl->headers->name.s,
00424                         ps->rpl->len-(ps->rpl->headers->name.s - ps->rpl->buf));
00425         }
00426 
00427         LM_DBG("mi_callback successfully completed\n");
00428 done:
00429         if (ps->code >= 200) {
00430                 mi_hdl->handler_f( rpl_tree, mi_hdl, 1 /*done*/ );
00431                 *ps->param = 0;
00432         } else {
00433                 mi_hdl->handler_f( rpl_tree, mi_hdl, 0 );
00434         }
00435 }
00436 
00437 
00438 
00439 /**************************** MI functions ********************************/
00440 
00441 
00442 /*
00443   Syntax of "t_uac_dlg" :
00444     method
00445     RURI
00446     NEXT_HOP
00447     socket
00448     headers
00449     [Body]
00450 */
00451 struct mi_root*  mi_tm_uac_dlg(struct mi_root* cmd_tree, void* param)
00452 {
00453         static char err_buf[MAX_REASON_LEN];
00454         static struct sip_msg tmp_msg;
00455         static dlg_t dlg;
00456         struct mi_root *rpl_tree;
00457         struct mi_node *node;
00458         struct sip_uri pruri;
00459         struct sip_uri pnexthop;
00460         struct socket_info* sock;
00461         str *method;
00462         str *ruri;
00463         str *nexthop;
00464         str *socket;
00465         str *hdrs;
00466         str *body;
00467         str s;
00468         str callid = {0,0};
00469         int sip_error;
00470         int proto;
00471         int port;
00472         int cseq;
00473         int n;
00474         uac_req_t uac_r;
00475 
00476         for( n=0,node = cmd_tree->node.kids; n<6 && node ; n++,node=node->next );
00477         if ( !(n==5 || n==6) || node!=0)
00478                 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00479 
00480         cseq = -1;
00481 
00482         /* method name (param 1) */
00483         node = cmd_tree->node.kids;
00484         method = &node->value;
00485 
00486         /* RURI (param 2) */
00487         node = node->next;
00488         ruri = &node->value;
00489         if (parse_uri( ruri->s, ruri->len, &pruri) < 0 )
00490                 return init_mi_tree( 400, "Invalid RURI", 12);
00491 
00492         /* nexthop RURI (param 3) */
00493         node = node->next;
00494         nexthop = &node->value;
00495         if (nexthop->len==1 && nexthop->s[0]=='.') {
00496                 nexthop = 0;
00497         } else {
00498                 if (parse_uri( nexthop->s, nexthop->len, &pnexthop) < 0 )
00499                         return init_mi_tree( 400, "Invalid NEXTHOP", 15);
00500         }
00501 
00502         /* socket (param 4) */
00503         node = node->next;
00504         socket = &node->value;
00505         if (socket->len==1 && socket->s[0]=='.' ) {
00506                 sock = 0;
00507         } else {
00508                 if (parse_phostport( socket->s, &s.s, &s.len,
00509                 &port,&proto)!=0)
00510                         return init_mi_tree( 404, "Invalid local socket", 20);
00511                 sock = grep_sock_info( &s, (unsigned short)port, proto);
00512                 if (sock==0)
00513                         return init_mi_tree( 404, "Local socket not found", 22);
00514         }
00515 
00516         /* new headers (param 5) */
00517         node = node->next;
00518         if (node->value.len==1 && node->value.s[0]=='.')
00519                 hdrs = 0;
00520         else {
00521                 hdrs = &node->value;
00522                 /* use SIP parser to look at what is in the FIFO request */
00523                 memset( &tmp_msg, 0, sizeof(struct sip_msg));
00524                 tmp_msg.len = hdrs->len; 
00525                 tmp_msg.buf = tmp_msg.unparsed = hdrs->s;
00526                 if (parse_headers( &tmp_msg, HDR_EOH_F, 0) == -1 )
00527                         return init_mi_tree( 400, "Bad headers", 11);
00528         }
00529 
00530         /* body (param 5 - optional) */
00531         node = node->next;
00532         if (node)
00533                 body = &node->value;
00534         else
00535                 body = 0;
00536 
00537         /* at this moment, we collected all the things we got, let's
00538          * verify user has not forgotten something */
00539         rpl_tree = mi_check_msg( &tmp_msg, method, body, &cseq, &callid);
00540         if (rpl_tree) {
00541                 if (tmp_msg.headers) free_hdr_field_lst(tmp_msg.headers);
00542                 return rpl_tree;
00543         }
00544 
00545         s.s = get_hfblock( nexthop ? nexthop : ruri,
00546                         tmp_msg.headers, &s.len, &sock);
00547         if (s.s==0) {
00548                 if (tmp_msg.headers) free_hdr_field_lst(tmp_msg.headers);
00549                 return 0;
00550         }
00551 
00552         memset( &dlg, 0, sizeof(dlg_t));
00553         /* Fill in Call-ID, use given Call-ID if
00554          * present and generate it if not present */
00555         if (callid.s && callid.len)
00556                 dlg.id.call_id = callid;
00557         else
00558                 _tmx_tmb.generate_callid(&dlg.id.call_id);
00559 
00560         /* We will not fill in dlg->id.rem_tag because
00561          * if present it will be printed within To HF */
00562 
00563         /* Generate fromtag if not present */
00564         if (!(get_from(&tmp_msg)->tag_value.len&&get_from(&tmp_msg)->tag_value.s))
00565                 _tmx_tmb.generate_fromtag(&dlg.id.loc_tag, &dlg.id.call_id);
00566 
00567         /* Fill in CSeq */
00568         if (cseq!=-1)
00569                 dlg.loc_seq.value = cseq;
00570         else
00571                 dlg.loc_seq.value = DEFAULT_CSEQ;
00572         dlg.loc_seq.is_set = 1;
00573 
00574         dlg.loc_uri = tmp_msg.from->body;
00575         dlg.rem_uri = tmp_msg.to->body;
00576         dlg.rem_target = *ruri;
00577         if (nexthop)
00578                 dlg.dst_uri = *nexthop;
00579         dlg.send_sock = sock;
00580 
00581         memset(&uac_r, 0, sizeof(uac_req_t));
00582         uac_r.method = method;
00583         uac_r.body = body;
00584         uac_r.headers = &s;
00585         uac_r.dialog = &dlg;
00586         if (cmd_tree->async_hdl!=NULL)
00587         {
00588                 uac_r.cb = mi_uac_dlg_hdl;
00589                 uac_r.cbp = (void*)cmd_tree->async_hdl;
00590                 uac_r.cb_flags = TMCB_LOCAL_COMPLETED;
00591         }
00592         n = _tmx_tmb.t_uac(&uac_r);
00593 
00594         pkg_free(s.s);
00595         if (tmp_msg.headers) free_hdr_field_lst(tmp_msg.headers);
00596 
00597         if (n<=0) {
00598                 /* error */
00599                 rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00600                 if (rpl_tree==0)
00601                         return 0;
00602 
00603                 n = err2reason_phrase( n, &sip_error, err_buf, sizeof(err_buf),
00604                         "MI/UAC") ;
00605                 if (n > 0 )
00606                         addf_mi_node_child( &rpl_tree->node, 0, 0, 0, "%d %.*s",
00607                                 sip_error, n, err_buf);
00608                 else
00609                         add_mi_node_child( &rpl_tree->node, 0, 0, 0,
00610                                 "500 MI/UAC failed", 17);
00611 
00612                 return rpl_tree;
00613         } else {
00614                 if (cmd_tree->async_hdl==NULL)
00615                         return init_mi_tree( 202, "Accepted", 8);
00616                 else
00617                         return MI_ROOT_ASYNC_RPL;
00618         }
00619 }
00620 
00621 
00622 /*
00623   Syntax of "t_uac_cancel" :
00624     callid
00625     cseq
00626 */
00627 struct mi_root* mi_tm_cancel(struct mi_root* cmd_tree, void* param)
00628 {
00629         struct cancel_info cancel_data;
00630         struct mi_node *node;
00631         struct cell *trans;
00632 
00633         node =  cmd_tree->node.kids;
00634         if ( !node || !node->next || node->next->next)
00635                 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00636 
00637         if( _tmx_tmb.t_lookup_callid( &trans, node->value, node->next->value) < 0 )
00638                 return init_mi_tree( 481, "No such transaction", 19);
00639 
00640         /* cancel the call */
00641         LM_DBG("cancelling transaction %p\n",trans);
00642 
00643         init_cancel_info(&cancel_data);
00644         cancel_data.cancel_bitmap = ~0; /*all branches*/
00645         _tmx_tmb.cancel_uacs(trans, &cancel_data, 0);
00646 
00647         _tmx_tmb.unref_cell(trans);
00648 
00649         return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00650 }
00651 
00652 
00653 /*
00654   Syntax of "t_hash" :
00655     no nodes
00656 */
00657 struct mi_root* mi_tm_hash(struct mi_root* cmd_tree, void* param)
00658 {
00659 #ifndef TM_HASH_STATS
00660         return init_mi_tree( 500, "No TM hash stats", 16);
00661 #else
00662         struct mi_root* rpl_tree= NULL;
00663         struct mi_node* rpl;
00664         struct mi_node* node;
00665         struct mi_attr* attr;
00666         struct s_table* tm_t;
00667         char *p;
00668         int i;
00669         int len;
00670 
00671         rpl_tree = init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00672         if (rpl_tree==0)
00673                 return 0;
00674         rpl = &rpl_tree->node;
00675         tm_t = _tmx_tmb.get_table();
00676 
00677         for (i=0; i<TABLE_ENTRIES; i++) {
00678                 if(tm_t->entries[i].cur_entries==0
00679                                 && tm_t->entries[i].acc_entries==0)
00680                         continue;
00681 
00682                 p = int2str((unsigned long)i, &len );
00683                 node = add_mi_node_child(rpl, MI_DUP_VALUE , 0, 0, p, len);
00684                 if(node == NULL)
00685                         goto error;
00686 
00687                 p = int2str((unsigned long)tm_t->entries[i].cur_entries, &len );
00688                 attr = add_mi_attr(node, MI_DUP_VALUE, "Current", 7, p, len );
00689                 if(attr == NULL)
00690                         goto error;
00691 
00692                 p = int2str((unsigned long)tm_t->entries[i].acc_entries, &len );
00693                 attr = add_mi_attr(node, MI_DUP_VALUE, "Total", 5, p, len );
00694                 if(attr == NULL)
00695                         goto error;
00696         }
00697 
00698         return rpl_tree;
00699 error:
00700         free_mi_tree(rpl_tree);
00701         return init_mi_tree( 500, MI_INTERNAL_ERR_S, MI_INTERNAL_ERR_LEN);
00702 #endif
00703 }
00704 
00705 
00706 /*
00707   Syntax of "t_reply" :
00708   code
00709   reason
00710   trans_id
00711   to_tag
00712   new headers
00713   [Body]
00714 */
00715 struct mi_root* mi_tm_reply(struct mi_root* cmd_tree, void* param)
00716 {
00717         struct mi_node* node;
00718         unsigned int hash_index;
00719         unsigned int hash_label;
00720         unsigned int rpl_code;
00721         struct cell *trans;
00722         str reason = {0, 0};
00723         str totag = {0, 0};
00724         str new_hdrs = {0, 0};
00725         str body = {0, 0};
00726         str tmp = {0, 0};
00727         char *p;
00728         int n;
00729 
00730         for( n=0,node = cmd_tree->node.kids; n<6 && node ; n++,node=node->next );
00731         if ( !(n==5 || n==6) || node!=0)
00732                 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00733 
00734         /* get all info from the command */
00735 
00736         /* reply code (param 1) */
00737         node = cmd_tree->node.kids;
00738         if (str2int( &node->value, &rpl_code)!=0 || rpl_code>=700)
00739                 return init_mi_tree( 400, "Invalid reply code", 18);
00740 
00741         /* reason text (param 2) */
00742         node = node->next;
00743         reason = node->value;
00744 
00745         /* trans_id (param 3) */
00746         node = node->next;
00747         tmp = node->value;
00748         p = memchr( tmp.s, ':', tmp.len);
00749         if(p==NULL)
00750                 return init_mi_tree( 400, "Invalid trans_id", 16);
00751 
00752         tmp.len = p-tmp.s;
00753         if(str2int(&tmp, &hash_index)!=0)
00754                 return init_mi_tree( 400, "Invalid index in trans_id", 25);
00755 
00756         tmp.s = p+1;
00757         tmp.len = (node->value.s+node->value.len) - tmp.s;
00758         if(str2int(&tmp, &hash_label)!=0)
00759                 return init_mi_tree( 400, "Invalid label in trans_id", 25);
00760 
00761         if(_tmx_tmb.t_lookup_ident( &trans, hash_index, hash_label)<0)
00762                 return init_mi_tree( 404, "Transaction not found", 21);
00763 
00764         /* to_tag (param 4) */
00765         node = node->next;
00766         totag = node->value;
00767 
00768         /* new headers (param 5) */
00769         node = node->next;
00770         if (!(node->value.len==1 && node->value.s[0]=='.'))
00771                 new_hdrs = node->value;
00772 
00773         /* body (param 5 - optional) */
00774         node = node->next;
00775         if (node)
00776                 body = node->value;
00777 
00778         /* it's refcounted now, t_reply_with body unrefs for me -- I can 
00779          * continue but may not use T anymore  */
00780         n = _tmx_tmb.t_reply_with_body(trans, rpl_code, &reason, &body,
00781                         &new_hdrs, &totag);
00782 
00783         if (n<0)
00784                 return init_mi_tree( 500, "Reply failed", 12);
00785 
00786         return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00787 }
00788 
00789 /*
00790   Syntax of "t_reply_callid" :
00791   code
00792   reason
00793   callid
00794   cseq
00795   to_tag
00796   new headers
00797   [Body]
00798 */
00799 struct mi_root* mi_tm_reply_callid(struct mi_root* cmd_tree, void* param)
00800 {
00801         struct mi_node* node;
00802         unsigned int rpl_code;
00803         struct cell *trans;
00804         str reason = {0, 0};
00805         str totag = {0, 0};
00806         str new_hdrs = {0, 0};
00807         str body = {0, 0};
00808         str callid = {0, 0};
00809         str cseq = {0, 0};
00810         int n;
00811 
00812         for( n=0,node = cmd_tree->node.kids; n<7 && node ; n++,node=node->next );
00813         if ( !(n==6 || n==7) || node!=0)
00814                 return init_mi_tree( 400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN);
00815 
00816         /* get all info from the command */
00817 
00818         /* reply code (param 1) */
00819         node = cmd_tree->node.kids;
00820         if (str2int( &node->value, &rpl_code)!=0 || rpl_code>=700)
00821                 return init_mi_tree( 400, "Invalid reply code", 18);
00822 
00823         /* reason text (param 2) */
00824         node = node->next;
00825         reason = node->value;
00826 
00827         /* callid (param 3) */
00828         node = node->next;
00829         callid = node->value;
00830 
00831         /* cseq (param 4) */
00832         node = node->next;
00833         cseq = node->value;
00834 
00835         if(_tmx_tmb.t_lookup_callid( &trans, callid, cseq) < 0 )
00836                 return init_mi_tree( 400, "Lookup failed - no transaction", 30);
00837 
00838         /* to_tag (param 5) */
00839         node = node->next;
00840         totag = node->value;
00841 
00842         /* new headers (param 6) */
00843         node = node->next;
00844         if (!(node->value.len==1 && node->value.s[0]=='.'))
00845                 new_hdrs = node->value;
00846 
00847         /* body (param 7 - optional) */
00848         node = node->next;
00849         if (node)
00850                 body = node->value;
00851 
00852         /* it's refcounted now, t_reply_with body unrefs for me -- I can
00853          * continue but may not use T anymore  */
00854         n = _tmx_tmb.t_reply_with_body(trans, rpl_code, &reason, &body,
00855                         &new_hdrs, &totag);
00856 
00857         if (n<0)
00858                 return init_mi_tree( 500, "Reply failed", 12);
00859 
00860         return init_mi_tree( 200, MI_OK_S, MI_OK_LEN);
00861 }
00862