aboutsummaryrefslogtreecommitdiffstats
path: root/main/kamailio/0002-mohqueue-v0-12.patch
diff options
context:
space:
mode:
authorNathan Angelacos <nangel@alpinelinux.org>2015-10-20 16:55:53 +0000
committerNatanael Copa <ncopa@alpinelinux.org>2015-10-21 06:10:33 +0000
commit166444ada7f481e2ceb4f8407cb35d7f57ec2c26 (patch)
treed330afdfa85b04bdc5f02998aa2e7d46e8b53a30 /main/kamailio/0002-mohqueue-v0-12.patch
parent72353bac55bbbf45ff8a3fc0d0f0624d0e2c3205 (diff)
downloadaports-166444ada7f481e2ceb4f8407cb35d7f57ec2c26.tar.bz2
aports-166444ada7f481e2ceb4f8407cb35d7f57ec2c26.tar.xz
main/kamailio mohqueue 0.12
rebased mohqueue patch against the v0.12 version on github
Diffstat (limited to 'main/kamailio/0002-mohqueue-v0-12.patch')
-rw-r--r--main/kamailio/0002-mohqueue-v0-12.patch2794
1 files changed, 2794 insertions, 0 deletions
diff --git a/main/kamailio/0002-mohqueue-v0-12.patch b/main/kamailio/0002-mohqueue-v0-12.patch
new file mode 100644
index 0000000000..63219c4b05
--- /dev/null
+++ b/main/kamailio/0002-mohqueue-v0-12.patch
@@ -0,0 +1,2794 @@
+diff --git a/modules/mohqueue/Makefile b/modules/mohqueue/Makefile
+index 8351c02..f10bb40 100644
+--- a/modules/mohqueue/Makefile
++++ b/modules/mohqueue/Makefile
+@@ -1,5 +1,6 @@
++# $Id$
+ #
+-# mohqueue module makefile
++# msgqueue module makefile
+ #
+ #
+ # WARNING: do not run this directly, it should be run by the master Makefile
+diff --git a/modules/mohqueue/NOTES b/modules/mohqueue/NOTES
+index 0741d9f..ef2fbb6 100644
+--- a/modules/mohqueue/NOTES
++++ b/modules/mohqueue/NOTES
+@@ -1,6 +1,9 @@
+ Things to look into:
+
+ * RFC3261, section 12.1.1 requires UAS to copy Record-Route
++
+ * Check to see if any memory leaks.
++
+ * Should probably respond when caller says BYE after queue says BYE.
+-* check RAck number
++
++* check RAck number
+\ No newline at end of file
+diff --git a/modules/mohqueue/mohq.c b/modules/mohqueue/mohq.c
+index 711f3fe..bc54aca 100644
+--- a/modules/mohqueue/mohq.c
++++ b/modules/mohqueue/mohq.c
+@@ -1,6 +1,5 @@
+ /*
+- *
+- * Copyright (C) 2013 Robert Boisvert
++ * Copyright (C) 2013-15 Robert Boisvert
+ *
+ * This file is part of the mohqueue module for Kamailio, a free SIP server.
+ *
+@@ -60,9 +59,9 @@ static cmd_export_t mod_cmds [] = {
+ };
+
+ /* PARAMETERS */
+-str db_url = str_init(DEFAULT_DB_URL);
+-str db_ctable = str_init("mohqcalls");
+-str db_qtable = str_init("mohqueues");
++str db_url = str_init (DEFAULT_DB_URL);
++str db_ctable = str_init ("mohqcalls");
++str db_qtable = str_init ("mohqueues");
+ char *mohdir = "";
+ int moh_maxcalls = 50;
+
+@@ -133,83 +132,87 @@ return 0;
+ static int init_cfg (void)
+
+ {
+- int error = 0;
+- int bfnd = 0;
+- struct stat psb [1];
+-
+- /**********
+- * db_url, db_ctable, db_qtable exist?
+- **********/
+-
+- if (!db_url.s || db_url.len<=0)
++int bfnd = 0;
++int berror = 0;
++struct stat psb [1];
++
++/**********
++* db_url, db_ctable, db_qtable exist?
++**********/
++
++if (!db_url.s || db_url.len <= 0)
+ {
+- LM_ERR ("db_url parameter not set!\n");
+- error = 1;
++ LM_ERR ("db_url parameter not set!\n");
++ berror = 1;
+ }
+-
+- if (!db_ctable.s || db_ctable.len<=0)
++if (!db_ctable.s || db_ctable.len <= 0)
+ {
+- LM_ERR ("db_ctable parameter not set!\n");
+- error = 1;
++ LM_ERR ("db_ctable parameter not set!\n");
++ berror = 1;
+ }
+-
+- if (!db_qtable.s || db_qtable.len<=0)
++if (!db_qtable.s || db_qtable.len <= 0)
+ {
+- LM_ERR ("db_qtable parameter not set!\n");
+- error = 1;
+- }
+-
+- /**********
+- * mohdir
+- * o exists?
+- * o directory?
+- **********/
+-
+- if (!*mohdir) {
+- LM_ERR ("mohdir parameter not set!\n");
+- error = 1;
+- } else if (strlen(mohdir) > MOHDIRLEN) {
+- LM_ERR ("mohdir too long!");
+- error = 1;
++ LM_ERR ("db_qtable parameter not set!\n");
++ berror = 1;
+ }
+- if (moh_maxcalls < 1 || moh_maxcalls > 5000)
++
++/**********
++* mohdir
++* o exists?
++* o directory?
++**********/
++
++if (!*mohdir)
+ {
+- LM_ERR ("moh_maxcalls not in range of 1-5000!");
+- error = 1;
++ LM_ERR ("mohdir parameter not set!\n");
++ berror = 1;
+ }
+- if (error == 1) {
+- return 0;
++else if (strlen (mohdir) > MOHDIRLEN)
++ {
++ LM_ERR ("mohdir too long!\n");
++ berror = 1;
+ }
+- pmod_data->pcfg->db_qtable = db_qtable;
+- pmod_data->pcfg->db_ctable = db_ctable;
+- pmod_data->pcfg->db_url = db_url;
+- pmod_data->pcfg->mohdir = mohdir;
+-
+- if (!lstat (mohdir, psb))
++else
+ {
++ if (!lstat (mohdir, psb))
++ {
+ if ((psb->st_mode & S_IFMT) == S_IFDIR)
+ { bfnd = 1; }
+- }
++ }
+ if (!bfnd)
+- {
++ {
+ LM_ERR ("mohdir is not a directory!\n");
+- return 0;
++ berror = 1;
++ }
+ }
+
+- /**********
+- * max calls
+- * o valid count?
+- * o alloc memory
+- **********/
++/**********
++* o max calls valid?
++* o alloc memory
++* o save data
++**********/
+
+- pmod_data->pcall_lst = (call_lst *) shm_malloc (sizeof (call_lst) * moh_maxcalls);
+- if (!pmod_data->pcall_lst) {
+- LM_ERR ("Unable to allocate shared memory");
+- return -1;
++if (moh_maxcalls < 1 || moh_maxcalls > 5000)
++ {
++ LM_ERR ("moh_maxcalls not in range of 1-5000!\n");
++ berror = 1;
+ }
+- memset (pmod_data->pcall_lst, 0, sizeof (call_lst) * moh_maxcalls);
+- pmod_data->call_cnt = moh_maxcalls;
+- return -1;
++if (berror)
++ { return 0; }
++pmod_data->pcall_lst =
++ (call_lst *) shm_malloc (sizeof (call_lst) * moh_maxcalls);
++if (!pmod_data->pcall_lst)
++ {
++ LM_ERR ("Unable to allocate shared memory!\n");
++ return 0;
++ }
++pmod_data->pcfg->db_url = db_url;
++pmod_data->pcfg->db_ctable = db_ctable;
++pmod_data->pcfg->db_qtable = db_qtable;
++pmod_data->pcfg->mohdir = mohdir;
++memset (pmod_data->pcall_lst, 0, sizeof (call_lst) * moh_maxcalls);
++pmod_data->call_cnt = moh_maxcalls;
++return -1;
+ }
+
+ /**********
+@@ -232,13 +235,13 @@ static int init_db (void)
+ str *pdb_url = &pmod_data->pcfg->db_url;
+ if (db_bind_mod (pdb_url, pmod_data->pdb))
+ {
+- LM_ERR ("Unable to bind DB API using %s", pdb_url->s);
++ LM_ERR ("Unable to bind DB API using %s!\n", pdb_url->s);
+ return 0;
+ }
+ db_func_t *pdb = pmod_data->pdb;
+ if (!DB_CAPABILITY ((*pdb), DB_CAP_ALL))
+ {
+- LM_ERR ("Selected database %s lacks required capabilities", pdb_url->s);
++ LM_ERR ("Selected database %s lacks required capabilities!\n", pdb_url->s);
+ return 0;
+ }
+ db1_con_t *pconn = mohq_dbconnect ();
+@@ -254,14 +257,14 @@ if (!pconn)
+ if (db_check_table_version (pdb, pconn,
+ &pmod_data->pcfg->db_ctable, MOHQ_CTABLE_VERSION) < 0)
+ {
+- LM_ERR ("%s table in DB %s not at version %d",
++ LM_ERR ("%s table in DB %s not at version %d!\n",
+ pmod_data->pcfg->db_ctable.s, pdb_url->s, MOHQ_CTABLE_VERSION);
+ goto dberr;
+ }
+ if (db_check_table_version (pdb, pconn,
+ &pmod_data->pcfg->db_qtable, MOHQ_QTABLE_VERSION) < 0)
+ {
+- LM_ERR ("%s table in DB %s not at version %d",
++ LM_ERR ("%s table in DB %s not at version %d!\n",
+ pmod_data->pcfg->db_qtable.s, pdb_url->s, MOHQ_QTABLE_VERSION);
+ goto dberr;
+ }
+@@ -301,7 +304,7 @@ if (rank == PROC_INIT || rank == PROC_TCP_MAIN || rank == PROC_MAIN)
+ { return 0; }
+ if (!pmod_data->pdb->init)
+ {
+- LM_CRIT ("DB API not loaded!");
++ LM_CRIT ("DB API not loaded!\n");
+ return -1;
+ }
+ return 0;
+@@ -355,7 +358,7 @@ int mod_init (void)
+ pmod_data = (mod_data *) shm_malloc (sizeof (mod_data));
+ if (!pmod_data)
+ {
+- LM_ERR ("Unable to allocate shared memory");
++ LM_ERR ("Unable to allocate shared memory!\n");
+ return -1;
+ }
+ memset (pmod_data, 0, sizeof (mod_data));
+@@ -371,47 +374,59 @@ if (!init_db ())
+
+ if (sl_load_api (pmod_data->psl))
+ {
+- LM_ERR ("Unable to load SL module\n");
++ LM_ERR ("Unable to load SL module!\n");
+ goto initerr;
+ }
+ if (load_tm_api (pmod_data->ptm))
+ {
+- LM_ERR ("Unable to load TM module\n");
++ LM_ERR ("Unable to load TM module!\n");
+ goto initerr;
+ }
+ if (load_rr_api (pmod_data->prr))
+ {
+- LM_ERR ("Unable to load RR module\n");
++ LM_ERR ("Unable to load RR module!\n");
+ goto initerr;
+ }
+ pmod_data->fn_rtp_answer = find_export ("rtpproxy_answer", 0, 0);
+ if (!pmod_data->fn_rtp_answer)
+ {
+- LM_ERR ("Unable to load rtpproxy_answer\n");
++ LM_ERR ("Unable to load rtpproxy_answer!\n");
+ goto initerr;
+ }
+ pmod_data->fn_rtp_offer = find_export ("rtpproxy_offer", 0, 0);
+ if (!pmod_data->fn_rtp_offer)
+ {
+- LM_ERR ("Unable to load rtpproxy_offer\n");
++ LM_ERR ("Unable to load rtpproxy_offer!\n");
+ goto initerr;
+ }
+ pmod_data->fn_rtp_stream_c = find_export ("rtpproxy_stream2uac", 2, 0);
+ if (!pmod_data->fn_rtp_stream_c)
+ {
+- LM_ERR ("Unable to load rtpproxy_stream2uac\n");
++ LM_ERR ("Unable to load rtpproxy_stream2uac!\n");
+ goto initerr;
+ }
+ pmod_data->fn_rtp_stream_s = find_export ("rtpproxy_stream2uas", 2, 0);
+ if (!pmod_data->fn_rtp_stream_s)
+ {
+- LM_ERR ("Unable to load rtpproxy_stream2uas\n");
++ LM_ERR ("Unable to load rtpproxy_stream2uas!\n");
++ goto initerr;
++ }
++pmod_data->fn_rtp_stop_c = find_export ("rtpproxy_stop_stream2uac", 0, 0);
++if (!pmod_data->fn_rtp_stop_c)
++ {
++ LM_ERR ("Unable to load rtpproxy_stop_stream2uac!\n");
++ goto initerr;
++ }
++pmod_data->fn_rtp_stop_s = find_export ("rtpproxy_stop_stream2uas", 0, 0);
++if (!pmod_data->fn_rtp_stop_s)
++ {
++ LM_ERR ("Unable to load rtpproxy_stop_stream2uas!\n");
+ goto initerr;
+ }
+ pmod_data->fn_rtp_destroy = find_export ("rtpproxy_destroy", 0, 0);
+ if (!pmod_data->fn_rtp_destroy)
+ {
+- LM_ERR ("Unable to load rtpproxy_destroy\n");
++ LM_ERR ("Unable to load rtpproxy_destroy!\n");
+ goto initerr;
+ }
+
+@@ -438,4 +453,4 @@ if (pmod_data->pcall_lock->plock)
+ shm_free (pmod_data);
+ pmod_data = NULL;
+ return -1;
+-}
++}
+\ No newline at end of file
+diff --git a/modules/mohqueue/mohq.h b/modules/mohqueue/mohq.h
+index b23e6a3..207bcba 100644
+--- a/modules/mohqueue/mohq.h
++++ b/modules/mohqueue/mohq.h
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (C) 2013 Robert Boisvert
++ * Copyright (C) 2013-15 Robert Boisvert
+ *
+ * This file is part of the mohqueue module for Kamailio, a free SIP server.
+ *
+@@ -61,31 +61,35 @@ typedef struct
+
+ /* call_state values */
+ #define CLSTA_ENTER 100
+-#define CLSTA_PRACKSTRT 101
+-#define CLSTA_PRACKRPLY 102
+-#define CLSTA_RINGING 103
++#define CLSTA_TRYING 101
++#define CLSTA_PRACKSTRT 102
++#define CLSTA_PRACKRPLY 103
+ #define CLSTA_INVITED 104
+ #define CLSTA_CANCEL 105
+ #define CLSTA_INQUEUE 200
+ #define CLSTA_REFER 301
+ #define CLSTA_RFRWAIT 302
++#define CLSTA_BYEOK 304
+ #define CLSTA_BYE 305
+
+ typedef struct
+ {
+- int call_active;
+- char call_id [101];
+- char call_from [URI_LEN + 1];
++ char call_buffer [1024];
++ size_t call_buflen;
++ char *call_id;
++ char *call_from;
+ char call_referto [URI_LEN + 1];
+- char call_contact [URI_LEN + 1];
+- char call_tag [101];
+- char call_via [1024];
++ char *call_contact;
++ char *call_tag;
++ char *call_via;
++ char *call_route;
+ char call_addr [IP_ADDR_MAX_STR_SIZE + 4];
+ int call_state;
+ int call_cseq;
+ int call_aport;
+ mohq_lst *pmohq;
+ time_t call_time;
++ time_t refer_time;
+ unsigned int call_hash;
+ unsigned int call_label;
+ sip_msg_t *call_pmsg;
+@@ -118,6 +122,8 @@ typedef struct
+ cmd_function fn_rtp_offer;
+ cmd_function fn_rtp_stream_c;
+ cmd_function fn_rtp_stream_s;
++ cmd_function fn_rtp_stop_c;
++ cmd_function fn_rtp_stop_s;
+ } mod_data;
+
+ /**********
+@@ -127,4 +133,4 @@ typedef struct
+ extern mod_data *pmod_data;
+ extern rtpmap prtpmap [];
+
+-#endif /* MOHQ_H */
++#endif /* MOHQ_H */
+\ No newline at end of file
+diff --git a/modules/mohqueue/mohq_common.h b/modules/mohqueue/mohq_common.h
+index 9103323..10f6249 100644
+--- a/modules/mohqueue/mohq_common.h
++++ b/modules/mohqueue/mohq_common.h
+@@ -1,6 +1,5 @@
+ /*
+- *
+- * Copyright (C) 2013 Robert Boisvert
++ * Copyright (C) 2013-15 Robert Boisvert
+ *
+ * This file is part of the mohqueue module for Kamailio, a free SIP server.
+ *
+@@ -52,6 +51,7 @@
+ #include "../../parser/contact/parse_contact.h"
+ #include "../../parser/parse_expires.h"
+ #include "../../parser/parse_from.h"
++#include "../../parser/parse_rr.h"
+ #include "../../parser/sdp/sdp.h"
+
+ /* convenience macros */
+@@ -68,7 +68,7 @@
+
+ #define MOHQ_STR_APPEND_L( str1, str1_lim, s2, s2_len ) \
+ if ((str1)->len + (s2_len) >= (str1_lim)) { \
+- LM_ERR( "Failed to append to str: too long" ); \
++ LM_ERR( "Failed to append to str: too long!\n" ); \
+ } else { \
+ MOHQ_STR_APPEND((str1), (s2), (s2_len)); \
+ (str1_lim) -= (s2_len); \
+@@ -83,7 +83,7 @@
+
+ #define MOHQ_STR_APPEND_CSTR_L( str1, str1_lim, cstr1 ) \
+ if ((str1)->len + strlen(cstr1) >= (str1_lim)) { \
+- LM_ERR( "Failed to append to str: too long" ); \
++ LM_ERR( "Failed to append to str: too long!\n" ); \
+ } else { \
+ MOHQ_STR_APPEND_CSTR((str1), (cstr1)); \
+ }
+@@ -100,4 +100,4 @@
+ #define MOHQ_HEADER_EMPTY( hdr1 ) \
+ ((hdr1) == NULL || MOHQ_STR_EMPTY( &(hdr1)->body ))
+
+-#endif /* MOHQ_COMMON_H */
++#endif /* MOHQ_COMMON_H */
+\ No newline at end of file
+diff --git a/modules/mohqueue/mohq_db.c b/modules/mohqueue/mohq_db.c
+index 64ac90e..56e420f 100644
+--- a/modules/mohqueue/mohq_db.c
++++ b/modules/mohqueue/mohq_db.c
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (C) 2013 Robert Boisvert
++ * Copyright (C) 2013-15 Robert Boisvert
+ *
+ * This file is part of the mohqueue module for Kamailio, a free SIP server.
+ *
+@@ -214,7 +214,7 @@ pcall->call_time = time (0);
+ fill_call_vals (prvals, pcall, CALL_COLCNT);
+ if (pdb->insert (pconn, prkeys, prvals, CALL_COLCNT) < 0)
+ {
+- LM_WARN ("%sUnable to add new row to %s", pfncname,
++ LM_WARN ("%sUnable to add new row to %s\n", pfncname,
+ pmod_data->pcfg->db_ctable.s);
+ }
+ mohq_dbdisconnect (pconn);
+@@ -241,7 +241,7 @@ db_func_t *pdb = pmod_data->pdb;
+ pdb->use_table (pconn, &pmod_data->pcfg->db_ctable);
+ if (pdb->delete (pconn, 0, 0, 0, 0) < 0)
+ {
+- LM_WARN ("%sUnable to delete all rows from %s", pfncname,
++ LM_WARN ("%sUnable to delete all rows from %s\n", pfncname,
+ pmod_data->pcfg->db_ctable.s);
+ }
+ return;
+@@ -275,7 +275,7 @@ db_val_t prvals [1];
+ set_call_val (prvals, 0, CALLCOL_CALL, pcall->call_id);
+ if (pdb->delete (pconn, prkeys, 0, prvals, 1) < 0)
+ {
+- LM_WARN ("%sUnable to delete row from %s", pfncname,
++ LM_WARN ("%sUnable to delete row from %s\n", pfncname,
+ pmod_data->pcfg->db_ctable.s);
+ }
+ mohq_dbdisconnect (pconn);
+@@ -295,7 +295,7 @@ db1_con_t *mohq_dbconnect (void)
+ str *pdb_url = &pmod_data->pcfg->db_url;
+ db1_con_t *pconn = pmod_data->pdb->init (pdb_url);
+ if (!pconn)
+- { LM_ERR ("Unable to connect to DB %s\n", pdb_url->s); }
++ { LM_ERR ("Unable to connect to DB %s!\n", pdb_url->s); }
+ return pconn;
+ }
+
+@@ -346,7 +346,7 @@ db_val_t puvals [1];
+ fill_call_vals (puvals, pcall, CALLCOL_STATE);
+ if (pdb->update (pconn, pqkeys, 0, pqvals, pukeys, puvals, 1, 1) < 0)
+ {
+- LM_WARN ("%sUnable to update row in %s", pfncname,
++ LM_WARN ("%sUnable to update row in %s\n", pfncname,
+ pmod_data->pcfg->db_ctable.s);
+ }
+ mohq_dbdisconnect (pconn);
+@@ -388,7 +388,7 @@ puvals->type = DB1_INT;
+ puvals->nul = 0;
+ if (pdb->update (pconn, pqkeys, 0, pqvals, pukeys, puvals, 1, 1) < 0)
+ {
+- LM_WARN ("%sUnable to update row in %s", pfncname,
++ LM_WARN ("%sUnable to update row in %s\n", pfncname,
+ pmod_data->pcfg->db_qtable.s);
+ }
+ mohq_dbdisconnect (pconn);
+@@ -523,21 +523,21 @@ for (nidx = 0; nidx < nrows; nidx++)
+ if (strcmp (pqlst [nidx2].mohq_mohdir, pmohdir))
+ {
+ strcpy (pqlst [nidx2].mohq_mohdir, pmohdir);
+- LM_INFO ("Queue,Field (%s,%.*s): Changed", pqname,
++ LM_INFO ("Queue,Field (%s,%.*s): Changed\n", pqname,
+ STR_FMT (&MOHQCSTR_MDIR));
+ }
+ ptext = (char *)VAL_STRING (prowvals + MOHQCOL_MFILE);
+ if (strcmp (pqlst [nidx2].mohq_mohfile, ptext))
+ {
+ strcpy (pqlst [nidx2].mohq_mohfile, ptext);
+- LM_INFO ("Queue,Field (%s,%.*s): Changed", pqname,
++ LM_INFO ("Queue,Field (%s,%.*s): Changed\n", pqname,
+ STR_FMT (&MOHQCSTR_MFILE));
+ }
+ ptext = (char *)VAL_STRING (prowvals + MOHQCOL_NAME);
+ if (strcmp (pqlst [nidx2].mohq_name, ptext))
+ {
+ strcpy (pqlst [nidx2].mohq_name, ptext);
+- LM_INFO ("Queue,Field (%s,%.*s): Changed", pqname,
++ LM_INFO ("Queue,Field (%s,%.*s): Changed\n", pqname,
+ STR_FMT (&MOHQCSTR_NAME));
+ }
+ int bdebug = VAL_INT (prowvals + MOHQCOL_DEBUG) ? MOHQF_DBG : 0;
+@@ -547,7 +547,7 @@ for (nidx = 0; nidx < nrows; nidx++)
+ { pqlst [nidx2].mohq_flags |= MOHQF_DBG; }
+ else
+ { pqlst [nidx2].mohq_flags &= ~MOHQF_DBG; }
+- LM_INFO ("Queue,Field (%s,%.*s): Changed", pqname,
++ LM_INFO ("Queue,Field (%s,%.*s): Changed\n", pqname,
+ STR_FMT (&MOHQCSTR_DEBUG));
+ }
+ bfnd = -1;
+@@ -590,7 +590,7 @@ for (nidx = 0; nidx < nrows; nidx++)
+ (char *)VAL_STRING (prowvals + MOHQCOL_NAME));
+ if (VAL_INT (prowvals + MOHQCOL_DEBUG))
+ { pnewlst [nsize].mohq_flags |= MOHQF_DBG; }
+- LM_INFO ("Added new queue (%s)", pnewlst [nsize].mohq_name);
++ LM_INFO ("Added new queue (%s)\n", pnewlst [nsize].mohq_name);
+ if (nsize)
+ { shm_free (pmod_data->pmohq_lst); }
+ pmod_data->pmohq_lst = pnewlst;
+@@ -611,7 +611,7 @@ for (nidx = 0; nidx < pmod_data->mohq_cnt; nidx++)
+
+ if (pqlst [nidx].mohq_flags & MOHQF_CHK)
+ { continue; }
+- LM_INFO ("Removed queue (%s)", pqlst [nidx].mohq_name);
++ LM_INFO ("Removed queue (%s)\n", pqlst [nidx].mohq_name);
+ if (nidx != (pmod_data->mohq_cnt - 1))
+ {
+ memcpy (&pqlst [nidx], &pqlst [pmod_data->mohq_cnt - 1],
+@@ -621,4 +621,4 @@ for (nidx = 0; nidx < pmod_data->mohq_cnt; nidx++)
+ --nidx;
+ }
+ return;
+-}
++}
+\ No newline at end of file
+diff --git a/modules/mohqueue/mohq_db.h b/modules/mohqueue/mohq_db.h
+index 611d455..c343601 100644
+--- a/modules/mohqueue/mohq_db.h
++++ b/modules/mohqueue/mohq_db.h
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (C) 2013 Robert Boisvert
++ * Copyright (C) 2013-15 Robert Boisvert
+ *
+ * This file is part of the mohqueue module for Kamailio, a free SIP server.
+ *
+@@ -61,4 +61,4 @@ void update_call_rec (call_lst *);
+ void update_debug (mohq_lst *, int);
+ void update_mohq_lst (db1_con_t *pconn);
+
+-#endif /* MOHQ_DB_H */
++#endif /* MOHQ_DB_H */
+\ No newline at end of file
+diff --git a/modules/mohqueue/mohq_funcs.c b/modules/mohqueue/mohq_funcs.c
+index 1d023e6..86699ae 100644
+--- a/modules/mohqueue/mohq_funcs.c
++++ b/modules/mohqueue/mohq_funcs.c
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (C) 2013 Robert Boisvert
++ * Copyright (C) 2013-15 Robert Boisvert
+ *
+ * This file is part of the mohqueue module for Kamailio, a free SIP server.
+ *
+@@ -32,7 +32,7 @@
+ #define ALLOWHDR "Allow: INVITE, ACK, BYE, CANCEL, NOTIFY, PRACK"
+ #define CLENHDR "Content-Length"
+ #define SIPEOL "\r\n"
+-#define USRAGNT "Kamailio MOH Queue v1.0"
++#define USRAGNT "Kamailio MOH Queue v1.2"
+
+ /**********
+ * local constants
+@@ -46,6 +46,7 @@ str pinvite [1] = {STR_STATIC_INIT ("INVITE")};
+ str pmi_nolock [1] = {STR_STATIC_INIT ("Unable to lock queue")};
+ str pmi_noqueue [1] = {STR_STATIC_INIT ("No matching queue name found")};
+ str prefer [1] = {STR_STATIC_INIT ("REFER")};
++str presp_busy [1] = {STR_STATIC_INIT ("Busy Here")};
+ str presp_noaccept [1] = {STR_STATIC_INIT ("Not Acceptable Here")};
+ str presp_noallow [1] = {STR_STATIC_INIT ("Method Not Allowed")};
+ str presp_nocall [1] = {STR_STATIC_INIT ("Call/Transaction Does Not Exist")};
+@@ -55,6 +56,7 @@ str presp_reqterm [1] = {STR_STATIC_INIT ("Request Terminated")};
+ str presp_ring [1] = {STR_STATIC_INIT ("Ringing")};
+ str psipfrag [1] = {STR_STATIC_INIT ("message/sipfrag")};
+ str presp_srverr [1] = {STR_STATIC_INIT ("Server Internal Error")};
++str presp_trying [1] = {STR_STATIC_INIT ("Trying to enter MOH queue")};
+ str presp_unsupp [1] = {STR_STATIC_INIT ("Unsupported Media Type")};
+
+ rtpmap prtpmap [] =
+@@ -86,9 +88,9 @@ str pallowhdr [1] = { STR_STATIC_INIT (ALLOWHDR SIPEOL) };
+ char pbyemsg [] =
+ {
+ "%s"
++ "%s"
+ "Max-Forwards: 70" SIPEOL
+ "Contact: <%s>" SIPEOL
+- "User-Agent: " USRAGNT SIPEOL
+ };
+
+ str pextrahdr [1] =
+@@ -98,7 +100,6 @@ str pextrahdr [1] =
+ "Supported: 100rel" SIPEOL
+ "Accept-Language: en" SIPEOL
+ "Content-Type: application/sdp" SIPEOL
+- "User-Agent: " USRAGNT SIPEOL
+ )
+ };
+
+@@ -116,10 +117,11 @@ char pinvitesdp [] =
+ char prefermsg [] =
+ {
+ "%s"
++ "%s"
++ "Contact: <%s>" SIPEOL
+ "Max-Forwards: 70" SIPEOL
+ "Refer-To: <%s>" SIPEOL
+- "Referred-By: <%.*s>" SIPEOL
+- "User-Agent: " USRAGNT SIPEOL
++ "Referred-By: <%s>" SIPEOL
+ };
+
+ char preinvitemsg [] =
+@@ -129,7 +131,6 @@ char preinvitemsg [] =
+ "Contact: <%s>" SIPEOL
+ ALLOWHDR SIPEOL
+ "Supported: 100rel" SIPEOL
+- "User-Agent: " USRAGNT SIPEOL
+ "Accept-Language: en" SIPEOL
+ "Content-Type: application/sdp" SIPEOL
+ };
+@@ -151,8 +152,7 @@ char prtpsdp [] =
+ **********/
+
+ void delete_call (call_lst *);
+-void drop_call (sip_msg_t *, call_lst *);
+-int find_call (sip_msg_t *, call_lst **);
++void end_RTP (sip_msg_t *, call_lst *);
+ dlg_t *form_dialog (call_lst *, struct to_body *);
+ int form_rtp_SDP (str *, call_lst *, char *);
+ static void invite_cb (struct cell *, int, struct tmcb_params *);
+@@ -162,6 +162,7 @@ int send_prov_rsp (sip_msg_t *, call_lst *);
+ int send_rtp_answer (sip_msg_t *, call_lst *);
+ int search_hdr_ext (struct hdr_field *, str *);
+ int start_stream (sip_msg_t *, call_lst *, int);
++int stop_stream (sip_msg_t *, call_lst *, int);
+
+ /**********
+ * local functions
+@@ -173,10 +174,10 @@ int start_stream (sip_msg_t *, call_lst *, int);
+ * INPUT:
+ * Arg (1) = SIP message pointer
+ * Arg (2) = call pointer
+-* OUTPUT: 0=failed
++* OUTPUT: none
+ **********/
+
+-int ack_msg (sip_msg_t *pmsg, call_lst *pcall)
++void ack_msg (sip_msg_t *pmsg, call_lst *pcall)
+
+ {
+ /**********
+@@ -199,7 +200,7 @@ if (pcall->call_state != CLSTA_INVITED)
+ mohq_debug (pcall->pmohq, "%sACK from refused re-INVITE (%s)!\n",
+ pfncname, pcall->call_from);
+ }
+- return 1;
++ return;
+ }
+
+ /**********
+@@ -212,7 +213,7 @@ if (ptm->t_lookup_ident (&ptrans, pcall->call_hash, pcall->call_label) < 0)
+ {
+ LM_ERR ("%sINVITE transaction missing for call (%s)!\n",
+ pfncname, pcall->call_from);
+- return 1;
++ return;
+ }
+ else
+ {
+@@ -220,7 +221,7 @@ else
+ {
+ LM_ERR ("%sRelease transaction failed for call (%s)!\n",
+ pfncname, pcall->call_from);
+- return 1;
++ return;
+ }
+ }
+ pcall->call_hash = pcall->call_label = 0;
+@@ -233,6 +234,47 @@ pcall->call_cseq = 1;
+ mohq_debug (pcall->pmohq,
+ "%sACK received for call (%s); placed in queue (%s)",
+ pfncname, pcall->call_from, pcall->pmohq->mohq_name);
++return;
++}
++
++/**********
++* Add String to Buffer
++*
++* INPUT:
++* Arg (1) = string pointer
++* Arg (2) = string length
++* Arg (3) = pointer to buffer pointer
++* Arg (4) = pointer to buffer size
++* Arg (5) = add NUL flag
++* OUTPUT: =0 if insufficent space
++* bufpointer incremented, size decremented
++**********/
++
++int addstrbfr (char *pstr, size_t nlen, char **pbuf, size_t *nmax, int bnull)
++
++{
++/**********
++* o enough space?
++* o copy string
++* o adjust position/size
++**********/
++
++size_t nsize = nlen;
++if (bnull)
++ { nsize++; }
++if (nsize > *nmax)
++ { return 0; }
++if (nlen)
++ {
++ strncpy (*pbuf, pstr, nlen);
++ *pbuf += nlen;
++ }
++if (bnull)
++ {
++ **pbuf = '\0';
++ (*pbuf)++;
++ }
++*nmax -= nsize;
+ return 1;
+ }
+
+@@ -259,7 +301,7 @@ char *pfncname = "bye_cb: ";
+ call_lst *pcall = (call_lst *)*pcbp->param;
+ if (ntype == TMCB_ON_FAILURE)
+ {
+- LM_ERR ("%sCall (%s) did not respond to BYE\n", pfncname,
++ LM_ERR ("%sCall (%s) did not respond to BYE!\n", pfncname,
+ pcall->call_from);
+ }
+ else
+@@ -267,7 +309,7 @@ else
+ int nreply = pcbp->code;
+ if ((nreply / 100) != 2)
+ {
+- LM_ERR ("%sCall (%s) BYE error (%d)\n", pfncname,
++ LM_ERR ("%sCall (%s) BYE error (%d)!\n", pfncname,
+ pcall->call_from, nreply);
+ }
+ else
+@@ -286,33 +328,43 @@ return;
+ * INPUT:
+ * Arg (1) = SIP message pointer
+ * Arg (2) = call pointer
+-* OUTPUT: 0=failed
++* OUTPUT: none
+ **********/
+
+-int bye_msg (sip_msg_t *pmsg, call_lst *pcall)
++void bye_msg (sip_msg_t *pmsg, call_lst *pcall)
+
+ {
+ /**********
+-* o send OK
+-* o teardown call
++* o responded?
++* o teardown RTP
+ **********/
+
+ char *pfncname = "bye_msg: ";
+-if (pmod_data->psl->freply (pmsg, 200, presp_ok) < 0)
++if (pcall->call_state == CLSTA_BYEOK)
++ { return; }
++if (pcall->call_state >= CLSTA_INQUEUE)
+ {
+- LM_ERR ("%sUnable to create reply to call (%s)\n", pfncname,
+- pcall->call_from);
+- return 1;
++ pcall->call_state = CLSTA_BYEOK;
++ end_RTP (pmsg, pcall);
+ }
+-if (pcall->call_state >= CLSTA_INQUEUE)
+- { drop_call (pmsg, pcall); }
+ else
+ {
+ LM_ERR ("%sEnding call (%s) before placed in queue!\n",
+ pfncname, pcall->call_from);
+- delete_call (pcall);
+ }
+-return 1;
++
++/**********
++* send OK and delete from queue
++**********/
++
++if (pmod_data->psl->freply (pmsg, 200, presp_ok) < 0)
++ {
++ LM_ERR ("%sUnable to create reply to call (%s)!\n", pfncname,
++ pcall->call_from);
++ return;
++ }
++delete_call (pcall);
++return;
+ }
+
+ /**********
+@@ -321,14 +373,15 @@ return 1;
+ * INPUT:
+ * Arg (1) = SIP message pointer
+ * Arg (2) = call pointer
+-* OUTPUT: 0=failed
++* OUTPUT: none
+ **********/
+
+-int cancel_msg (sip_msg_t *pmsg, call_lst *pcall)
++void cancel_msg (sip_msg_t *pmsg, call_lst *pcall)
+
+ {
+ /**********
+-* still in INVITE dialog?
++* RFC 3261 section 9.2
++* o still in INVITE dialog?
+ **********/
+
+ char *pfncname = "cancel_msg: ";
+@@ -347,7 +400,7 @@ else
+ if (pmod_data->psl->freply (pmsg, 481, presp_nocall) < 0)
+ { LM_ERR ("%sUnable to create reply!\n", pfncname); }
+ }
+-return 1;
++return;
+ }
+
+ /**********
+@@ -363,23 +416,14 @@ void close_call (sip_msg_t *pmsg, call_lst *pcall)
+
+ {
+ /**********
+-* o destroy proxy connection
++* o destroy RTP connection
+ * o create dialog
+ **********/
+
+ char *pfncname = "close_call: ";
+ int bsent = 0;
+ char *phdr = 0;
+-if (pmsg != FAKED_REPLY)
+- {
+- mohq_debug (pcall->pmohq, "%sDestroying RTP link for call (%s)",
+- pfncname, pcall->call_from);
+- if (pmod_data->fn_rtp_destroy (pmsg, 0, 0) != 1)
+- {
+- LM_ERR ("%srtpproxy_destroy refused for call (%s)!\n",
+- pfncname, pcall->call_from);
+- }
+- }
++end_RTP (pmsg, pcall);
+ struct to_body ptob [2];
+ dlg_t *pdlg = form_dialog (pcall, ptob);
+ if (!pdlg)
+@@ -396,6 +440,7 @@ tm_api_t *ptm = pmod_data->ptm;
+ char *pquri = pcall->pmohq->mohq_uri;
+ int npos1 = sizeof (pbyemsg) // BYE template
+ + strlen (pcall->call_via) // Via
++ + strlen (pcall->call_route) // Route
+ + strlen (pquri); // Contact
+ phdr = pkg_malloc (npos1);
+ if (!phdr)
+@@ -405,6 +450,7 @@ if (!phdr)
+ }
+ sprintf (phdr, pbyemsg,
+ pcall->call_via, // Via
++ pcall->call_route, // Route
+ pquri); // Contact
+ str phdrs [1];
+ phdrs->s = phdr;
+@@ -424,7 +470,7 @@ if (ptm->t_request_within (puac) < 0)
+ pfncname, pcall->call_from);
+ goto bye_err;
+ }
+-mohq_debug (pcall->pmohq, "%sSent BYE request for call (%s)\n",
++mohq_debug (pcall->pmohq, "%sSent BYE request for call (%s)",
+ pfncname, pcall->call_from);
+ bsent = 1;
+
+@@ -447,138 +493,125 @@ return;
+ * Create New Call Record
+ *
+ * INPUT:
+-* Arg (1) = queue index
+-* Arg (2) = SIP message pointer
+-* OUTPUT: call index; -1 if unable to create
++* Arg (1) = SIP message pointer
++* Arg (2) = call pointer
++* Arg (3) = call index
++* Arg (4) = queue index
++* OUTPUT: initializes call record; =0 if failed
+ **********/
+
+-int create_call (int mohq_idx, sip_msg_t *pmsg)
++int
++create_call (sip_msg_t *pmsg, call_lst *pcall, int ncall_idx, int mohq_idx)
+
+ {
+ /**********
+-* o lock calls
+-* o already in use?
+-* o find inactive slot
+-**********/
+-
+-char *pfncname = "create_call: ";
+-if (!mohq_lock_set (pmod_data->pcall_lock, 1, 2000))
+- {
+- LM_ERR ("%sUnable to lock calls!\n", pfncname);
+- return -1;
+- }
+-call_lst *pcall;
+-int ncall_idx = find_call (pmsg, &pcall);
+-if (pcall)
+- {
+- mohq_lock_release (pmod_data->pcall_lock);
+- LM_ERR ("%sCall already in use (%s)!\n", pfncname, pcall->call_from);
+- return -1;
+- }
+-for (ncall_idx = 0; ncall_idx < pmod_data->call_cnt; ncall_idx++)
+- {
+- if (!pmod_data->pcall_lst [ncall_idx].call_active)
+- { break; }
+- }
+-if (ncall_idx == pmod_data->call_cnt)
+- {
+- mohq_lock_release (pmod_data->pcall_lock);
+- LM_ERR ("%sNo call slots available!\n", pfncname);
+- return -1;
+- }
+-
+-/**********
+ * add values to new entry
+ **********/
+
+-pcall = &pmod_data->pcall_lst [ncall_idx];
+-pcall->call_active = 1;
++char *pfncname = "create_call: ";
+ pcall->pmohq = &pmod_data->pmohq_lst [mohq_idx];
+-pcall->call_state = 0;
+ str *pstr = &pmsg->callid->body;
+-strncpy (pcall->call_id, pstr->s, pstr->len);
+-pcall->call_id [pstr->len] = '\0';
++char *pbuf = pcall->call_buffer;
++pcall->call_buflen = sizeof (pcall->call_buffer);
++pcall->call_id = pbuf;
++if (!addstrbfr (pstr->s, pstr->len, &pbuf, &pcall->call_buflen, 1))
++ { return 0; }
+ pstr = &pmsg->from->body;
+-strncpy (pcall->call_from, pstr->s, pstr->len);
+-pcall->call_from [pstr->len] = '\0';
+-*pcall->call_tag = '\0';
+-if (!pmsg->contact)
+- { *pcall->call_contact = '\0'; }
+-else
++pcall->call_from = pbuf;
++if (!addstrbfr (pstr->s, pstr->len, &pbuf, &pcall->call_buflen, 1))
++ { return 0; }
++pcall->call_contact = pbuf;
++if (pmsg->contact)
+ {
+ pstr = &pmsg->contact->body;
+- strncpy (pcall->call_contact, pstr->s, pstr->len);
+- pcall->call_contact [pstr->len] = '\0';
++ if (!addstrbfr (pstr->s, pstr->len, &pbuf, &pcall->call_buflen, 0))
++ { return 0; }
+ }
++if (!addstrbfr (0, 0, &pbuf, &pcall->call_buflen, 1))
++ { return 0; }
+
+ /**********
+ * extract Via headers
+ **********/
+
+-hdr_field_t *phdr = pmsg->h_via1;
+-if (phdr)
++pcall->call_via = pbuf;
++hdr_field_t *phdr;
++for (phdr = pmsg->h_via1; phdr; phdr = next_sibling_hdr (phdr))
+ {
+- int npos1 = 0;
+- while ((phdr = next_sibling_hdr (phdr)))
++ struct via_body *pvia;
++ char *pviabuf;
++ int npos;
++ for (pvia = (struct via_body *)phdr->parsed; pvia; pvia = pvia->next)
+ {
+- struct via_body *pvia;
+- char *pviabuf;
+- int bovrflow = 0;
+- int npos2;
+- int nvia_max = sizeof (pcall->call_via);
+- for (pvia = (struct via_body *)phdr->parsed; pvia; pvia = pvia->next)
++ /**********
++ * skip trailing whitespace
++ **********/
++
++ npos = pvia->bsize;
++ pviabuf = pvia->name.s;
++ while (npos)
+ {
+- /**********
+- * o skip trailing whitespace
+- * o check if overflow
+- **********/
++ --npos;
++ if (pviabuf [npos] == ' ' || pviabuf [npos] == '\r'
++ || pviabuf [npos] == '\n' || pviabuf [npos] == '\t'
++ || pviabuf [npos] == ',')
++ { continue; }
++ break;
++ }
+
+- npos2 = pvia->bsize;
+- pviabuf = pvia->name.s;
+- while (npos2)
+- {
+- --npos2;
+- if (pviabuf [npos2] == ' ' || pviabuf [npos2] == '\r'
+- || pviabuf [npos2] == '\n' || pviabuf [npos2] == '\t' || pviabuf [npos2] == ',')
+- { continue; }
+- break;
+- }
+- if ((npos2 + npos1 + 7) >= nvia_max)
+- {
+- LM_WARN ("%sVia buffer overflowed!", pfncname);
+- bovrflow = 1;
+- break;
+- }
++ /**********
++ * copy via
++ **********/
+
+- /**********
+- * copy via
+- **********/
++ if (!addstrbfr ("Via: ", 5, &pbuf, &pcall->call_buflen, 0))
++ { return 0; }
++ if (!addstrbfr (pviabuf, npos + 1, &pbuf, &pcall->call_buflen, 0))
++ { return 0; }
++ if (!addstrbfr (SIPEOL, 2, &pbuf, &pcall->call_buflen, 0))
++ { return 0; }
++ }
++ }
++if (!addstrbfr (0, 0, &pbuf, &pcall->call_buflen, 1))
++ { return 0; }
+
+- strcpy (&pcall->call_via [npos1], "Via: ");
+- npos1 += 5;
+- strncpy (&pcall->call_via [npos1], pviabuf, npos2);
+- npos1 += npos2;
+- strcpy (&pcall->call_via [npos1], SIPEOL);
+- npos1 += 2;
+- }
+- if (bovrflow)
+- { break; }
++/**********
++* extract Route headers
++**********/
++
++pcall->call_route = pbuf;
++struct hdr_field *proute;
++for (proute = pmsg->record_route; proute; proute = next_sibling_hdr (proute))
++ {
++ if (parse_rr (proute) < 0)
++ { return 0; }
++ rr_t *prouterr;
++ for (prouterr = proute->parsed; prouterr; prouterr = prouterr->next)
++ {
++ if (!addstrbfr ("Route: ", 7, &pbuf, &pcall->call_buflen, 0))
++ { return 0; }
++ if (!addstrbfr (prouterr->nameaddr.name.s, prouterr->len,
++ &pbuf, &pcall->call_buflen, 0))
++ { return 0; }
++ if (!addstrbfr (SIPEOL, 2, &pbuf, &pcall->call_buflen, 0))
++ { return 0; }
+ }
+ }
++if (!addstrbfr (0, 0, &pbuf, &pcall->call_buflen, 1))
++ { return 0; }
+
+ /**********
+-* o release call lock
++* o place tag at the end
+ * o update DB
+-* o lock MOH queue
+ **********/
+
++pcall->call_tag = pbuf;
++if (!addstrbfr (0, 0, &pbuf, &pcall->call_buflen, 1))
++ { return 0; }
+ pcall->call_state = CLSTA_ENTER;
+-mohq_lock_release (pmod_data->pcall_lock);
+ add_call_rec (ncall_idx);
+-mohq_lock_set (pmod_data->pmohq_lock, 0, 0);
+ mohq_debug (pcall->pmohq, "%sAdded call (%s) to queue (%s)",
+ pfncname, pcall->call_from, pcall->pmohq->mohq_name);
+-return ncall_idx;
++return 1;
+ }
+
+ /**********
+@@ -603,15 +636,15 @@ if (pcall->call_hash || pcall->call_label)
+ {
+ if (ptm->t_lookup_ident (&ptrans, pcall->call_hash, pcall->call_label) < 0)
+ {
+- LM_ERR ("%sLookup transaction failed for call (%s)!\n", pfncname,
+- pcall->call_from);
++ LM_ERR ("%sLookup transaction failed for call (%s) from queue (%s)!\n",
++ pfncname, pcall->call_from, pcall->pmohq->mohq_name);
+ }
+ else
+ {
+ if (ptm->t_release (pcall->call_pmsg) < 0)
+ {
+- LM_ERR ("%sRelease transaction failed for call (%s)!\n",
+- pfncname, pcall->call_from);
++ LM_ERR ("%sRelease transaction failed for call (%s) from queue (%s)!\n",
++ pfncname, pcall->call_from, pcall->pmohq->mohq_name);
+ }
+ }
+ pcall->call_hash = pcall->call_label = 0;
+@@ -620,14 +653,21 @@ if (pcall->call_hash || pcall->call_label)
+ /**********
+ * o update DB
+ * o inactivate slot
+-* o release MOH queue
+ **********/
+
+-mohq_debug (pcall->pmohq, "delete_call: Deleting call (%s) from queue (%s)",
+- pcall->call_from, pcall->pmohq->mohq_name);
+-delete_call_rec (pcall);
+-pcall->call_active = 0;
+-mohq_lock_release (pmod_data->pmohq_lock);
++if (!mohq_lock_set (pmod_data->pcall_lock, 1, 5000))
++ {
++ LM_ERR ("%sUnable to set call lock for call (%s) from queue (%s)!\n",
++ pfncname, pcall->call_from, pcall->pmohq->mohq_name);
++ }
++else
++ {
++ mohq_debug (pcall->pmohq, "%sDeleting call (%s) from queue (%s)",
++ pfncname, pcall->call_from, pcall->pmohq->mohq_name);
++ delete_call_rec (pcall);
++ mohq_lock_release (pmod_data->pcall_lock);
++ }
++pcall->call_state = 0;
+ return;
+ }
+
+@@ -663,7 +703,7 @@ if (ptm->t_newtran (pmsg) < 0)
+ }
+ if (!add_lump_rpl2 (pmsg, pallowhdr->s, pallowhdr->len, LUMP_RPL_HDR))
+ { LM_ERR ("%sUnable to add Allow header!\n", pfncname); }
+-LM_ERR ("%sRefused %.*s for call (%s)!", pfncname,
++LM_ERR ("%sRefused %.*s for call (%s)!\n", pfncname,
+ STR_FMT (&REQ_LINE (pmsg).method), pcall->call_from);
+ if (ptm->t_reply (pmsg, 405, presp_noallow->s) < 0)
+ {
+@@ -674,7 +714,7 @@ return;
+ }
+
+ /**********
+-* Drop the Call
++* End RTP
+ *
+ * INPUT:
+ * Arg (1) = SIP message pointer
+@@ -682,16 +722,15 @@ return;
+ * OUTPUT: none
+ **********/
+
+-void drop_call (sip_msg_t *pmsg, call_lst *pcall)
++void end_RTP (sip_msg_t *pmsg, call_lst *pcall)
+
+ {
+ /**********
+-* o destroy proxy connection
+-* o delete call
++* destroy RTP connection
+ **********/
+
+-char *pfncname = "drop_call: ";
+-if (pmsg != FAKED_REPLY)
++char *pfncname = "end_RTP: ";
++if ((pmsg != FAKED_REPLY) && (pcall->call_state != CLSTA_ENTER))
+ {
+ mohq_debug (pcall->pmohq, "%sDestroying RTP link for call (%s)",
+ pfncname, pcall->call_from);
+@@ -701,7 +740,6 @@ if (pmsg != FAKED_REPLY)
+ pfncname, pcall->call_from);
+ }
+ }
+-delete_call (pcall);
+ return;
+ }
+
+@@ -710,62 +748,37 @@ return;
+ *
+ * INPUT:
+ * Arg (1) = SIP message pointer
+-* Arg (2) = pointer to call pointer
+-* OUTPUT: queue index; -1 if unable to find
++* Arg (2) = queue index
++* OUTPUT: call pointer; =0 if unable to find/create
+ **********/
+
+-int find_call (sip_msg_t *pmsg, call_lst **ppcall)
++call_lst *find_call (sip_msg_t *pmsg, int mohq_idx)
+
+ {
+ /**********
+-* o find current RURI
+-* o strip off parms or headers
+-* o search MOH queue
+-**********/
+-
+-str *pruri =
+- pmsg->new_uri.s ? &pmsg->new_uri : &pmsg->first_line.u.request.uri;
+-int nidx;
+-str pstr [1];
+-pstr->s = pruri->s;
+-pstr->len = pruri->len;
+-for (nidx = 0; nidx < pruri->len; nidx++)
+- {
+- if (pstr->s [nidx] == ';' || pstr->s [nidx] == '?')
+- {
+- pstr->len = nidx;
+- break;
+- }
+- }
+-mohq_lst *pqlst = pmod_data->pmohq_lst;
+-int nqidx;
+-for (nqidx = 0; nqidx < pmod_data->mohq_cnt; nqidx++)
+- {
+- str pmohstr [1];
+- pmohstr->s = pqlst [nqidx].mohq_uri;
+- pmohstr->len = strlen (pmohstr->s);
+- if (STR_EQ (*pmohstr, *pstr))
+- { break; }
+- }
+-*ppcall = 0;
+-if (nqidx == pmod_data->mohq_cnt)
+- { return -1;}
+-
+-/**********
+ * o get to tag
+ * o get callID
+-* o ignore to tag if CANCEL on first INVITE
+-* o search call queue
++* o search calls
+ **********/
+
++char *pfncname = "find_call: ";
+ str *ptotag = &(get_to (pmsg)->tag_value);
+ if (!ptotag->len)
+ { ptotag = 0; }
+ if (!pmsg->callid)
+- { return -1; }
++ {
++ LM_ERR ("%sNo call ID!\n", pfncname);
++ return 0;
++ }
+ str *pcallid = &pmsg->callid->body;
+ if (!pcallid)
+- { return -1; }
++ {
++ LM_ERR ("%sNo call ID!\n", pfncname);
++ return 0;
++ }
++int nopen = -1;
++int nidx;
++call_lst *pcall;
+ for (nidx = 0; nidx < pmod_data->call_cnt; nidx++)
+ {
+ /**********
+@@ -773,21 +786,25 @@ for (nidx = 0; nidx < pmod_data->call_cnt; nidx++)
+ * o call timed out on ACK?
+ * o callID matches?
+ * o to tag matches?
+- * o return call pointer
+ **********/
+
+- call_lst *pcall = &pmod_data->pcall_lst [nidx];
+- if (!pcall->call_active)
+- { continue; }
++ pcall = &pmod_data->pcall_lst [nidx];
++ if (!pcall->call_state)
++ {
++ nopen = nidx;
++ continue;
++ }
++#if 0 /* ??? need to handle */
+ if (pcall->call_time && (pcall->call_state < CLSTA_INQUEUE))
+ {
+ if ((pcall->call_time + 32) < time (0))
+ {
+- LM_ERR ("find_call: No ACK response for call (%s)\n", pcall->call_from);
++ LM_ERR ("%sNo ACK response for call (%s)!\n", pfncname, pcall->call_from);
+ delete_call (pcall);
+ continue;
+ }
+ }
++#endif /* ??? */
+ str tmpstr [1];
+ tmpstr->s = pcall->call_id;
+ tmpstr->len = strlen (tmpstr->s);
+@@ -800,31 +817,96 @@ for (nidx = 0; nidx < pmod_data->call_cnt; nidx++)
+ if (!STR_EQ (*tmpstr, *ptotag))
+ { continue; }
+ }
+- *ppcall = pcall;
+- return nqidx;
++ else
++ {
++ /**********
++ * match not allowed for INVITE
++ **********/
++
++ if (pmsg->REQ_METHOD == METHOD_INVITE)
++ { return 0; }
++ }
++ return pcall;
+ }
+
+ /**********
+-* first INVITE?
++* o first INVITE?
++* o create a new call record
+ **********/
+
+-if (pmsg->REQ_METHOD == METHOD_INVITE)
++if (pmsg->REQ_METHOD != METHOD_INVITE)
+ { return 0; }
+-return -1;
++if (ptotag)
++ { return 0; }
++if (nopen < 0)
++ {
++ LM_ERR ("%sNo call slots available!\n", pfncname);
++ return 0;
++ }
++pcall = &pmod_data->pcall_lst [nopen];
++if (!create_call (pmsg, pcall, nopen, mohq_idx))
++ { return 0; }
++return pcall;
+ }
+
+ /**********
+ * Find Queue
+ *
+ * INPUT:
++* Arg (1) = SIP message pointer
++* OUTPUT: queue index; -1 if unable to find
++**********/
++
++int find_queue (sip_msg_t *pmsg)
++
++{
++/**********
++* o find current RURI
++* o strip off parms or headers
++* o search queues
++**********/
++
++str *pruri =
++ pmsg->new_uri.s ? &pmsg->new_uri : &pmsg->first_line.u.request.uri;
++int nidx;
++str pstr [1];
++pstr->s = pruri->s;
++pstr->len = pruri->len;
++for (nidx = 0; nidx < pruri->len; nidx++)
++ {
++ if (pstr->s [nidx] == ';' || pstr->s [nidx] == '?')
++ {
++ pstr->len = nidx;
++ break;
++ }
++ }
++mohq_lst *pqlst = pmod_data->pmohq_lst;
++int nqidx;
++for (nqidx = 0; nqidx < pmod_data->mohq_cnt; nqidx++)
++ {
++ str pmohstr [1];
++ pmohstr->s = pqlst [nqidx].mohq_uri;
++ pmohstr->len = strlen (pmohstr->s);
++ if (STR_EQ (*pmohstr, *pstr))
++ { break; }
++ }
++if (nqidx == pmod_data->mohq_cnt)
++ { return -1;}
++return nqidx;
++}
++
++/**********
++* Find Queue Name
++*
++* INPUT:
+ * Arg (1) = queue name str pointer
+ * OUTPUT: queue index; -1 if unable to find
+ **********/
+
+-int find_queue (str *pqname)
++int find_qname (str *pqname)
+
+ {
+-char *pfncname = "find_queue: ";
++char *pfncname = "find_qname: ";
+ int nidx;
+ str tmpstr;
+ if (!mohq_lock_set (pmod_data->pmohq_lock, 0, 500))
+@@ -869,7 +951,7 @@ parse_to (pvalue->s, &pvalue->s [pvalue->len + 1], pref);
+ if (pref->error != PARSE_OK)
+ {
+ // should never happen
+- LM_ERR ("%sInvalid Referred-By URI (%.*s)!", pfncname, STR_FMT (pvalue));
++ LM_ERR ("%sInvalid Referred-By URI (%.*s)!\n", pfncname, STR_FMT (pvalue));
+ return -1;
+ }
+ if (pref->param_lst)
+@@ -884,7 +966,7 @@ str tmpstr;
+ struct to_body pfrom [1];
+ for (nidx = 0; nidx < pmod_data->call_cnt; nidx++)
+ {
+- if (!pmod_data->pcall_lst [nidx].call_active)
++ if (!pmod_data->pcall_lst [nidx].call_state)
+ { continue; }
+ tmpstr.s = pmod_data->pcall_lst [nidx].call_from;
+ tmpstr.len = strlen (tmpstr.s);
+@@ -892,7 +974,7 @@ for (nidx = 0; nidx < pmod_data->call_cnt; nidx++)
+ if (pfrom->error != PARSE_OK)
+ {
+ // should never happen
+- LM_ERR ("%sInvalid From URI (%.*s)!", pfncname, STR_FMT (&tmpstr));
++ LM_ERR ("%sInvalid From URI (%.*s)!\n", pfncname, STR_FMT (&tmpstr));
+ continue;
+ }
+ if (pfrom->param_lst)
+@@ -908,55 +990,65 @@ return -1;
+ *
+ * INPUT:
+ * Arg (1) = SIP message pointer
+-* Arg (2) = queue index
+-* OUTPUT: 0=failed
++* Arg (2) = call pointer
++* OUTPUT: none
+ **********/
+
+-int first_invite_msg (sip_msg_t *pmsg, int mohq_idx)
++void first_invite_msg (sip_msg_t *pmsg, call_lst *pcall)
+
+ {
+-/**********
+-* create call record
+-**********/
+-
+ char *pfncname = "first_invite_msg: ";
+-int ncall_idx = create_call (mohq_idx, pmsg);
+-if (ncall_idx == -1)
+- { return 0; }
+-call_lst *pcall = &pmod_data->pcall_lst [ncall_idx];
+
+ /**********
+ * o SDP exists?
+ * o accepts REFER?
+-* o send rtpproxy offer
++* o send RTP offer
+ **********/
+
+ if (!(pmsg->msg_flags & FL_SDP_BODY))
+ {
+ if (parse_sdp (pmsg))
+ {
+- LM_ERR ("%sINVITE lacks SDP (%s)!", pfncname, pcall->call_from);
++ if (pmod_data->psl->freply (pmsg, 488, presp_noaccept) < 0)
++ {
++ LM_ERR ("%sUnable to create reply!\n", pfncname);
++ return;
++ }
++ LM_ERR ("%sINVITE lacks SDP (%s) from queue (%s)!\n",
++ pfncname, pcall->call_from, pcall->pmohq->mohq_name);
+ delete_call (pcall);
+- return 0;
++ return;
+ }
+ }
+ if (pmsg->allow)
+ {
+ if (!search_hdr_ext (pmsg->allow, prefer))
+ {
+- LM_ERR ("%sMissing REFER support (%s)!", pfncname, pcall->call_from);
++ if (pmod_data->psl->freply (pmsg, 488, presp_noaccept) < 0)
++ {
++ LM_ERR ("%sUnable to create reply!\n", pfncname);
++ return;
++ }
++ LM_ERR ("%sMissing REFER support (%s) from queue (%s)!\n",
++ pfncname, pcall->call_from, pcall->pmohq->mohq_name);
+ delete_call (pcall);
+- return 0;
++ return;
+ }
+ }
+-mohq_debug (pcall->pmohq, "%sMaking offer for RTP link for call (%s)",
+- pfncname, pcall->call_from);
++mohq_debug (pcall->pmohq,
++ "%sMaking offer for RTP link for call (%s) from queue (%s)",
++ pfncname, pcall->call_from, pcall->pmohq->mohq_name);
+ if (pmod_data->fn_rtp_offer (pmsg, 0, 0) != 1)
+ {
+- LM_ERR ("%srtpproxy_offer refused for call (%s)!",
+- pfncname, pcall->call_from);
++ if (pmod_data->psl->freply (pmsg, 486, presp_busy) < 0)
++ {
++ LM_ERR ("%sUnable to create reply!\n", pfncname);
++ return;
++ }
++ LM_ERR ("%srtpproxy_offer refused for call (%s)!\n",
++ pfncname, pcall->call_from);
+ delete_call (pcall);
+- return 0;
++ return;
+ }
+
+ /**********
+@@ -969,10 +1061,11 @@ if (pmod_data->fn_rtp_offer (pmsg, 0, 0) != 1)
+ tm_api_t *ptm = pmod_data->ptm;
+ if (ptm->t_newtran (pmsg) < 0)
+ {
+- LM_ERR ("%sUnable to create new transaction for call (%s)!",
++ LM_ERR ("%sUnable to create new transaction for call (%s)!\n",
+ pfncname, pcall->call_from);
++ end_RTP (pmsg, pcall);
+ delete_call (pcall);
+- return 0;
++ return;
+ }
+ struct cell *ptrans = ptm->t_gett ();
+ pcall->call_hash = ptrans->hash_index;
+@@ -980,26 +1073,50 @@ pcall->call_label = ptrans->label;
+ str ptotag [1];
+ if (ptm->t_get_reply_totag (pmsg, ptotag) != 1)
+ {
+- LM_ERR ("%sUnable to create totag for call (%s)!",
++ LM_ERR ("%sUnable to create totag for call (%s)!\n",
+ pfncname, pcall->call_from);
+ if (ptm->t_reply (pmsg, 500, presp_srverr->s) < 0)
+- { LM_ERR ("%sUnable to reply to INVITE!", pfncname); }
++ { LM_ERR ("%sUnable to reply to INVITE!\n", pfncname); }
++ end_RTP (pmsg, pcall);
+ delete_call (pcall);
+- return 1;
++ return;
++ }
++char *pbuf = pcall->call_tag;
++if (!addstrbfr (ptotag->s, ptotag->len, &pbuf, &pcall->call_buflen, 1))
++ {
++ LM_ERR ("%sInsufficient buffer space for call (%s)!\n",
++ pfncname, pcall->call_from);
++ if (ptm->t_reply (pmsg, 500, presp_srverr->s) < 0)
++ { LM_ERR ("%sUnable to reply to INVITE!\n", pfncname); }
++ end_RTP (pmsg, pcall);
++ delete_call (pcall);
++ return;
+ }
+-strncpy (pcall->call_tag, ptotag->s, ptotag->len);
+-pcall->call_tag [ptotag->len] = '\0';
+ pcall->call_cseq = 1;
+ if (ptm->register_tmcb (pmsg, 0, TMCB_DESTROY | TMCB_ON_FAILURE,
+ invite_cb, pcall, 0) < 0)
+ {
+- LM_ERR ("%sUnable to set callback for call (%s)!",
++ LM_ERR ("%sUnable to set callback for call (%s)!\n",
+ pfncname, pcall->call_from);
+ if (ptm->t_reply (pmsg, 500, presp_srverr->s) < 0)
+- { LM_ERR ("%sUnable to reply to INVITE!", pfncname); }
++ { LM_ERR ("%sUnable to reply to INVITE!\n", pfncname); }
++ end_RTP (pmsg, pcall);
+ delete_call (pcall);
+- return 1;
++ return;
++ }
++
++/**********
++* reply with trying
++**********/
++
++if (ptm->t_reply (pmsg, 100, presp_trying->s) < 0)
++ {
++ LM_ERR ("%sUnable to create reply!\n", pfncname);
++ end_RTP (pmsg, pcall);
++ delete_call (pcall);
++ return;
+ }
++pcall->call_state = CLSTA_TRYING;
+
+ /**********
+ * o add contact to reply
+@@ -1009,19 +1126,20 @@ if (ptm->register_tmcb (pmsg, 0, TMCB_DESTROY | TMCB_ON_FAILURE,
+
+ str pcontact [1];
+ char *pcontacthdr = "Contact: <%s>" SIPEOL;
+-pcontact->s = pkg_malloc (strlen (pmod_data->pmohq_lst [mohq_idx].mohq_uri)
+- + strlen (pcontacthdr));
++pcontact->s
++ = pkg_malloc (strlen (pcall->pmohq->mohq_uri) + strlen (pcontacthdr));
+ if (!pcontact->s)
+ {
+- LM_ERR ("%sNo more memory!", pfncname);
++ LM_ERR ("%sNo more memory!\n", pfncname);
++ end_RTP (pmsg, pcall);
+ delete_call (pcall);
+- return 1;
++ return;
+ }
+-sprintf (pcontact->s, pcontacthdr, pmod_data->pmohq_lst [mohq_idx].mohq_uri);
++sprintf (pcontact->s, pcontacthdr, pcall->pmohq->mohq_uri);
+ pcontact->len = strlen (pcontact->s);
+ if (!add_lump_rpl2 (pmsg, pcontact->s, pcontact->len, LUMP_RPL_HDR))
+ {
+- LM_ERR ("%sUnable to add contact (%s) to call (%s)!",
++ LM_ERR ("%sUnable to add contact (%s) to call (%s)!\n",
+ pfncname, pcontact->s, pcall->call_from);
+ }
+ pkg_free (pcontact->s);
+@@ -1030,42 +1148,30 @@ if (search_hdr_ext (pmsg->require, p100rel))
+ {
+ if (!send_prov_rsp (pmsg, pcall))
+ {
++ end_RTP (pmsg, pcall);
+ delete_call (pcall);
+- return 1;
++ return;
+ }
+- }
+-else
+- {
+- if (ptm->t_reply (pmsg, 180, presp_ring->s) < 0)
+- {
+- LM_ERR ("%sUnable to reply to INVITE!", pfncname);
+- return 1;
+- }
+- else
++ if (pcall->call_state == CLSTA_CANCEL)
+ {
+- pcall->call_state = CLSTA_RINGING;
+- mohq_debug (pcall->pmohq, "%sSent RINGING for call (%s)",
+- pfncname, pcall->call_from);
++ end_RTP (pmsg, pcall);
++ delete_call (pcall);
++ return;
+ }
+ }
+
+ /**********
+-* o call cancelled?
+-* o accept call with RTP
++* accept call with RTP
+ **********/
+
+-if (pcall->call_state == CLSTA_CANCEL)
+- {
+- delete_call (pcall);
+- return 1;
+- }
+ if (!send_rtp_answer (pmsg, pcall))
+ {
+ if (pmod_data->psl->freply (pmsg, 500, presp_srverr) < 0)
+- { LM_ERR ("%sUnable to create reply!", pfncname); }
++ { LM_ERR ("%sUnable to create reply!\n", pfncname); }
++ end_RTP (pmsg, pcall);
+ delete_call (pcall);
+ }
+-return 1;
++return;
+ }
+
+ /**********
+@@ -1085,6 +1191,9 @@ dlg_t *form_dialog (call_lst *pcall, struct to_body *pto_body)
+ **********/
+
+ char *pfncname = "form_dialog: ";
++str pdsturi [1], ptarget [1];
++int index;
++name_addr_t pname [1];
+ struct to_body *ptob = &pto_body [0];
+ struct to_body *pcontact = &pto_body [1];
+ parse_to (pcall->call_from,
+@@ -1092,12 +1201,49 @@ parse_to (pcall->call_from,
+ if (ptob->error != PARSE_OK)
+ {
+ // should never happen
+- LM_ERR ("%sInvalid from URI (%s)!", pfncname, pcall->call_from);
++ LM_ERR ("%sInvalid from URI (%s)!\n", pfncname, pcall->call_from);
+ return 0;
+ }
+ if (ptob->param_lst)
+ { free_to_params (ptob); }
+-str ptarget [1];
++
++/**********
++* form dest URI from record route
++**********/
++
++if (!*pcall->call_route)
++ { pdsturi->s = 0; }
++else
++ {
++ /**********
++ * o find first route URI
++ * o strip off parameter
++ **********/
++
++ pdsturi->s = pcall->call_route;
++ pdsturi->len = strlen (pcall->call_route);
++ if (parse_nameaddr (pdsturi, pname) < 0)
++ {
++ // should never happen
++ LM_ERR ("%sUnable to parse route (%s)!\n", pfncname, pcall->call_from);
++ return 0;
++ }
++ pdsturi->s = pname->uri.s;
++ pdsturi->len = pname->uri.len;
++ for (index = 1; index < pdsturi->len; index++)
++ {
++ if (pdsturi->s [index] == ';')
++ {
++ pdsturi->len = index;
++ break;
++ }
++ }
++ }
++
++/**********
++* form target URI
++**********/
++
+ if (!*pcall->call_contact)
+ {
+ ptarget->s = ptob->uri.s;
+@@ -1110,7 +1256,7 @@ else
+ if (pcontact->error != PARSE_OK)
+ {
+ // should never happen
+- LM_ERR ("%sInvalid contact (%s) for call (%s)!", pfncname,
++ LM_ERR ("%sInvalid contact (%s) for call (%s)!\n", pfncname,
+ pcall->call_contact, pcall->call_from);
+ return 0;
+ }
+@@ -1127,7 +1273,7 @@ else
+ dlg_t *pdlg = (dlg_t *)pkg_malloc (sizeof (dlg_t));
+ if (!pdlg)
+ {
+- LM_ERR ("%sNo more memory!", pfncname);
++ LM_ERR ("%sNo more memory!\n", pfncname);
+ return 0;
+ }
+ memset (pdlg, 0, sizeof (dlg_t));
+@@ -1145,6 +1291,11 @@ pdlg->loc_uri.s = pcall->pmohq->mohq_uri;
+ pdlg->loc_uri.len = strlen (pdlg->loc_uri.s);
+ pdlg->rem_uri.s = ptob->uri.s;
+ pdlg->rem_uri.len = ptob->uri.len;
++if (pdsturi->s)
++ {
++ pdlg->dst_uri.s = pdsturi->s;
++ pdlg->dst_uri.len = pdsturi->len;
++ }
+ return pdlg;
+ }
+
+@@ -1171,7 +1322,7 @@ rtpmap **pmohfiles = find_MOH (pcall->pmohq->mohq_mohdir,
+ pcall->pmohq->mohq_mohfile);
+ if (!pmohfiles [0])
+ {
+- LM_ERR ("%sUnable to find any MOH files for queue (%s)!", pfncname,
++ LM_ERR ("%sUnable to find any MOH files for queue (%s)!\n", pfncname,
+ pcall->pmohq->mohq_name);
+ return 0;
+ }
+@@ -1191,7 +1342,7 @@ for (nidx = 0; pmohfiles [nidx]; nidx++)
+ pstr->s = pkg_malloc (nsize + 1);
+ if (!pstr->s)
+ {
+- LM_ERR ("%sNo more memory!", pfncname);
++ LM_ERR ("%sNo more memory!\n", pfncname);
+ return 0;
+ }
+ strcpy (pstr->s, pSDP);
+@@ -1238,7 +1389,7 @@ static void
+ call_lst *pcall = (call_lst *)*pcbp->param;
+ if (ntype == TMCB_DESTROY)
+ { pcall->call_hash = pcall->call_label = 0; }
+-LM_ERR ("invite_cb: INVITE failed for call (%s)!", pcall->call_from);
++LM_ERR ("invite_cb: INVITE failed for call (%s)!\n", pcall->call_from);
+ delete_call (pcall);
+ return;
+ }
+@@ -1249,10 +1400,10 @@ return;
+ * INPUT:
+ * Arg (1) = SIP message pointer
+ * Arg (2) = call pointer
+-* OUTPUT: 0=failed
++* OUTPUT: none
+ **********/
+
+-int notify_msg (sip_msg_t *pmsg, call_lst *pcall)
++void notify_msg (sip_msg_t *pmsg, call_lst *pcall)
+
+ {
+ /**********
+@@ -1262,11 +1413,11 @@ int notify_msg (sip_msg_t *pmsg, call_lst *pcall)
+ char *pfncname = "notify_msg: ";
+ if (pcall->call_state != CLSTA_RFRWAIT)
+ {
+- LM_ERR ("%sNot waiting on a REFER for call (%s)!", pfncname,
++ LM_ERR ("%sNot waiting on a REFER for call (%s)!\n", pfncname,
+ pcall->call_from);
+ if (pmod_data->psl->freply (pmsg, 481, presp_nocall) < 0)
+- { LM_ERR ("%sUnable to create reply!", pfncname); }
+- return 1;
++ { LM_ERR ("%sUnable to create reply!\n", pfncname); }
++ return;
+ }
+
+ /**********
+@@ -1277,28 +1428,28 @@ if (pcall->call_state != CLSTA_RFRWAIT)
+
+ if (!search_hdr_ext (pmsg->content_type, psipfrag))
+ {
+- LM_ERR ("%sNot a %s type for call (%s)!", pfncname,
++ LM_ERR ("%sNot a %s type for call (%s)!\n", pfncname,
+ psipfrag->s, pcall->call_from);
+ if (pmod_data->psl->freply (pmsg, 415, presp_unsupp) < 0)
+- { LM_ERR ("%sUnable to create reply!", pfncname); }
+- return 1;
++ { LM_ERR ("%sUnable to create reply!\n", pfncname); }
++ return;
+ }
+ char *pfrag = get_body (pmsg);
+ if (!pfrag)
+ {
+- LM_ERR ("%s%s body missing for call (%s)!", pfncname,
++ LM_ERR ("%s%s body missing for call (%s)!\n", pfncname,
+ psipfrag->s, pcall->call_from);
+ if (pmod_data->psl->freply (pmsg, 415, presp_unsupp) < 0)
+- { LM_ERR ("%sUnable to create reply!", pfncname); }
+- return 1;
++ { LM_ERR ("%sUnable to create reply!\n", pfncname); }
++ return;
+ }
+ str pbody [1];
+ pbody->len = pmsg->len - (int)(pfrag - pmsg->buf);
+ pbody->s = pkg_malloc (pbody->len + 2);
+ if (!pbody->s)
+ {
+- LM_ERR ("%sNo more memory!", pfncname);
+- return 1;
++ LM_ERR ("%sNo more memory!\n", pfncname);
++ return;
+ }
+ strncpy (pbody->s, pfrag, pbody->len);
+ if (pbody->s [pbody->len - 1] != '\n')
+@@ -1311,10 +1462,10 @@ parse_first_line (pbody->s, pbody->len + 1, pstart);
+ pkg_free (pbody->s);
+ if (pstart->type != SIP_REPLY)
+ {
+- LM_ERR ("%sReply missing for call (%s)!", pfncname, pcall->call_from);
++ LM_ERR ("%sReply missing for call (%s)!\n", pfncname, pcall->call_from);
+ if (pmod_data->psl->freply (pmsg, 415, presp_unsupp) < 0)
+- { LM_ERR ("%sUnable to create reply!", pfncname); }
+- return 1;
++ { LM_ERR ("%sUnable to create reply!\n", pfncname); }
++ return;
+ }
+
+ /**********
+@@ -1322,32 +1473,34 @@ if (pstart->type != SIP_REPLY)
+ * o REFER done?
+ **********/
+
++int nreply = pstart->u.reply.statuscode;
+ if (pmod_data->psl->freply (pmsg, 200, presp_ok) < 0)
+ {
+- LM_ERR ("%sUnable to create reply for call (%s)!",
++ LM_ERR ("%sUnable to create reply for call (%s)!\n",
+ pfncname, pcall->call_from);
+- return 1;
++ return;
+ }
+-int nreply = pstart->u.reply.statuscode;
+ mohq_debug (pcall->pmohq, "%sNOTIFY received reply (%d) for call (%s)",
+ pfncname, nreply, pcall->call_from);
+ switch (nreply / 100)
+ {
+ case 1:
++ pcall->refer_time = time (0);
+ break;
+ case 2:
+ close_call (pmsg, pcall);
+ break;
+ default:
+- LM_WARN ("%sUnable to redirect call (%s)!", pfncname, pcall->call_from);
++ LM_WARN ("%sUnable to redirect call (%s)\n", pfncname, pcall->call_from);
+ if (nreply == 487)
+ {
+ /**********
+- * call was canceled
++ * call was cancelled
+ **********/
+
+- drop_call (pmsg, pcall);
+- return 1;
++ end_RTP (pmsg, pcall);
++ delete_call (pcall);
++ return;
+ }
+
+ /**********
+@@ -1358,7 +1511,7 @@ switch (nreply / 100)
+ update_call_rec (pcall);
+ break;
+ }
+-return 1;
++return;
+ }
+
+ /**********
+@@ -1367,10 +1520,10 @@ return 1;
+ * INPUT:
+ * Arg (1) = SIP message pointer
+ * Arg (2) = call pointer
+-* OUTPUT: 0=failed
++* OUTPUT: none
+ **********/
+
+-int prack_msg (sip_msg_t *pmsg, call_lst *pcall)
++void prack_msg (sip_msg_t *pmsg, call_lst *pcall)
+
+ {
+ /**********
+@@ -1381,10 +1534,10 @@ char *pfncname = "prack_msg: ";
+ tm_api_t *ptm = pmod_data->ptm;
+ if (pcall->call_state != CLSTA_PRACKSTRT)
+ {
+- LM_ERR ("%sUnexpected PRACK (%s)!", pfncname, pcall->call_from);
++ LM_ERR ("%sUnexpected PRACK (%s)!\n", pfncname, pcall->call_from);
+ if (pmod_data->psl->freply (pmsg, 481, presp_nocall) < 0)
+- { LM_ERR ("%sUnable to create reply!", pfncname); }
+- return 1;
++ { LM_ERR ("%sUnable to create reply!\n", pfncname); }
++ return;
+ }
+
+ /**********
+@@ -1394,20 +1547,20 @@ if (pcall->call_state != CLSTA_PRACKSTRT)
+
+ if (ptm->t_newtran (pmsg) < 0)
+ {
+- LM_ERR ("%sUnable to create new transaction for call (%s)!",
++ LM_ERR ("%sUnable to create new transaction for call (%s)!\n",
+ pfncname, pcall->call_from);
+ if (pmod_data->psl->freply (pmsg, 500, presp_srverr) < 0)
+- { LM_ERR ("%sUnable to create reply!", pfncname); }
+- return 1;
++ { LM_ERR ("%sUnable to create reply!\n", pfncname); }
++ return;
+ }
+ if (ptm->t_reply (pmsg, 200, presp_ok->s) < 0)
+ {
+- LM_ERR ("%sUnable to reply to PRACK for call (%s)!",
++ LM_ERR ("%sUnable to reply to PRACK for call (%s)!\n",
+ pfncname, pcall->call_from);
+- return 1;
++ return;
+ }
+ pcall->call_state = CLSTA_PRACKRPLY;
+-return 1;
++return;
+ }
+
+ /**********
+@@ -1448,18 +1601,22 @@ puri->s = pcall->call_referto;
+ puri->len = strlen (puri->s);
+ int npos1 = sizeof (prefermsg) // REFER template
+ + strlen (pcall->call_via) // Via
++ + strlen (pcall->call_route) // Route
++ + strlen (pcall->pmohq->mohq_uri) // Contact
+ + puri->len // Refer-To
+- + ptob->uri.len; // Referred-By
++ + strlen (pcall->pmohq->mohq_uri); // Referred-By
+ char *pbuf = pkg_malloc (npos1);
+ if (!pbuf)
+ {
+- LM_ERR ("%sNo more memory!", pfncname);
++ LM_ERR ("%sNo more memory!\n", pfncname);
+ goto refererr;
+ }
+ sprintf (pbuf, prefermsg,
+ pcall->call_via, // Via
++ pcall->call_route, // Route
++ pcall->pmohq->mohq_uri, // Contact
+ puri->s, // Refer-To
+- STR_FMT (&ptob->uri)); // Referred-By
++ pcall->pmohq->mohq_uri); // Referred-By
+
+ /**********
+ * send REFER request
+@@ -1472,13 +1629,14 @@ phdrs->s = pbuf;
+ phdrs->len = strlen (pbuf);
+ set_uac_req (puac, prefer, phdrs, 0, pdlg,
+ TMCB_LOCAL_COMPLETED | TMCB_ON_FAILURE, refer_cb, pcall);
++pcall->refer_time = time (0);
+ pcall->call_state = CLSTA_REFER;
+ update_call_rec (pcall);
+ mohq_lock_release (plock);
+ if (ptm->t_request_within (puac) < 0)
+ {
+ pcall->call_state = CLSTA_INQUEUE;
+- LM_ERR ("%sUnable to create REFER request for call (%s)!",
++ LM_ERR ("%sUnable to create REFER request for call (%s)!\n",
+ pfncname, pcall->call_from);
+ update_call_rec (pcall);
+ goto refererr;
+@@ -1512,21 +1670,23 @@ char *pfncname = "refer_cb: ";
+ call_lst *pcall = (call_lst *)*pcbp->param;
+ if ((ntype == TMCB_ON_FAILURE) || (pcbp->req == FAKED_REPLY))
+ {
+- LM_ERR ("%sCall (%s) did not respond to REFER", pfncname,
++ LM_ERR ("%sCall (%s) did not respond to REFER!\n", pfncname,
+ pcall->call_from);
+- drop_call (pcbp->req, pcall);
++ end_RTP (pcbp->req, pcall);
++ delete_call (pcall);
+ return;
+ }
+ int nreply = pcbp->code;
+ if ((nreply / 100) == 2)
+ {
++ pcall->refer_time = time (0);
+ pcall->call_state = CLSTA_RFRWAIT;
+ mohq_debug (pcall->pmohq, "%sCall (%s) REFER reply=%d",
+ pfncname, pcall->call_from, nreply);
+ }
+ else
+ {
+- LM_ERR ("%sCall (%s) REFER error (%d)", pfncname,
++ LM_ERR ("%sCall (%s) REFER error (%d)!\n", pfncname,
+ pcall->call_from, nreply);
+ if (nreply == 481)
+ { delete_call (pcall); }
+@@ -1545,10 +1705,10 @@ return;
+ * INPUT:
+ * Arg (1) = SIP message pointer
+ * Arg (2) = call pointer
+-* OUTPUT: 0=failed
++* OUTPUT: none
+ **********/
+
+-int reinvite_msg (sip_msg_t *pmsg, call_lst *pcall)
++void reinvite_msg (sip_msg_t *pmsg, call_lst *pcall)
+
+ {
+ /**********
+@@ -1563,17 +1723,17 @@ if ((pcall->call_state / 100) < 2)
+ mohq_debug (pcall->pmohq, "%sINVITE still pending for call (%s)",
+ pfncname, pcall->call_from);
+ if (pmod_data->psl->freply (pmsg, 491, presp_reqpend) < 0)
+- { LM_ERR ("%sUnable to create reply!", pfncname); }
+- return 1;
++ { LM_ERR ("%sUnable to create reply!\n", pfncname); }
++ return;
+ }
+ if (!(pmsg->msg_flags & FL_SDP_BODY))
+ {
+ if (parse_sdp (pmsg))
+ {
+- LM_ERR ("%sre-INVITE lacks SDP (%s)!", pfncname, pcall->call_from);
++ LM_ERR ("%sre-INVITE lacks SDP (%s)!\n", pfncname, pcall->call_from);
+ if (pmod_data->psl->freply (pmsg, 488, presp_noaccept) < 0)
+- { LM_ERR ("%sUnable to create reply!", pfncname); }
+- return 1;
++ { LM_ERR ("%sUnable to create reply!\n", pfncname); }
++ return;
+ }
+ }
+
+@@ -1643,12 +1803,12 @@ if (!bhold)
+ {
+ if (!bmatch)
+ {
+- LM_ERR ("%sre-INVITE refused because no matching payload for call (%s)!",
++ LM_ERR ("%sre-INVITE refused because no matching payload for call (%s)!\n",
+ pfncname, pcall->call_from);
+ if (pmod_data->psl->freply (pmsg, 488, presp_noaccept) < 0)
+ {
+- LM_ERR ("%sUnable to create reply!", pfncname);
+- return 1;
++ LM_ERR ("%sUnable to create reply!\n", pfncname);
++ return;
+ }
+ }
+ else
+@@ -1657,26 +1817,26 @@ if (!bhold)
+ pfncname, pcall->call_from);
+ if (pmod_data->psl->freply (pmsg, 200, presp_ok) < 0)
+ {
+- LM_ERR ("%sUnable to create reply!", pfncname);
+- return 1;
++ LM_ERR ("%sUnable to create reply!\n", pfncname);
++ return;
+ }
+ }
+- return 1;
++ return;
+ }
+
+ /**********
+ * hold not allowed, say good-bye
+ **********/
+
+-LM_ERR ("%sTerminating call (%s) because hold not allowed!",
++LM_ERR ("%sTerminating call (%s) because hold not allowed!\n",
+ pfncname, pcall->call_from);
+ if (pmod_data->psl->freply (pmsg, 200, presp_ok) < 0)
+ {
+- LM_ERR ("%sUnable to create reply!", pfncname);
+- return 1;
++ LM_ERR ("%sUnable to create reply!\n", pfncname);
++ return;
+ }
+ close_call (pmsg, pcall);
+-return 1;
++return;
+ }
+
+ /**********
+@@ -1744,22 +1904,21 @@ char *phdrtmplt =
+ "Accept-Language: en" SIPEOL
+ "Require: 100rel" SIPEOL
+ "RSeq: %d" SIPEOL
+- "User-Agent: " USRAGNT SIPEOL
+ ;
+ sprintf (phdrtmp, phdrtmplt, pcall->call_cseq);
+ struct lump_rpl **phdrlump = add_lump_rpl2 (pmsg, phdrtmp,
+ strlen (phdrtmp), LUMP_RPL_HDR);
+ if (!phdrlump)
+ {
+- LM_ERR ("%sUnable to create new header for call (%s)!",
++ LM_ERR ("%sUnable to create new header for call (%s)!\n",
+ pfncname, pcall->call_from);
+ if (pmod_data->psl->freply (pmsg, 500, presp_srverr) < 0)
+- { LM_ERR ("%sUnable to create reply!", pfncname); }
++ { LM_ERR ("%sUnable to create reply!\n", pfncname); }
+ return 0;
+ }
+ if (ptm->t_reply (pmsg, 180, presp_ring->s) < 0)
+ {
+- LM_ERR ("%sUnable to reply to INVITE for call (%s)",
++ LM_ERR ("%sUnable to reply to INVITE for call (%s)!\n",
+ pfncname, pcall->call_from);
+ return 0;
+ }
+@@ -1780,7 +1939,7 @@ while (1)
+ { break; }
+ if (nstart < time (0))
+ {
+- LM_ERR ("%sNo PRACK response for call (%s)",
++ LM_ERR ("%sNo PRACK response for call (%s)!\n",
+ pfncname, pcall->call_from);
+ break;
+ }
+@@ -1820,7 +1979,7 @@ pbuf->s = build_res_buf_from_sip_req (200, presp_ok, ptotag, ptrans->uas.request
+ (unsigned int *)&pbuf->len, pBM);
+ if (!pbuf->s || !pbuf->len)
+ {
+- LM_ERR ("%sUnable to create SDP response for call (%s)!",
++ LM_ERR ("%sUnable to create SDP response for call (%s)!\n",
+ pfncname, pcall->call_from);
+ return 0;
+ }
+@@ -1893,7 +2052,7 @@ npos1 += pextrahdr->len + strlen (pbodylen) + pSDP->len + 1;
+ char *pnewbuf = pkg_malloc (npos1);
+ if (!pnewbuf)
+ {
+- LM_ERR ("%sNo more memory!", pfncname);
++ LM_ERR ("%sNo more memory!\n", pfncname);
+ goto answer_done;
+ }
+ for (npos1 = npos2 = 0; npos2 < nhdrcnt; npos2++)
+@@ -1923,7 +2082,7 @@ build_sip_msg_from_buf (pnmsg, pbuf->s, pbuf->len, 0);
+ memcpy (&pnmsg->rcv, &pmsg->rcv, sizeof (struct receive_info));
+
+ /**********
+-* o send rtpproxy answer
++* o send RTP answer
+ * o form stream file
+ * o send stream
+ **********/
+@@ -1932,7 +2091,7 @@ mohq_debug (pcall->pmohq, "%sAnswering RTP link for call (%s)",
+ pfncname, pcall->call_from);
+ if (pmod_data->fn_rtp_answer (pnmsg, 0, 0) != 1)
+ {
+- LM_ERR ("%srtpproxy_answer refused for call (%s)!",
++ LM_ERR ("%srtpproxy_answer refused for call (%s)!\n",
+ pfncname, pcall->call_from);
+ goto answer_done;
+ }
+@@ -1949,7 +2108,7 @@ pkg_free (pnewbuf);
+ free_sip_msg (pnmsg);
+ if (!pbuf->s || !pbuf->len)
+ {
+- LM_ERR ("%sUnable to create SDP response for call (%s)!",
++ LM_ERR ("%sUnable to create SDP response for call (%s)!\n",
+ pfncname, pcall->call_from);
+ goto answer_done;
+ }
+@@ -1973,26 +2132,26 @@ char *pfnd = strstr (pnewSDP->s, "m=audio ");
+ if (!pfnd)
+ {
+ // should not happen
+- LM_ERR ("%sUnable to find audio port for call (%s)!",
++ LM_ERR ("%sUnable to find audio port for call (%s)!\n",
+ pfncname, pcall->call_from);
+ goto answer_done;
+ }
+ pcall->call_aport = strtol (pfnd + 8, NULL, 10);
+ if (!add_lump_rpl2 (pmsg, pextrahdr->s, pextrahdr->len, LUMP_RPL_HDR))
+ {
+- LM_ERR ("%sUnable to add header for call (%s)!",
++ LM_ERR ("%sUnable to add header for call (%s)!\n",
+ pfncname, pcall->call_from);
+ goto answer_done;
+ }
+ if (!add_lump_rpl2 (pmsg, pnewSDP->s, pnewSDP->len, LUMP_RPL_BODY))
+ {
+- LM_ERR ("%sUnable to add SDP body for call (%s)!",
++ LM_ERR ("%sUnable to add SDP body for call (%s)!\n",
+ pfncname, pcall->call_from);
+ goto answer_done;
+ }
+ if (ptm->t_reply (pmsg, 200, presp_ok->s) < 0)
+ {
+- LM_ERR ("%sUnable to reply to INVITE for call (%s)!",
++ LM_ERR ("%sUnable to reply to INVITE for call (%s)!\n",
+ pfncname, pcall->call_from);
+ goto answer_done;
+ }
+@@ -2041,7 +2200,34 @@ mohq_debug (pcall->pmohq, "%sStarting RTP link for call (%s)",
+ pfncname, pcall->call_from);
+ if (fn_stream (pmsg, (char *)pmodel, (char *)-1) != 1)
+ {
+- LM_ERR ("%srtpproxy_stream refused for call (%s)!",
++ LM_ERR ("%srtpproxy_stream refused for call (%s)!\n",
++ pfncname, pcall->call_from);
++ return 0;
++ }
++return 1;
++}
++
++/**********
++* Stop Streaming
++*
++* INPUT:
++* Arg (1) = SIP message pointer
++* Arg (2) = call pointer
++* Arg (3) = server flag
++* OUTPUT: 0 if failed
++**********/
++
++int stop_stream (sip_msg_t *pmsg, call_lst *pcall, int bserver)
++
++{
++char *pfncname = "stop_stream: ";
++cmd_function fn_stop = bserver ? pmod_data->fn_rtp_stop_s
++ : pmod_data->fn_rtp_stop_c;
++mohq_debug (pcall->pmohq, "%sStopping RTP link for call (%s)",
++ pfncname, pcall->call_from);
++if (fn_stop (pmsg, (char *)-1, (char *)-1) != 1)
++ {
++ LM_ERR ("%srtpproxy_stop refused for call (%s)!\n",
+ pfncname, pcall->call_from);
+ return 0;
+ }
+@@ -2062,7 +2248,7 @@ char *form_tmpstr (str *pstr)
+ char *pcstr = malloc (pstr->len + 1);
+ if (!pcstr)
+ {
+- LM_ERR ("No more memory!");
++ LM_ERR ("No more memory!\n");
+ return NULL;
+ }
+ memcpy (pcstr, pstr->s, pstr->len);
+@@ -2162,7 +2348,7 @@ struct mi_root *mi_debug (struct mi_root *pcmd_tree, void *parms)
+ struct mi_node *pnode = pcmd_tree->node.kids;
+ if (!pnode || !pnode->next || pnode->next->next)
+ { return init_mi_tree (400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); }
+-int nq_idx = find_queue (&pnode->value);
++int nq_idx = find_qname (&pnode->value);
+ if (nq_idx == -1)
+ { return init_mi_tree (400, pmi_noqueue->s, pmi_noqueue->len); }
+ char pint [20];
+@@ -2215,7 +2401,7 @@ struct mi_root *mi_drop_call (struct mi_root *pcmd_tree, void *parms)
+ struct mi_node *pnode = pcmd_tree->node.kids;
+ if (!pnode || !pnode->next || pnode->next->next)
+ { return init_mi_tree (400, MI_MISSING_PARM_S, MI_MISSING_PARM_LEN); }
+-int nq_idx = find_queue (&pnode->value);
++int nq_idx = find_qname (&pnode->value);
+ if (nq_idx == -1)
+ { return init_mi_tree (400, pmi_noqueue->s, pmi_noqueue->len); }
+ if (!mohq_lock_set (pmod_data->pcall_lock, 0, 5000))
+@@ -2238,7 +2424,7 @@ for (nidx = 0; nidx < pmod_data->call_cnt; nidx++)
+ **********/
+
+ call_lst *pcall = &pmod_data->pcall_lst [nidx];
+- if (!pcall->call_active)
++ if (!pcall->call_state)
+ { continue; }
+ if (pqueue->mohq_id != pcall->pmohq->mohq_id)
+ { continue; }
+@@ -2277,12 +2463,12 @@ char *pfncname = "mohq_count: ";
+ str pqname [1];
+ if (!pqueue || !presult)
+ {
+- LM_ERR ("%sParameters missing!", pfncname);
++ LM_ERR ("%sParameters missing!\n", pfncname);
+ return -1;
+ }
+ if (fixup_get_svalue (pmsg, (gparam_p)pqueue, pqname))
+ {
+- LM_ERR ("%sInvalid queue name!", pfncname);
++ LM_ERR ("%sInvalid queue name!\n", pfncname);
+ return -1;
+ }
+
+@@ -2292,12 +2478,12 @@ if (fixup_get_svalue (pmsg, (gparam_p)pqueue, pqname))
+ * o count items in queue
+ **********/
+
+-int nq_idx = find_queue (pqname);
++int nq_idx = find_qname (pqname);
+ int ncount = 0;
+ call_lst *pcalls = pmod_data->pcall_lst;
+ int ncall_idx, mohq_id;
+ if (!mohq_lock_set (pmod_data->pcall_lock, 0, 200))
+- { LM_ERR ("%sUnable to lock calls!", pfncname); }
++ { LM_ERR ("%sUnable to lock calls!\n", pfncname); }
+ else
+ {
+ if (nq_idx != -1)
+@@ -2305,7 +2491,7 @@ else
+ mohq_id = pmod_data->pmohq_lst [nq_idx].mohq_id;
+ for (ncall_idx = 0; ncall_idx < pmod_data->call_cnt; ncall_idx++)
+ {
+- if (!pcalls [ncall_idx].call_active)
++ if (!pcalls [ncall_idx].call_state)
+ { continue; }
+ if (pcalls [ncall_idx].pmohq->mohq_id == mohq_id
+ && pcalls [ncall_idx].call_state == CLSTA_INQUEUE)
+@@ -2326,7 +2512,7 @@ pavp_val->ri = ncount;
+ pavp_val->flags = PV_TYPE_INT | PV_VAL_INT;
+ if (presult->setf (pmsg, &presult->pvp, (int)EQ_T, pavp_val) < 0)
+ {
+- LM_ERR ("%sUnable to set pv value for mohq_count ()!", pfncname);
++ LM_ERR ("%sUnable to set pv value for mohq_count ()!\n", pfncname);
+ return -1;
+ }
+ return 1;
+@@ -2364,7 +2550,7 @@ va_list ap;
+ va_start (ap, pfmt);
+ vsnprintf (ptext, sizeof (ptext), pfmt, ap);
+ va_end (ap);
+-LM_DBG ("%s", ptext);
++LM_DBG ("%s\n", ptext);
+ if (nsys_log < nmohq_log)
+ { reset_local_debug_level (); }
+ return;
+@@ -2375,39 +2561,28 @@ return;
+ *
+ * INPUT:
+ * Arg (1) = SIP message pointer
+-* OUTPUT: -1=not directed to queue; 1=successfully processed
++* OUTPUT: -1=not directed to queue or other error; 1=processed
+ **********/
+
+ int mohq_process (sip_msg_t *pmsg)
+
+ {
+ /**********
+-* o parse headers
+-* o lock MOH queue
+-* o directed to message queue?
+-* o connect to database
++* read lock queue and check for updates
+ **********/
+
+ char *pfncname = "mohq_process: ";
+-if (parse_headers (pmsg, HDR_EOH_F, 0) < 0)
+- {
+- LM_ERR ("%sUnable to parse header!", pfncname);
+- return -1;
+- }
+-if (!mohq_lock_set (pmod_data->pmohq_lock, 0, 2000))
++if (!mohq_lock_set (pmod_data->pmohq_lock, 0, 500))
+ {
+- LM_ERR ("%sUnable to lock calls!", pfncname);
++ LM_ERR ("%sUnable to read lock queue!\n", pfncname);
+ return -1;
+ }
+-call_lst *pcall;
+-int mohq_idx = find_call (pmsg, &pcall);
+ db1_con_t *pconn = mohq_dbconnect ();
+ if (pconn)
+ {
+ /**********
+ * o last update older than 1 minute?
+- * o exclusively lock MOH queue
+- * o update queue
++ * o update write locked queue
+ **********/
+
+ if (pmod_data->mohq_update + 60 < time (0))
+@@ -2421,22 +2596,51 @@ if (pconn)
+ }
+ mohq_dbdisconnect (pconn);
+ }
++
++/**********
++* o parse headers
++* o directed to message queue?
++* o write lock calls
++* o search for call
++* o release call lock
++**********/
++
++if (parse_headers (pmsg, HDR_EOH_F, 0) < 0)
++ {
++ mohq_lock_release (pmod_data->pmohq_lock);
++ LM_ERR ("%sUnable to parse header!\n", pfncname);
++ return -1;
++ }
++int mohq_idx = find_queue (pmsg);
+ if (mohq_idx < 0)
+ {
+ mohq_lock_release (pmod_data->pmohq_lock);
+ return -1;
+ }
++if (!mohq_lock_set (pmod_data->pcall_lock, 1, 500))
++ {
++ mohq_lock_release (pmod_data->pmohq_lock);
++ LM_ERR ("%sUnable to write lock calls!\n", pfncname);
++ return 1;
++ }
++call_lst *pcall = find_call (pmsg, mohq_idx);
++mohq_lock_release (pmod_data->pcall_lock);
++if (!pcall)
++ {
++ mohq_lock_release (pmod_data->pmohq_lock);
++ return 1;
++ }
+
+ /**********
+ * o process message
+-* o release MOH queue
++* o release queue lock
+ **********/
+
+ mohq_debug (&pmod_data->pmohq_lst [mohq_idx],
+ "%sProcessing %.*s, queue (%s)", pfncname,
+ STR_FMT (&REQ_LINE (pmsg).method),
+ pmod_data->pmohq_lst [mohq_idx].mohq_name);
+-int ret;
++str *ptotag;
+ switch (pmsg->REQ_METHOD)
+ {
+ case METHOD_INVITE:
+@@ -2444,33 +2648,35 @@ switch (pmsg->REQ_METHOD)
+ * initial INVITE?
+ **********/
+
+- if (!pcall)
+- { ret = first_invite_msg (pmsg, mohq_idx); }
++ ptotag = &(get_to (pmsg)->tag_value);
++ if (!ptotag->len)
++ { ptotag = 0; }
++ if (!ptotag)
++ { first_invite_msg (pmsg, pcall); }
+ else
+- { ret = reinvite_msg (pmsg, pcall); }
++ { reinvite_msg (pmsg, pcall); }
+ break;
+ case METHOD_NOTIFY:
+- ret = notify_msg (pmsg, pcall);
++ notify_msg (pmsg, pcall);
+ break;
+ case METHOD_PRACK:
+- ret = prack_msg (pmsg, pcall);
++ prack_msg (pmsg, pcall);
+ break;
+ case METHOD_ACK:
+- ret = ack_msg (pmsg, pcall);
++ ack_msg (pmsg, pcall);
+ break;
+ case METHOD_BYE:
+- ret = bye_msg (pmsg, pcall);
++ bye_msg (pmsg, pcall);
+ break;
+ case METHOD_CANCEL:
+- ret = cancel_msg (pmsg, pcall);
++ cancel_msg (pmsg, pcall);
+ break;
+ default:
+ deny_method (pmsg, pcall);
+- ret = 1;
+ break;
+ }
+ mohq_lock_release (pmod_data->pmohq_lock);
+-return ret ? 1 : -1;
++return 1;
+ }
+
+ /**********
+@@ -2495,28 +2701,28 @@ char *pfncname = "mohq_retrieve: ";
+ str puri [1], pqname [1];
+ if (!pqueue || !pURI)
+ {
+- LM_ERR ("%sParameters missing!", pfncname);
++ LM_ERR ("%sParameters missing!\n", pfncname);
+ return -1;
+ }
+ if (fixup_get_svalue (pmsg, (gparam_p)pqueue, pqname))
+ {
+- LM_ERR ("%sInvalid queue name!", pfncname);
++ LM_ERR ("%sInvalid queue name!\n", pfncname);
+ return -1;
+ }
+ if (fixup_get_svalue (pmsg, (gparam_p)pURI, puri))
+ {
+- LM_ERR ("%sInvalid URI!", pfncname);
++ LM_ERR ("%sInvalid URI!\n", pfncname);
+ return -1;
+ }
+ if (puri->len > URI_LEN)
+ {
+- LM_ERR ("%sURI too long!", pfncname);
++ LM_ERR ("%sURI too long!\n", pfncname);
+ return -1;
+ }
+ struct sip_uri puri_parsed [1];
+ if (parse_uri (puri->s, puri->len, puri_parsed))
+ {
+- LM_ERR ("%sInvalid URI (%.*s)!", pfncname, STR_FMT (puri));
++ LM_ERR ("%sInvalid URI (%.*s)!\n", pfncname, STR_FMT (puri));
+ return -1;
+ }
+
+@@ -2526,12 +2732,12 @@ if (parse_uri (puri->s, puri->len, puri_parsed))
+ * o find oldest call
+ **********/
+
+-int nq_idx = find_queue (pqname);
++int nq_idx = find_qname (pqname);
+ if (nq_idx == -1)
+ { return -1; }
+ if (!mohq_lock_set (pmod_data->pcall_lock, 0, 200))
+ {
+- LM_ERR ("%sUnable to lock calls!", pfncname);
++ LM_ERR ("%sUnable to lock calls!\n", pfncname);
+ return -1;
+ }
+ call_lst *pcall = 0;
+@@ -2544,15 +2750,27 @@ for (ncall_idx = 0; ncall_idx < pmod_data->call_cnt; ncall_idx++)
+ /**********
+ * o active call?
+ * o matching queue?
++ * o refer stuck?
+ * o in queue?
+ * o check age
+ **********/
+
+ pcall = &pmod_data->pcall_lst [ncall_idx];
+- if (!pcall->call_active)
++ if (!pcall->call_state)
+ { continue; }
+ if (pcall->pmohq->mohq_id != mohq_id)
+ { continue; }
++ if ((pcall->call_state == CLSTA_REFER)
++ || (pcall->call_state == CLSTA_RFRWAIT))
++ {
++ if ((pcall->refer_time + 32) < time (0))
++ {
++ LM_ERR
++ ("%sDropping call because no response to REFER for call (%s)!\n",
++ pfncname, pcall->call_from);
++ close_call (FAKED_REPLY, pcall);
++ }
++ }
+ if (pcall->call_state != CLSTA_INQUEUE)
+ { continue; }
+ if (!ntime)
+@@ -2571,7 +2789,7 @@ for (ncall_idx = 0; ncall_idx < pmod_data->call_cnt; ncall_idx++)
+ }
+ if (nfound == -1)
+ {
+- LM_WARN ("%sNo calls in queue (%.*s)", pfncname, STR_FMT (pqname));
++ LM_WARN ("%sNo calls in queue (%.*s)\n", pfncname, STR_FMT (pqname));
+ mohq_lock_release (pmod_data->pcall_lock);
+ return -1;
+ }
+@@ -2586,7 +2804,7 @@ strncpy (pcall->call_referto, puri->s, puri->len);
+ pcall->call_referto [puri->len] = '\0';
+ if (refer_call (pcall, pmod_data->pcall_lock))
+ { return 1; }
+-LM_ERR ("%sUnable to refer call (%s)!", pfncname, pcall->call_from);
++LM_ERR ("%sUnable to refer call (%s)!\n", pfncname, pcall->call_from);
+ return -1;
+ }
+
+@@ -2610,24 +2828,24 @@ int mohq_send (sip_msg_t *pmsg, char *pqueue)
+ char *pfncname = "mohq_send: ";
+ if (pmsg->REQ_METHOD != METHOD_INVITE)
+ {
+- LM_ERR ("%sNot an INVITE message!", pfncname);
++ LM_ERR ("%sNot an INVITE message!\n", pfncname);
+ return -1;
+ }
+ to_body_t *pto_body = get_to (pmsg);
+ if (pto_body->tag_value.len)
+ {
+- LM_ERR ("%sNot a first INVITE message!", pfncname);
++ LM_ERR ("%sNot a first INVITE message!\n", pfncname);
+ return -1;
+ }
+ str pqname [1];
+ if (!pqueue)
+ {
+- LM_ERR ("%sParameters missing!", pfncname);
++ LM_ERR ("%sParameters missing!\n", pfncname);
+ return -1;
+ }
+ if (fixup_get_svalue (pmsg, (gparam_p)pqueue, pqname))
+ {
+- LM_ERR ("%sInvalid queue name!", pfncname);
++ LM_ERR ("%sInvalid queue name!\n", pfncname);
+ return -1;
+ }
+
+@@ -2637,14 +2855,14 @@ if (fixup_get_svalue (pmsg, (gparam_p)pqueue, pqname))
+ * o relay message
+ **********/
+
+-int nq_idx = find_queue (pqname);
++int nq_idx = find_qname (pqname);
+ if (nq_idx == -1)
+ { return -1; }
+ str pruri [1] = {{0, strlen (pmod_data->pmohq_lst [nq_idx].mohq_uri)}};
+ pruri->s = pkg_malloc (pruri->len + 1);
+ if (!pruri->s)
+ {
+- LM_ERR ("%sNo more memory!", pfncname);
++ LM_ERR ("%sNo more memory!\n", pfncname);
+ return -1;
+ }
+ strcpy (pruri->s, pmod_data->pmohq_lst [nq_idx].mohq_uri);
+@@ -2656,8 +2874,8 @@ pmsg->parsed_uri_ok = 0;
+ pmsg->parsed_orig_ruri_ok = 0;
+ if (pmod_data->ptm->t_relay (pmsg, 0, 0) < 0)
+ {
+- LM_ERR ("%sUnable to relay INVITE!", pfncname);
++ LM_ERR ("%sUnable to relay INVITE!\n", pfncname);
+ return -1;
+ }
+ return 1;
+-}
++}
+\ No newline at end of file
+diff --git a/modules/mohqueue/mohq_funcs.h b/modules/mohqueue/mohq_funcs.h
+index dbe02c5..5d4dfd1 100644
+--- a/modules/mohqueue/mohq_funcs.h
++++ b/modules/mohqueue/mohq_funcs.h
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (C) 2013 Robert Boisvert
++ * Copyright (C) 2013-15 Robert Boisvert
+ *
+ * This file is part of the mohqueue module for Kamailio, a free SIP server.
+ *
+@@ -35,4 +35,4 @@ int mohq_process (sip_msg_t *);
+ int mohq_retrieve (sip_msg_t *, char *, char *);
+ int mohq_send (sip_msg_t *, char *);
+
+-#endif /* MOHQ_FUNCS_H */
++#endif /* MOHQ_FUNCS_H */
+\ No newline at end of file
+diff --git a/modules/mohqueue/mohq_locks.c b/modules/mohqueue/mohq_locks.c
+index 7adb04b..50ecb1c 100644
+--- a/modules/mohqueue/mohq_locks.c
++++ b/modules/mohqueue/mohq_locks.c
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (C) 2013 Robert Boisvert
++ * Copyright (C) 2013-15 Robert Boisvert
+ *
+ * This file is part of the mohqueue module for Kamailio, a free SIP server.
+ *
+@@ -101,12 +101,12 @@ char *pfncname = "mohq_lock_init: ";
+ plock->plock = lock_alloc ();
+ if (!plock->plock)
+ {
+- LM_ERR ("%sUnable to allocate lock memory!", pfncname);
++ LM_ERR ("%sUnable to allocate lock memory!\n", pfncname);
+ return 0;
+ }
+ if (!lock_init (plock->plock))
+ {
+- LM_ERR ("%sUnable to init lock!", pfncname);
++ LM_ERR ("%sUnable to init lock!\n", pfncname);
+ lock_dealloc (plock->plock);
+ return 0;
+ }
+@@ -138,7 +138,7 @@ switch (plock->lock_cnt)
+ plock->lock_cnt = 0;
+ break;
+ case 0:
+- LM_WARN ("mohq_lock_release: Lock was not set");
++ LM_WARN ("mohq_lock_release: Lock was not set.\n");
+ break;
+ default:
+ plock->lock_cnt--;
+@@ -194,4 +194,4 @@ do
+ }
+ while (!nret && --nms_cnt >= 0);
+ return nret;
+-}
++}
+\ No newline at end of file
+diff --git a/modules/mohqueue/mohq_locks.h b/modules/mohqueue/mohq_locks.h
+index 6f95c65..18c23fe 100644
+--- a/modules/mohqueue/mohq_locks.h
++++ b/modules/mohqueue/mohq_locks.h
+@@ -1,5 +1,5 @@
+ /*
+- * Copyright (C) 2013 Robert Boisvert
++ * Copyright (C) 2013-15 Robert Boisvert
+ *
+ * This file is part of the mohqueue module for Kamailio, a free SIP server.
+ *
+@@ -44,4 +44,4 @@ int mohq_lock_init (mohq_lock *);
+ void mohq_lock_release (mohq_lock *);
+ int mohq_lock_set (mohq_lock *, int, int);
+
+-#endif /* MOHQ_LOCKS_H */
++#endif /* MOHQ_LOCKS_H */
+\ No newline at end of file