dlg_profile.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865
  1. /*
  2. * $Id$
  3. *
  4. * Copyright (C) 2008 Voice System SRL
  5. *
  6. * This file is part of Kamailio, a free SIP server.
  7. *
  8. * Kamailio is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation; either version 2 of the License, or
  11. * (at your option) any later version
  12. *
  13. * Kamailio is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. * GNU General Public License for more details.
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program; if not, write to the Free Software
  20. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  21. *
  22. * History:
  23. * --------
  24. * 2008-04-20 initial version (bogdan)
  25. *
  26. */
  27. /*!
  28. * \file
  29. * \brief Profile related functions for the dialog module
  30. * \ingroup dialog
  31. * Module: \ref dialog
  32. */
  33. #include "../../mem/shm_mem.h"
  34. #include "../../dprint.h"
  35. #include "../../ut.h"
  36. #include "../../route.h"
  37. #include "../../modules/tm/tm_load.h"
  38. #include "../../trim.h"
  39. #include "dlg_hash.h"
  40. #include "dlg_handlers.h"
  41. #include "dlg_profile.h"
  42. /*! size of dialog profile hash */
  43. #define PROFILE_HASH_SIZE 16
  44. /*! tm bindings */
  45. extern struct tm_binds d_tmb;
  46. /*! global dialog message id */
  47. static unsigned int current_dlg_msg_id = 0 ;
  48. /*! global dialog */
  49. struct dlg_cell *current_dlg_pointer = NULL ;
  50. /*! pending dialog links */
  51. static struct dlg_profile_link *current_pending_linkers = NULL;
  52. /*! global dialog profile list */
  53. static struct dlg_profile_table *profiles = NULL;
  54. static struct dlg_profile_table* new_dlg_profile( str *name,
  55. unsigned int size, unsigned int has_value);
  56. struct dlg_cell *get_current_dlg_pointer(void)
  57. {
  58. return current_dlg_pointer;
  59. }
  60. void reset_current_dlg_pointer(void)
  61. {
  62. current_dlg_pointer = NULL;
  63. }
  64. /*!
  65. * \brief Add profile definitions to the global list
  66. * \see new_dlg_profile
  67. * \param profiles profile name
  68. * \param has_value set to 0 for a profile without value, otherwise it has a value
  69. * \return 0 on success, -1 on failure
  70. */
  71. int add_profile_definitions( char* profiles, unsigned int has_value)
  72. {
  73. char *p;
  74. char *d;
  75. str name;
  76. unsigned int i;
  77. if (profiles==NULL || strlen(profiles)==0 )
  78. return 0;
  79. p = profiles;
  80. do {
  81. /* locate name of profile */
  82. name.s = p;
  83. d = strchr( p, ';');
  84. if (d) {
  85. name.len = d-p;
  86. d++;
  87. } else {
  88. name.len = strlen(p);
  89. }
  90. /* we have the name -> trim it for spaces */
  91. trim_spaces_lr( name );
  92. /* check len name */
  93. if (name.len==0)
  94. /* ignore */
  95. continue;
  96. /* check the name format */
  97. for(i=0;i<name.len;i++) {
  98. if ( !isalnum(name.s[i]) ) {
  99. LM_ERR("bad profile name <%.*s>, char %c - use only "
  100. "alphanumerical characters\n", name.len,name.s,name.s[i]);
  101. return -1;
  102. }
  103. }
  104. /* name ok -> create the profile */
  105. LM_DBG("creating profile <%.*s>\n",name.len,name.s);
  106. if (new_dlg_profile( &name, PROFILE_HASH_SIZE, has_value)==NULL) {
  107. LM_ERR("failed to create new profile <%.*s>\n",name.len,name.s);
  108. return -1;
  109. }
  110. }while( (p=d)!=NULL );
  111. return 0;
  112. }
  113. /*!
  114. * \brief Search a dialog profile in the global list
  115. * \note Linear search, this won't have the best performance for huge profile lists
  116. * \param name searched dialog profile
  117. * \return pointer to the profile on success, NULL otherwise
  118. */
  119. struct dlg_profile_table* search_dlg_profile(str *name)
  120. {
  121. struct dlg_profile_table *profile;
  122. for( profile=profiles ; profile ; profile=profile->next ) {
  123. if (name->len==profile->name.len &&
  124. memcmp(name->s,profile->name.s,name->len)==0 )
  125. return profile;
  126. }
  127. return NULL;
  128. }
  129. /*!
  130. * \brief Creates a new dialog profile
  131. * \see add_profile_definitions
  132. * \param name profile name
  133. * \param size profile size
  134. * \param has_value set to 0 for a profile without value, otherwise it has a value
  135. * \return pointer to the created dialog on success, NULL otherwise
  136. */
  137. static struct dlg_profile_table* new_dlg_profile( str *name, unsigned int size,
  138. unsigned int has_value)
  139. {
  140. struct dlg_profile_table *profile;
  141. struct dlg_profile_table *ptmp;
  142. unsigned int len;
  143. unsigned int i;
  144. if ( name->s==NULL || name->len==0 || size==0 ) {
  145. LM_ERR("invalid parameters\n");
  146. return NULL;
  147. }
  148. for( len=0,i=0 ; i<8*sizeof(size) ; i++ ) {
  149. if ( size & (1<<i) ) len++;
  150. }
  151. if (len!=1) {
  152. LM_ERR(" size %u is not power of 2!\n", size);
  153. return NULL;
  154. }
  155. profile = search_dlg_profile(name);
  156. if (profile!=NULL) {
  157. LM_ERR("duplicate dialog profile registered <%.*s>\n",
  158. name->len, name->s);
  159. return NULL;
  160. }
  161. len = sizeof(struct dlg_profile_table) +
  162. size*sizeof(struct dlg_profile_entry) +
  163. name->len + 1;
  164. profile = (struct dlg_profile_table *)shm_malloc(len);
  165. if (profile==NULL) {
  166. LM_ERR("no more shm mem\n");
  167. return NULL;
  168. }
  169. memset( profile , 0 , len);
  170. profile->size = size;
  171. profile->has_value = (has_value==0)?0:1;
  172. /* init lock */
  173. if (lock_init( &profile->lock )==NULL) {
  174. LM_ERR("failed to init lock\n");
  175. shm_free(profile);
  176. return NULL;
  177. }
  178. /* set inner pointers */
  179. profile->entries = (struct dlg_profile_entry*)(profile + 1);
  180. profile->name.s = ((char*)profile->entries) +
  181. size*sizeof(struct dlg_profile_entry);
  182. /* copy the name of the profile */
  183. memcpy( profile->name.s, name->s, name->len );
  184. profile->name.len = name->len;
  185. profile->name.s[profile->name.len] = 0;
  186. /* link profile */
  187. for( ptmp=profiles ; ptmp && ptmp->next; ptmp=ptmp->next );
  188. if (ptmp==NULL)
  189. profiles = profile;
  190. else
  191. ptmp->next = profile;
  192. return profile;
  193. }
  194. /*!
  195. * \brief Destroy a dialog profile list
  196. * \param profile dialog profile
  197. */
  198. static void destroy_dlg_profile(struct dlg_profile_table *profile)
  199. {
  200. if (profile==NULL)
  201. return;
  202. lock_destroy( &profile->lock );
  203. shm_free( profile );
  204. return;
  205. }
  206. /*!
  207. * \brief Destroy the global dialog profile list
  208. */
  209. void destroy_dlg_profiles(void)
  210. {
  211. struct dlg_profile_table *profile;
  212. while(profiles) {
  213. profile = profiles;
  214. profiles = profiles->next;
  215. destroy_dlg_profile( profile );
  216. }
  217. return;
  218. }
  219. /*!
  220. * \brief Destroy dialog linkers
  221. * \param linker dialog linker
  222. */
  223. void destroy_linkers(struct dlg_profile_link *linker)
  224. {
  225. struct dlg_profile_entry *p_entry;
  226. struct dlg_profile_link *l;
  227. struct dlg_profile_hash *lh;
  228. while(linker) {
  229. l = linker;
  230. linker = linker->next;
  231. /* unlink from profile table */
  232. if (l->hash_linker.next) {
  233. p_entry = &l->profile->entries[l->hash_linker.hash];
  234. lock_get( &l->profile->lock );
  235. lh = &l->hash_linker;
  236. /* last element on the list? */
  237. if (lh==lh->next) {
  238. p_entry->first = NULL;
  239. } else {
  240. if (p_entry->first==lh)
  241. p_entry->first = lh->next;
  242. lh->next->prev = lh->prev;
  243. lh->prev->next = lh->next;
  244. }
  245. lh->next = lh->prev = NULL;
  246. p_entry->content --;
  247. lock_release( &l->profile->lock );
  248. }
  249. /* free memory */
  250. shm_free(l);
  251. }
  252. }
  253. /*!
  254. * \brief Cleanup a profile
  255. * \param msg SIP message
  256. * \param flags unused
  257. * \param unused
  258. * \return 1
  259. */
  260. int profile_cleanup( struct sip_msg *msg, unsigned int flags, void *param )
  261. {
  262. current_dlg_msg_id = 0;
  263. if (current_dlg_pointer) {
  264. unref_dlg( current_dlg_pointer, 1);
  265. current_dlg_pointer = NULL;
  266. }
  267. if (current_pending_linkers) {
  268. destroy_linkers(current_pending_linkers);
  269. current_pending_linkers = NULL;
  270. }
  271. /* need to return non-zero - 0 will break the exec of the request */
  272. return 1;
  273. }
  274. struct dlg_cell* get_dialog_from_tm(struct cell *t)
  275. {
  276. if (t==NULL || t==T_UNDEFINED)
  277. return NULL;
  278. struct tm_callback* x = (struct tm_callback*)(t->tmcb_hl.first);
  279. while(x){
  280. membar_depends();
  281. if (x->types==TMCB_MAX && x->callback==dlg_tmcb_dummy){
  282. return (struct dlg_cell*)(x->param);
  283. }
  284. x=x->next;
  285. }
  286. return NULL;
  287. }
  288. /*!
  289. * \brief Get the current dialog for a message, if exists
  290. * \param msg SIP message
  291. * \return NULL if called in REQUEST_ROUTE, pointer to dialog ctx otherwise
  292. */
  293. struct dlg_cell *get_current_dialog(struct sip_msg *msg)
  294. {
  295. if (is_route_type(REQUEST_ROUTE|BRANCH_ROUTE)) {
  296. LM_DBG("Get Current Dialog: Route type is REQUEST ROUTE or BRANCH ROUTE");
  297. LM_DBG("Get Current Dialog: SIP Method - %.*s", msg->first_line.u.request.method.len, msg->first_line.u.request.method.s);
  298. /* use the per-process static holder */
  299. if (msg->id==current_dlg_msg_id){
  300. LM_DBG("Message Id [%i] equals current dlg msg id [%i] - returning current dlg pointer", msg->id, current_dlg_msg_id);
  301. return current_dlg_pointer;
  302. }
  303. LM_DBG("Message Id [%i] not equal to current point dlg id [%i] - returning null", msg->id, current_dlg_msg_id);
  304. current_dlg_pointer = NULL;
  305. current_dlg_msg_id = msg->id;
  306. destroy_linkers(current_pending_linkers);
  307. current_pending_linkers = NULL;
  308. return NULL;
  309. } else {
  310. /* use current transaction to get dialog */
  311. LM_DBG("Route type is not REQUEST ROUTE or brancg route - getting from tm");
  312. return get_dialog_from_tm(d_tmb.t_gett());
  313. }
  314. }
  315. /*!
  316. * \brief Calculate the hash profile from a dialog
  317. * \see core_hash
  318. * \param value hash source
  319. * \param dlg dialog cell
  320. * \param profile dialog profile table (for hash size)
  321. * \return value hash if the value has a value, hash over dialog otherwise
  322. */
  323. inline static unsigned int calc_hash_profile(str *value, struct dlg_cell *dlg,
  324. struct dlg_profile_table *profile)
  325. {
  326. if (profile->has_value) {
  327. /* do hash over the value */
  328. return core_hash( value, NULL, profile->size);
  329. } else {
  330. /* do hash over dialog pointer */
  331. return ((unsigned long)dlg) % profile->size ;
  332. }
  333. }
  334. /*!
  335. * \brief Link a dialog profile
  336. * \param linker dialog linker
  337. * \param dlg dialog cell
  338. */
  339. static void link_dlg_profile(struct dlg_profile_link *linker, struct dlg_cell *dlg)
  340. {
  341. unsigned int hash;
  342. struct dlg_profile_entry *p_entry;
  343. struct dlg_entry *d_entry;
  344. /* add the linker to the dialog */
  345. /* FIXME zero h_id is not 100% for testing if the dialog is inserted
  346. * into the hash table -> we need circular lists -bogdan */
  347. if (dlg->h_id) {
  348. d_entry = &d_table->entries[dlg->h_entry];
  349. dlg_lock( d_table, d_entry);
  350. linker->next = dlg->profile_links;
  351. dlg->profile_links =linker;
  352. linker->hash_linker.dlg = dlg;
  353. dlg_unlock( d_table, d_entry);
  354. } else {
  355. linker->next = dlg->profile_links;
  356. dlg->profile_links =linker;
  357. linker->hash_linker.dlg = dlg;
  358. }
  359. /* calculate the hash position */
  360. hash = calc_hash_profile(&linker->hash_linker.value, dlg, linker->profile);
  361. linker->hash_linker.hash = hash;
  362. /* insert into profile hash table */
  363. p_entry = &linker->profile->entries[hash];
  364. lock_get( &linker->profile->lock );
  365. if (p_entry->first) {
  366. linker->hash_linker.prev = p_entry->first->prev;
  367. linker->hash_linker.next = p_entry->first;
  368. p_entry->first->prev->next = &linker->hash_linker;
  369. p_entry->first->prev = &linker->hash_linker;
  370. } else {
  371. p_entry->first = linker->hash_linker.next
  372. = linker->hash_linker.prev = &linker->hash_linker;
  373. }
  374. p_entry->content ++;
  375. lock_release( &linker->profile->lock );
  376. }
  377. /*!
  378. * \brief Set the global variables to the current dialog
  379. * \param msg SIP message
  380. * \param dlg dialog cell
  381. */
  382. void set_current_dialog(struct sip_msg *msg, struct dlg_cell *dlg)
  383. {
  384. struct dlg_profile_link *linker;
  385. struct dlg_profile_link *tlinker;
  386. /* if linkers are not from current request, just discard them */
  387. if (msg->id!=current_dlg_msg_id) {
  388. current_dlg_msg_id = msg->id;
  389. destroy_linkers(current_pending_linkers);
  390. } else {
  391. /* add the linker, one be one, to the dialog */
  392. linker = current_pending_linkers;
  393. while (linker) {
  394. tlinker = linker;
  395. linker = linker->next;
  396. /* process tlinker */
  397. tlinker->next = NULL;
  398. link_dlg_profile( tlinker, dlg);
  399. }
  400. }
  401. current_pending_linkers = NULL;
  402. current_dlg_pointer = dlg;
  403. /* do not increase reference counter here, let caller handle it
  404. * (yes, this is somewhat ugly) */
  405. }
  406. /*!
  407. * \brief Set a dialog profile
  408. * \param msg SIP message
  409. * \param value value
  410. * \param profile dialog profile table
  411. * \return 0 on success, -1 on failure
  412. */
  413. int set_dlg_profile(struct sip_msg *msg, str *value, struct dlg_profile_table *profile)
  414. {
  415. struct dlg_cell *dlg;
  416. struct dlg_profile_link *linker;
  417. /* get current dialog */
  418. dlg = get_current_dialog(msg);
  419. if (dlg==NULL && !is_route_type(REQUEST_ROUTE)) {
  420. LM_CRIT("BUG - dialog not found in a non REQUEST route (%d)\n",
  421. REQUEST_ROUTE);
  422. return -1;
  423. }
  424. /* build new linker */
  425. linker = (struct dlg_profile_link*)shm_malloc(
  426. sizeof(struct dlg_profile_link) + (profile->has_value?value->len:0) );
  427. if (linker==NULL) {
  428. LM_ERR("no more shm memory\n");
  429. return -1;
  430. }
  431. memset(linker, 0, sizeof(struct dlg_profile_link));
  432. /* set backpointer to profile */
  433. linker->profile = profile;
  434. /* set the value */
  435. if (profile->has_value) {
  436. linker->hash_linker.value.s = (char*)(linker+1);
  437. memcpy( linker->hash_linker.value.s, value->s, value->len);
  438. linker->hash_linker.value.len = value->len;
  439. }
  440. if (dlg!=NULL) {
  441. /* add linker directly to the dialog and profile */
  442. link_dlg_profile( linker, dlg);
  443. } else {
  444. /* no dialog yet -> set linker as pending */
  445. linker->next = current_pending_linkers;
  446. current_pending_linkers = linker;
  447. }
  448. return 0;
  449. }
  450. /*!
  451. * \brief Unset a dialog profile
  452. * \param msg SIP message
  453. * \param value value
  454. * \param profile dialog profile table
  455. * \return 1 on success, -1 on failure
  456. */
  457. int unset_dlg_profile(struct sip_msg *msg, str *value,
  458. struct dlg_profile_table *profile)
  459. {
  460. struct dlg_cell *dlg;
  461. struct dlg_profile_link *linker;
  462. struct dlg_profile_link *linker_prev;
  463. struct dlg_entry *d_entry;
  464. /* get current dialog */
  465. dlg = get_current_dialog(msg);
  466. if (dlg==NULL || is_route_type(REQUEST_ROUTE)) {
  467. LM_CRIT("BUG - dialog NULL or del_profile used in request route\n");
  468. return -1;
  469. }
  470. /* check the dialog linkers */
  471. d_entry = &d_table->entries[dlg->h_entry];
  472. dlg_lock( d_table, d_entry);
  473. linker = dlg->profile_links;
  474. linker_prev = NULL;
  475. for( ; linker ; linker_prev=linker,linker=linker->next) {
  476. if (linker->profile==profile) {
  477. if (profile->has_value==0) {
  478. goto found;
  479. } else if (value && value->len==linker->hash_linker.value.len &&
  480. memcmp(value->s,linker->hash_linker.value.s,value->len)==0){
  481. goto found;
  482. }
  483. /* allow further search - maybe the dialog is inserted twice in
  484. * the same profile, but with different values -bogdan
  485. */
  486. }
  487. }
  488. dlg_unlock( d_table, d_entry);
  489. return -1;
  490. found:
  491. /* table still locked */
  492. /* remove the linker element from dialog */
  493. if (linker_prev==NULL) {
  494. dlg->profile_links = linker->next;
  495. } else {
  496. linker_prev->next = linker->next;
  497. }
  498. linker->next = NULL;
  499. dlg_unlock( d_table, d_entry);
  500. /* remove linker from profile table and free it */
  501. destroy_linkers(linker);
  502. return 1;
  503. }
  504. /*!
  505. * \brief Check if a dialog belongs to a profile
  506. * \param msg SIP message
  507. * \param profile dialog profile table
  508. * \param value value
  509. * \return 1 on success, -1 on failure
  510. */
  511. int is_dlg_in_profile(struct sip_msg *msg, struct dlg_profile_table *profile,
  512. str *value) {
  513. struct dlg_cell *dlg;
  514. struct dlg_profile_link *linker;
  515. struct dlg_entry *d_entry;
  516. LM_DBG("Getting current dialog");
  517. /* get current dialog */
  518. dlg = get_current_dialog(msg);
  519. if (dlg == NULL) {
  520. LM_DBG("Error: Current dlg is null");
  521. return -1;
  522. }
  523. LM_DBG("Current dlg found");
  524. /* check the dialog linkers */
  525. d_entry = &d_table->entries[dlg->h_entry];
  526. dlg_lock( d_table, d_entry);
  527. for (linker = dlg->profile_links; linker; linker = linker->next) {
  528. LM_DBG("Running through linkers");
  529. if (linker->profile == profile) {
  530. LM_DBG("Profile matches");
  531. if (profile->has_value == 0) {
  532. LM_DBG("Profile has value is zero returning true");
  533. dlg_unlock( d_table, d_entry);
  534. return 1;
  535. } else if (value && value->len == linker->hash_linker.value.len
  536. && memcmp(value->s, linker->hash_linker.value.s, value->len)
  537. == 0) {
  538. LM_DBG("Profile has value equal to passed value returning true");
  539. dlg_unlock( d_table, d_entry);
  540. return 1;
  541. }
  542. /* allow further search - maybe the dialog is inserted twice in
  543. * the same profile, but with different values -bogdan
  544. */
  545. }
  546. }
  547. dlg_unlock( d_table, d_entry);
  548. return -1;
  549. }
  550. /*!
  551. * \brief Get the size of a profile
  552. * \param profile evaluated profile
  553. * \param value value
  554. * \return the profile size
  555. */
  556. unsigned int get_profile_size(struct dlg_profile_table *profile, str *value)
  557. {
  558. unsigned int n,i;
  559. struct dlg_profile_hash *ph;
  560. if (profile->has_value==0 || value==NULL) {
  561. /* iterate through the hash and count all records */
  562. lock_get( &profile->lock );
  563. for( i=0,n=0 ; i<profile->size ; i++ )
  564. n += profile->entries[i].content;
  565. lock_release( &profile->lock );
  566. return n;
  567. } else {
  568. /* iterate through the hash entry and count only matching */
  569. /* calculate the hash position */
  570. i = calc_hash_profile( value, NULL, profile);
  571. n = 0;
  572. lock_get( &profile->lock );
  573. ph = profile->entries[i].first;
  574. if(ph) {
  575. do {
  576. /* compare */
  577. if ( value->len==ph->value.len &&
  578. memcmp(value->s,ph->value.s,value->len)==0 ) {
  579. /* found */
  580. n++;
  581. }
  582. /* next */
  583. ph=ph->next;
  584. }while( ph!=profile->entries[i].first );
  585. }
  586. lock_release( &profile->lock );
  587. return n;
  588. }
  589. }
  590. /*
  591. * Determine if message is in a dialog currently being tracked
  592. */
  593. int is_known_dlg(struct sip_msg *msg) {
  594. if(get_current_dialog(msg) == NULL)
  595. return -1;
  596. return 1;
  597. }
  598. /****************************** MI commands *********************************/
  599. /*!
  600. * \brief Output a profile via MI interface
  601. * \param cmd_tree MI command tree
  602. * \param param unused
  603. * \return MI root output on success, NULL on failure
  604. */
  605. struct mi_root * mi_get_profile(struct mi_root *cmd_tree, void *param)
  606. {
  607. struct mi_node* node;
  608. struct mi_root* rpl_tree= NULL;
  609. struct mi_node* rpl = NULL;
  610. struct mi_attr* attr;
  611. struct dlg_profile_table *profile;
  612. str *value;
  613. str *profile_name;
  614. unsigned int size;
  615. int len;
  616. char *p;
  617. node = cmd_tree->node.kids;
  618. if (node==NULL || !node->value.s || !node->value.len)
  619. return init_mi_tree( 400, MI_SSTR(MI_MISSING_PARM));
  620. profile_name = &node->value;
  621. if (node->next) {
  622. node = node->next;
  623. if (!node->value.s || !node->value.len)
  624. return init_mi_tree( 400, MI_SSTR(MI_BAD_PARM));
  625. if (node->next)
  626. return init_mi_tree( 400, MI_SSTR(MI_MISSING_PARM));
  627. value = &node->value;
  628. } else {
  629. value = NULL;
  630. }
  631. /* search for the profile */
  632. profile = search_dlg_profile( profile_name );
  633. if (profile==NULL)
  634. return init_mi_tree( 404, MI_SSTR("Profile not found"));
  635. size = get_profile_size( profile , value );
  636. rpl_tree = init_mi_tree( 200, MI_SSTR(MI_OK));
  637. if (rpl_tree==0)
  638. return 0;
  639. rpl = &rpl_tree->node;
  640. node = add_mi_node_child(rpl, MI_DUP_VALUE, "profile", 7, NULL, 0);
  641. if (node==0) {
  642. free_mi_tree(rpl_tree);
  643. return NULL;
  644. }
  645. attr = add_mi_attr(node, MI_DUP_VALUE, "name", 4,
  646. profile->name.s, profile->name.len);
  647. if(attr == NULL) {
  648. goto error;
  649. }
  650. if (value) {
  651. attr = add_mi_attr(node, MI_DUP_VALUE, "value", 5, value->s, value->len);
  652. } else {
  653. attr = add_mi_attr(node, MI_DUP_VALUE, "value", 5, NULL, 0);
  654. }
  655. if(attr == NULL) {
  656. goto error;
  657. }
  658. p= int2str((unsigned long)size, &len);
  659. attr = add_mi_attr(node, MI_DUP_VALUE, "count", 5, p, len);
  660. if(attr == NULL) {
  661. goto error;
  662. }
  663. return rpl_tree;
  664. error:
  665. free_mi_tree(rpl_tree);
  666. return NULL;
  667. }
  668. /*!
  669. * \brief List the profiles via MI interface
  670. * \param cmd_tree MI command tree
  671. * \param param unused
  672. * \return MI root output on success, NULL on failure
  673. */
  674. struct mi_root * mi_profile_list(struct mi_root *cmd_tree, void *param )
  675. {
  676. struct mi_node* node;
  677. struct mi_root* rpl_tree= NULL;
  678. struct mi_node* rpl = NULL;
  679. struct dlg_profile_table *profile;
  680. struct dlg_profile_hash *ph;
  681. str *profile_name;
  682. str *value;
  683. unsigned int i;
  684. node = cmd_tree->node.kids;
  685. if (node==NULL || !node->value.s || !node->value.len)
  686. return init_mi_tree( 400, MI_SSTR(MI_MISSING_PARM));
  687. profile_name = &node->value;
  688. if (node->next) {
  689. node = node->next;
  690. if (!node->value.s || !node->value.len)
  691. return init_mi_tree( 400, MI_SSTR(MI_BAD_PARM));
  692. if (node->next)
  693. return init_mi_tree( 400, MI_SSTR(MI_MISSING_PARM));
  694. value = &node->value;
  695. } else {
  696. value = NULL;
  697. }
  698. /* search for the profile */
  699. profile = search_dlg_profile( profile_name );
  700. if (profile==NULL)
  701. return init_mi_tree( 404, MI_SSTR("Profile not found"));
  702. rpl_tree = init_mi_tree( 200, MI_SSTR(MI_OK));
  703. if (rpl_tree==0)
  704. return 0;
  705. rpl = &rpl_tree->node;
  706. /* go through the hash and print the dialogs */
  707. if (profile->has_value==0 || value==NULL) {
  708. /* no value */
  709. lock_get( &profile->lock );
  710. for ( i=0 ; i< profile->size ; i++ ) {
  711. ph = profile->entries[i].first;
  712. if(ph) {
  713. do {
  714. /* print dialog */
  715. if ( mi_print_dlg( rpl, ph->dlg, 0)!=0 )
  716. goto error;
  717. /* next */
  718. ph=ph->next;
  719. }while( ph!=profile->entries[i].first );
  720. }
  721. lock_release( &profile->lock );
  722. }
  723. } else {
  724. /* check for value also */
  725. lock_get( &profile->lock );
  726. for ( i=0 ; i< profile->size ; i++ ) {
  727. ph = profile->entries[i].first;
  728. if(ph) {
  729. do {
  730. if ( value->len==ph->value.len &&
  731. memcmp(value->s,ph->value.s,value->len)==0 ) {
  732. /* print dialog */
  733. if ( mi_print_dlg( rpl, ph->dlg, 0)!=0 )
  734. goto error;
  735. }
  736. /* next */
  737. ph=ph->next;
  738. }while( ph!=profile->entries[i].first );
  739. }
  740. lock_release( &profile->lock );
  741. }
  742. }
  743. return rpl_tree;
  744. error:
  745. free_mi_tree(rpl_tree);
  746. return NULL;
  747. }