summaryrefslogtreecommitdiffstats
path: root/main/kamailio
diff options
context:
space:
mode:
authorNathan Angelacos <nangel@alpinelinux.org>2015-06-08 22:03:19 +0000
committerNatanael Copa <ncopa@alpinelinux.org>2015-06-09 14:58:26 +0000
commit9cec9d32fe869695a47042fb35c5043db9fc57f7 (patch)
tree88c90304610229620dc933ecedb2e7738aa88f81 /main/kamailio
parent465b2767e69576b62efeefa923720d5e2b866ced (diff)
downloadaports-9cec9d32fe869695a47042fb35c5043db9fc57f7.tar.bz2
aports-9cec9d32fe869695a47042fb35c5043db9fc57f7.tar.xz
main/kamailio use mohqueue v0.11 module from github
Diffstat (limited to 'main/kamailio')
-rw-r--r--main/kamailio/0002-mohqueue-v0-11.patch2851
-rw-r--r--main/kamailio/APKBUILD6
2 files changed, 2856 insertions, 1 deletions
diff --git a/main/kamailio/0002-mohqueue-v0-11.patch b/main/kamailio/0002-mohqueue-v0-11.patch
new file mode 100644
index 000000000..f6285a56b
--- /dev/null
+++ b/main/kamailio/0002-mohqueue-v0-11.patch
@@ -0,0 +1,2851 @@
+--- 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
++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
+\ No newline at end of file
+--- a/modules/mohqueue/mohq.c
++++ b/modules/mohqueue/mohq.c
+@@ -1,10 +1,8 @@
+ /*
+- * $Id$
++ * Copyright (C) 2013-15 Robert Boisvert
+ *
+- * Copyright (C) 2013 Robert Boisvert
++ * This file is part of the mohqueue module for Kamailio, a free SIP server.
+ *
+- * This file is part of the mohqueue module for sip-router, a free SIP server.
+- *
+ * The mohqueue module is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+@@ -61,9 +59,9 @@
+ };
+
+ /* 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;
+
+@@ -134,81 +132,84 @@
+ static int init_cfg (void)
+
+ {
++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)
++if (!db_url.s || db_url.len <= 0)
+ {
+- LM_ERR ("db_url parameter not set!");
+- return 0;
++ LM_ERR ("db_url parameter not set!\n");
++ berror = 1;
+ }
+- pmod_data->pcfg->db_url = db_url;
+-
+- if (!db_ctable.s || db_ctable.len<=0)
++if (!db_ctable.s || db_ctable.len <= 0)
+ {
+- LM_ERR ("db_ctable parameter not set!");
+- return 0;
++ LM_ERR ("db_ctable parameter not set!\n");
++ berror = 1;
+ }
+- pmod_data->pcfg->db_ctable = db_ctable;
+-
+- if (!db_qtable.s || db_qtable.len<=0)
++if (!db_qtable.s || db_qtable.len <= 0)
+ {
+- LM_ERR ("db_qtable parameter not set!");
+- return 0;
++ LM_ERR ("db_qtable parameter not set!\n");
++ berror = 1;
+ }
+- pmod_data->pcfg->db_qtable = db_qtable;
+
+-
+ /**********
+ * mohdir
+ * o exists?
+ * o directory?
+ **********/
+
+- if (!*mohdir)
++if (!*mohdir)
+ {
+- LM_ERR ("mohdir parameter not set!");
+- return 0;
++ LM_ERR ("mohdir parameter not set!\n");
++ berror = 1;
+ }
+- if (strlen(mohdir) > MOHDIRLEN)
++else if (strlen (mohdir) > MOHDIRLEN)
+ {
+- LM_ERR ("mohdir too long!");
+- return 0;
++ LM_ERR ("mohdir too long!\n");
++ berror = 1;
+ }
+- pmod_data->pcfg->mohdir = mohdir;
+-
+- int bfnd = 0;
+- struct stat psb [1];
+- 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!");
+- return 0;
++ {
++ LM_ERR ("mohdir is not a directory!\n");
++ berror = 1;
++ }
+ }
+
+ /**********
+-* max calls
+-* o valid count?
++* o max calls valid?
+ * o alloc memory
++* o save data
+ **********/
+
+ if (moh_maxcalls < 1 || moh_maxcalls > 5000)
+ {
+- LM_ERR ("moh_maxcalls not in range of 1-5000!");
+- return 0;
++ LM_ERR ("moh_maxcalls not in range of 1-5000!\n");
++ berror = 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");
+- return -1;
++ 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;
+@@ -234,13 +235,13 @@
+ 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 ();
+@@ -256,14 +257,14 @@
+ 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;
+ }
+@@ -303,7 +304,7 @@
+ { return 0; }
+ if (!pmod_data->pdb->init)
+ {
+- LM_CRIT ("DB API not loaded!");
++ LM_CRIT ("DB API not loaded!\n");
+ return -1;
+ }
+ return 0;
+@@ -357,7 +358,7 @@
+ 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));
+@@ -373,47 +374,59 @@
+
+ if (sl_load_api (pmod_data->psl))
+ {
+- LM_ERR ("Unable to load SL module");
++ LM_ERR ("Unable to load SL module!\n");
+ goto initerr;
+ }
+ if (load_tm_api (pmod_data->ptm))
+ {
+- LM_ERR ("Unable to load TM module");
++ LM_ERR ("Unable to load TM module!\n");
+ goto initerr;
+ }
+ if (load_rr_api (pmod_data->prr))
+ {
+- LM_ERR ("Unable to load RR module");
++ 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");
++ 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");
++ 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");
++ 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");
++ 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");
++ LM_ERR ("Unable to load rtpproxy_destroy!\n");
+ goto initerr;
+ }
+
+@@ -440,4 +453,4 @@
+ shm_free (pmod_data);
+ pmod_data = NULL;
+ return -1;
+-}
++}
+\ No newline at end of file
+--- a/modules/mohqueue/mohq.h
++++ b/modules/mohqueue/mohq.h
+@@ -1,10 +1,8 @@
+ /*
+- * $Id$
++ * Copyright (C) 2013-15 Robert Boisvert
+ *
+- * Copyright (C) 2013 Robert Boisvert
++ * This file is part of the mohqueue module for Kamailio, a free SIP server.
+ *
+- * This file is part of the mohqueue module for sip-router, a free SIP server.
+- *
+ * The mohqueue module is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+@@ -63,31 +61,35 @@
+
+ /* 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_bufpos;
++ 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;
+@@ -120,6 +122,8 @@
+ 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;
+
+ /**********
+--- a/modules/mohqueue/mohq_common.h
++++ b/modules/mohqueue/mohq_common.h
+@@ -1,10 +1,8 @@
+ /*
+- * $Id$
++ * Copyright (C) 2013-15 Robert Boisvert
+ *
+- * Copyright (C) 2013 Robert Boisvert
++ * This file is part of the mohqueue module for Kamailio, a free SIP server.
+ *
+- * This file is part of the mohqueue module for sip-router, a free SIP server.
+- *
+ * The mohqueue module is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+@@ -53,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 */
+@@ -69,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); \
+@@ -84,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)); \
+ }
+--- a/modules/mohqueue/mohq_db.c
++++ b/modules/mohqueue/mohq_db.c
+@@ -1,10 +1,8 @@
+ /*
+- * $Id$
++ * Copyright (C) 2013-15 Robert Boisvert
+ *
+- * Copyright (C) 2013 Robert Boisvert
++ * This file is part of the mohqueue module for Kamailio, a free SIP server.
+ *
+- * This file is part of the mohqueue module for sip-router, a free SIP server.
+- *
+ * The mohqueue module is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+@@ -216,7 +214,7 @@
+ 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);
+@@ -243,7 +241,7 @@
+ 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;
+@@ -277,7 +275,7 @@
+ 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);
+@@ -297,7 +295,7 @@
+ 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", pdb_url->s); }
++ { LM_ERR ("Unable to connect to DB %s!\n", pdb_url->s); }
+ return pconn;
+ }
+
+@@ -348,7 +346,7 @@
+ 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);
+@@ -390,7 +388,7 @@
+ 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);
+@@ -428,7 +426,7 @@
+ db1_res_t *presult = NULL;
+ if (pdb->query (pconn, 0, 0, 0, prkeys, 0, MOHQ_COLCNT, 0, &presult))
+ {
+- LM_ERR ("%stable query (%s) failed!", pfncname,
++ LM_ERR ("%stable query (%s) failed!\n", pfncname,
+ pmod_data->pcfg->db_qtable.s);
+ return;
+ }
+@@ -449,7 +447,7 @@
+ struct sip_uri puri_parsed [1];
+ if (parse_uri (puri, strlen (puri), puri_parsed))
+ {
+- LM_ERR ("Queue,Field (%s,%.*s): %s is not a valid URI!", pqname,
++ LM_ERR ("Queue,Field (%s,%.*s): %s is not a valid URI!\n", pqname,
+ STR_FMT (&MOHQCSTR_URI), puri);
+ continue;
+ }
+@@ -477,7 +475,7 @@
+ struct stat psb [1];
+ if (lstat (pmohdir, psb))
+ {
+- LM_ERR ("Queue,Field (%s,%.*s): Unable to find %s!", pqname,
++ LM_ERR ("Queue,Field (%s,%.*s): Unable to find %s!\n", pqname,
+ STR_FMT (&MOHQCSTR_MDIR), pmohdir);
+ continue;
+ }
+@@ -485,7 +483,7 @@
+ {
+ if ((psb->st_mode & S_IFMT) != S_IFDIR)
+ {
+- LM_ERR ("Queue,Field (%s,%.*s): %s is not a directory!", pqname,
++ LM_ERR ("Queue,Field (%s,%.*s): %s is not a directory!\n", pqname,
+ STR_FMT (&MOHQCSTR_MDIR), pmohdir);
+ continue;
+ }
+@@ -501,7 +499,7 @@
+ (char *)VAL_STRING (prowvals + MOHQCOL_MFILE));
+ if (!pmohfiles [0])
+ {
+- LM_ERR ("Queue,Field (%s,%.*s): Unable to find MOH files (%s/%s.*)!",
++ LM_ERR ("Queue,Field (%s,%.*s): Unable to find MOH files (%s/%s.*)!\n",
+ pqname, STR_FMT (&MOHQCSTR_MDIR), pmohdir,
+ (char *)VAL_STRING (prowvals + MOHQCOL_MFILE));
+ continue;
+@@ -525,21 +523,21 @@
+ 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;
+@@ -549,7 +547,7 @@
+ { 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;
+@@ -576,7 +574,7 @@
+ pnewlst = (mohq_lst *) shm_malloc (sizeof (mohq_lst) * nsize);
+ if (!pnewlst)
+ {
+- LM_ERR ("%sUnable to allocate shared memory!", pfncname);
++ LM_ERR ("%sUnable to allocate shared memory!\n", pfncname);
+ return;
+ }
+ pmod_data->mohq_cnt = nsize;
+@@ -592,7 +590,7 @@
+ (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;
+@@ -613,7 +611,7 @@
+
+ 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],
+--- a/modules/mohqueue/mohq_db.h
++++ b/modules/mohqueue/mohq_db.h
+@@ -1,9 +1,7 @@
+ /*
+- * $Id$
++ * Copyright (C) 2013-15 Robert Boisvert
+ *
+- * Copyright (C) 2013 Robert Boisvert
+- *
+- * This file is part of the mohqueue module for sip-router, a free SIP server.
++ * This file is part of the mohqueue module for Kamailio, a free SIP server.
+ *
+ * The mohqueue module is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+--- a/modules/mohqueue/mohq_funcs.c
++++ b/modules/mohqueue/mohq_funcs.c
+@@ -1,10 +1,8 @@
+ /*
+- * $Id$
++ * Copyright (C) 2013-15 Robert Boisvert
+ *
+- * Copyright (C) 2013 Robert Boisvert
++ * This file is part of the mohqueue module for Kamailio, a free SIP server.
+ *
+- * This file is part of the mohqueue module for sip-router, a free SIP server.
+- *
+ * The mohqueue module is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+@@ -34,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
+@@ -48,6 +46,7 @@
+ 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")};
+@@ -57,6 +56,7 @@
+ 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 [] =
+@@ -88,9 +88,9 @@
+ char pbyemsg [] =
+ {
+ "%s"
++ "%s"
+ "Max-Forwards: 70" SIPEOL
+ "Contact: <%s>" SIPEOL
+- "User-Agent: " USRAGNT SIPEOL
+ };
+
+ str pextrahdr [1] =
+@@ -100,7 +100,6 @@
+ "Supported: 100rel" SIPEOL
+ "Accept-Language: en" SIPEOL
+ "Content-Type: application/sdp" SIPEOL
+- "User-Agent: " USRAGNT SIPEOL
+ )
+ };
+
+@@ -118,10 +117,11 @@
+ 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 [] =
+@@ -131,7 +131,6 @@
+ "Contact: <%s>" SIPEOL
+ ALLOWHDR SIPEOL
+ "Supported: 100rel" SIPEOL
+- "User-Agent: " USRAGNT SIPEOL
+ "Accept-Language: en" SIPEOL
+ "Content-Type: application/sdp" SIPEOL
+ };
+@@ -153,8 +152,7 @@
+ **********/
+
+ 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 *);
+@@ -164,6 +162,7 @@
+ 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
+@@ -175,10 +174,10 @@
+ * 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)
+
+ {
+ /**********
+@@ -195,13 +194,13 @@
+ **********/
+
+ if (pcall->call_state != CLSTA_INQUEUE)
+- { LM_ERR ("%sUnexpected ACK (%s)!", pfncname, pcall->call_from); }
++ { LM_ERR ("%sUnexpected ACK (%s)!\n", pfncname, pcall->call_from); }
+ else
+ {
+- mohq_debug (pcall->pmohq, "%sACK from refused re-INVITE (%s)!",
++ mohq_debug (pcall->pmohq, "%sACK from refused re-INVITE (%s)!\n",
+ pfncname, pcall->call_from);
+ }
+- return 1;
++ return;
+ }
+
+ /**********
+@@ -212,17 +211,17 @@
+
+ if (ptm->t_lookup_ident (&ptrans, pcall->call_hash, pcall->call_label) < 0)
+ {
+- LM_ERR ("%sINVITE transaction missing for call (%s)!",
++ LM_ERR ("%sINVITE transaction missing for call (%s)!\n",
+ pfncname, pcall->call_from);
+- return 1;
++ return;
+ }
+ else
+ {
+ if (ptm->t_release (pcall->call_pmsg) < 0)
+ {
+- LM_ERR ("%sRelease transaction failed for call (%s)!",
++ LM_ERR ("%sRelease transaction failed for call (%s)!\n",
+ pfncname, pcall->call_from);
+- return 1;
++ return;
+ }
+ }
+ pcall->call_hash = pcall->call_label = 0;
+@@ -235,6 +234,47 @@
+ 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;
+ }
+
+@@ -261,7 +301,7 @@
+ call_lst *pcall = (call_lst *)*pcbp->param;
+ if (ntype == TMCB_ON_FAILURE)
+ {
+- LM_ERR ("%sCall (%s) did not respond to BYE", pfncname,
++ LM_ERR ("%sCall (%s) did not respond to BYE!\n", pfncname,
+ pcall->call_from);
+ }
+ else
+@@ -269,7 +309,7 @@
+ int nreply = pcbp->code;
+ if ((nreply / 100) != 2)
+ {
+- LM_ERR ("%sCall (%s) BYE error (%d)", pfncname,
++ LM_ERR ("%sCall (%s) BYE error (%d)!\n", pfncname,
+ pcall->call_from, nreply);
+ }
+ else
+@@ -288,33 +328,43 @@
+ * 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)", 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!",
++ 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;
+ }
+
+ /**********
+@@ -323,14 +373,15 @@
+ * 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: ";
+@@ -340,16 +391,16 @@
+ mohq_debug (pcall->pmohq, "%sCANCELed call (%s)",
+ pfncname, pcall->call_from);
+ if (pmod_data->psl->freply (pmsg, 487, presp_reqterm) < 0)
+- { LM_ERR ("%sUnable to create reply!", pfncname); }
++ { LM_ERR ("%sUnable to create reply!\n", pfncname); }
+ }
+ else
+ {
+- LM_ERR ("%sUnable to CANCEL because accepted INVITE for call (%s)!",
++ LM_ERR ("%sUnable to CANCEL because accepted INVITE 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); }
++ { LM_ERR ("%sUnable to create reply!\n", pfncname); }
+ }
+-return 1;
++return;
+ }
+
+ /**********
+@@ -365,23 +416,14 @@
+
+ {
+ /**********
+-* 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)!",
+- pfncname, pcall->call_from);
+- }
+- }
++end_RTP (pmsg, pcall);
+ struct to_body ptob [2];
+ dlg_t *pdlg = form_dialog (pcall, ptob);
+ if (!pdlg)
+@@ -398,15 +440,17 @@
+ 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)
+ {
+- LM_ERR ("%sNo more memory!", pfncname);
++ LM_ERR ("%sNo more memory!\n", pfncname);
+ goto bye_err;
+ }
+ sprintf (phdr, pbyemsg,
+ pcall->call_via, // Via
++ pcall->call_route, // Route
+ pquri); // Contact
+ str phdrs [1];
+ phdrs->s = phdr;
+@@ -422,7 +466,7 @@
+ pcall->call_state = CLSTA_BYE;
+ if (ptm->t_request_within (puac) < 0)
+ {
+- LM_ERR ("%sUnable to create BYE request for call (%s)!",
++ LM_ERR ("%sUnable to create BYE request for call (%s)!\n",
+ pfncname, pcall->call_from);
+ goto bye_err;
+ }
+@@ -449,138 +493,127 @@
+ * 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!", 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)!", 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!", 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_bufpos = sizeof (pcall->call_buffer);
++pcall->call_id = pbuf;
++if (!addstrbfr (pstr->s, pstr->len, &pbuf, &pcall->call_bufpos, 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_bufpos, 1))
++ { return 0; }
++pcall->call_tag = pbuf;
++if (!addstrbfr (0, 0, &pbuf, &pcall->call_bufpos, 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_bufpos, 0))
++ { return 0; }
+ }
++if (!addstrbfr (0, 0, &pbuf, &pcall->call_bufpos, 1))
++ { return 0; }
+
+ /**********
+ * extract Via headers
+ **********/
+
++pcall->call_via = pbuf;
+ hdr_field_t *phdr = pmsg->h_via1;
+ if (phdr)
+ {
+- int npos1 = 0;
+ while ((phdr = next_sibling_hdr (phdr)))
+ {
+ struct via_body *pvia;
+ char *pviabuf;
+- int bovrflow = 0;
+- int npos2;
+- int nvia_max = sizeof (pcall->call_via);
++ int npos;
+ for (pvia = (struct via_body *)phdr->parsed; pvia; pvia = pvia->next)
+ {
+ /**********
+- * o skip trailing whitespace
+- * o check if overflow
++ * skip trailing whitespace
+ **********/
+
+- npos2 = pvia->bsize;
++ npos = pvia->bsize;
+ pviabuf = pvia->name.s;
+- while (npos2)
++ while (npos)
+ {
+- --npos2;
+- if (pviabuf [npos2] == ' ' || pviabuf [npos2] == '\r'
+- || pviabuf [npos2] == '\n' || pviabuf [npos2] == '\t' || pviabuf [npos2] == ',')
++ --npos;
++ if (pviabuf [npos] == ' ' || pviabuf [npos] == '\r'
++ || pviabuf [npos] == '\n' || pviabuf [npos] == '\t'
++ || pviabuf [npos] == ',')
+ { continue; }
+ break;
+ }
+- if ((npos2 + npos1 + 7) >= nvia_max)
+- {
+- LM_WARN ("%sVia buffer overflowed!", pfncname);
+- bovrflow = 1;
+- break;
+- }
+
+ /**********
+ * copy via
+ **********/
+
+- 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 (!addstrbfr ("Via: ", 5, &pbuf, &pcall->call_bufpos, 0))
++ { return 0; }
++ if (!addstrbfr (pviabuf, npos, &pbuf, &pcall->call_bufpos, 0))
++ { return 0; }
++ if (!addstrbfr (SIPEOL, 2, &pbuf, &pcall->call_bufpos, 0))
++ { return 0; }
+ }
+- if (bovrflow)
+- { break; }
+ }
+ }
++if (!addstrbfr (0, 0, &pbuf, &pcall->call_bufpos, 1))
++ { return 0; }
+
+ /**********
+-* o release call lock
+-* o update DB
+-* o lock MOH queue
++* 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_bufpos, 0))
++ { return 0; }
++ if (!addstrbfr (prouterr->nameaddr.name.s, prouterr->len,
++ &pbuf, &pcall->call_bufpos, 0))
++ { return 0; }
++ if (!addstrbfr (SIPEOL, 2, &pbuf, &pcall->call_bufpos, 0))
++ { return 0; }
++ }
++ }
++if (!addstrbfr (0, 0, &pbuf, &pcall->call_bufpos, 1))
++ { return 0; }
++
++/**********
++* update DB
++**********/
++
+ 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;
+ }
+
+ /**********
+@@ -605,15 +638,15 @@
+ {
+ if (ptm->t_lookup_ident (&ptrans, pcall->call_hash, pcall->call_label) < 0)
+ {
+- LM_ERR ("%sLookup transaction failed for call (%s)!", 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)!",
+- 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;
+@@ -622,14 +655,21 @@
+ /**********
+ * 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;
+ }
+
+@@ -655,28 +695,28 @@
+ tm_api_t *ptm = pmod_data->ptm;
+ if (ptm->t_newtran (pmsg) < 0)
+ {
+- LM_ERR ("%sUnable to create new transaction!", pfncname);
++ LM_ERR ("%sUnable to create new transaction!\n", pfncname);
+ if (pmod_data->psl->freply (pmsg, 500, presp_srverr) < 0)
+ {
+- LM_ERR ("%sUnable to create reply to %.*s!", pfncname,
++ LM_ERR ("%sUnable to create reply to %.*s!\n", pfncname,
+ STR_FMT (&REQ_LINE (pmsg).method));
+ }
+ return;
+ }
+ if (!add_lump_rpl2 (pmsg, pallowhdr->s, pallowhdr->len, LUMP_RPL_HDR))
+- { LM_ERR ("%sUnable to add Allow header!", pfncname); }
+-LM_ERR ("%sRefused %.*s for call (%s)!", pfncname,
++ { LM_ERR ("%sUnable to add Allow header!\n", 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)
+ {
+- LM_ERR ("%sUnable to create reply to %.*s!", pfncname,
++ LM_ERR ("%sUnable to create reply to %.*s!\n", pfncname,
+ STR_FMT (&REQ_LINE (pmsg).method));
+ }
+ return;
+ }
+
+ /**********
+-* Drop the Call
++* End RTP
+ *
+ * INPUT:
+ * Arg (1) = SIP message pointer
+@@ -684,26 +724,24 @@
+ * 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);
+ if (pmod_data->fn_rtp_destroy (pmsg, 0, 0) != 1)
+ {
+- LM_ERR ("%srtpproxy_destroy refused for call (%s)!",
++ LM_ERR ("%srtpproxy_destroy refused for call (%s)!\n",
+ pfncname, pcall->call_from);
+ }
+ }
+-delete_call (pcall);
+ return;
+ }
+
+@@ -712,62 +750,37 @@
+ *
+ * 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++)
+ {
+ /**********
+@@ -775,21 +788,25 @@
+ * 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)", 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);
+@@ -802,36 +819,101 @@
+ 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))
+ {
+- LM_ERR ("%sUnable to lock queues!", pfncname);
++ LM_ERR ("%sUnable to lock queues!\n", pfncname);
+ return -1;
+ }
+ for (nidx = 0; nidx < pmod_data->mohq_cnt; nidx++)
+@@ -843,7 +925,7 @@
+ }
+ if (nidx == pmod_data->mohq_cnt)
+ {
+- LM_ERR ("%sUnable to find queue (%.*s)!", pfncname, STR_FMT (pqname));
++ LM_ERR ("%sUnable to find queue (%.*s)!\n", pfncname, STR_FMT (pqname));
+ nidx = -1;
+ }
+ mohq_lock_release (pmod_data->pmohq_lock);
+@@ -871,7 +953,7 @@
+ 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)
+@@ -886,7 +968,7 @@
+ 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);
+@@ -894,7 +976,7 @@
+ 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)
+@@ -910,55 +992,65 @@
+ *
+ * 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;
+ }
+
+ /**********
+@@ -971,10 +1063,11 @@
+ 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;
+@@ -982,28 +1075,53 @@
+ 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;
+ }
+-strncpy (pcall->call_tag, ptotag->s, ptotag->len);
+-pcall->call_tag [ptotag->len] = '\0';
++char *pbuf = &pcall->call_buffer [pcall->call_bufpos];
++pcall->call_tag = pbuf;
++if (!addstrbfr (ptotag->s, ptotag->len, &pbuf, &pcall->call_bufpos, 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;
++ }
+ 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
+ * o supports/requires PRACK? (RFC 3262 section 3)
+ * o exit if not ringing
+@@ -1011,19 +1129,20 @@
+
+ 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);
+@@ -1032,42 +1151,30 @@
+ {
+ 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)
++ if (pcall->call_state == CLSTA_CANCEL)
+ {
+- LM_ERR ("%sUnable to reply to INVITE!", pfncname);
+- return 1;
++ end_RTP (pmsg, pcall);
++ delete_call (pcall);
++ return;
+ }
+- else
+- {
+- pcall->call_state = CLSTA_RINGING;
+- mohq_debug (pcall->pmohq, "%sSent RINGING for call (%s)",
+- pfncname, pcall->call_from);
+- }
+ }
+
+ /**********
+-* 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;
+ }
+
+ /**********
+@@ -1087,6 +1194,9 @@
+ **********/
+
+ 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,
+@@ -1094,12 +1204,49 @@
+ 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;
+@@ -1112,7 +1259,7 @@
+ 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;
+ }
+@@ -1129,7 +1276,7 @@
+ 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));
+@@ -1147,6 +1294,11 @@
+ 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;
+ }
+
+@@ -1173,7 +1325,7 @@
+ 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;
+ }
+@@ -1193,7 +1345,7 @@
+ 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);
+@@ -1240,7 +1392,7 @@
+ 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;
+ }
+@@ -1251,10 +1403,10 @@
+ * 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)
+
+ {
+ /**********
+@@ -1264,11 +1416,11 @@
+ 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;
+ }
+
+ /**********
+@@ -1279,28 +1431,28 @@
+
+ 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')
+@@ -1313,10 +1465,10 @@
+ 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;
+ }
+
+ /**********
+@@ -1324,32 +1476,34 @@
+ * 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;
+ }
+
+ /**********
+@@ -1360,7 +1514,7 @@
+ update_call_rec (pcall);
+ break;
+ }
+-return 1;
++return;
+ }
+
+ /**********
+@@ -1369,10 +1523,10 @@
+ * 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)
+
+ {
+ /**********
+@@ -1383,10 +1537,10 @@
+ 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;
+ }
+
+ /**********
+@@ -1396,20 +1550,20 @@
+
+ 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;
+ }
+
+ /**********
+@@ -1450,18 +1604,22 @@
+ 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
+@@ -1474,13 +1632,14 @@
+ 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;
+@@ -1514,21 +1673,23 @@
+ 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); }
+@@ -1547,10 +1708,10 @@
+ * 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)
+
+ {
+ /**********
+@@ -1565,17 +1726,17 @@
+ 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;
+ }
+ }
+
+@@ -1645,12 +1806,12 @@
+ {
+ 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
+@@ -1659,26 +1820,26 @@
+ 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;
+ }
+
+ /**********
+@@ -1746,22 +1907,21 @@
+ "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;
+ }
+@@ -1782,7 +1942,7 @@
+ { 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;
+ }
+@@ -1822,7 +1982,7 @@
+ (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;
+ }
+@@ -1895,7 +2055,7 @@
+ 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++)
+@@ -1925,7 +2085,7 @@
+ memcpy (&pnmsg->rcv, &pmsg->rcv, sizeof (struct receive_info));
+
+ /**********
+-* o send rtpproxy answer
++* o send RTP answer
+ * o form stream file
+ * o send stream
+ **********/
+@@ -1934,7 +2094,7 @@
+ 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;
+ }
+@@ -1951,7 +2111,7 @@
+ 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;
+ }
+@@ -1975,26 +2135,26 @@
+ 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;
+ }
+@@ -2043,7 +2203,7 @@
+ 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;
+ }
+@@ -2051,6 +2211,33 @@
+ }
+
+ /**********
++* 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;
++ }
++return 1;
++}
++
++/**********
+ * Form Char Array from STR
+ *
+ * INPUT:
+@@ -2064,7 +2251,7 @@
+ 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);
+@@ -2164,7 +2351,7 @@
+ 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];
+@@ -2217,7 +2404,7 @@
+ 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))
+@@ -2240,7 +2427,7 @@
+ **********/
+
+ 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; }
+@@ -2279,12 +2466,12 @@
+ 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;
+ }
+
+@@ -2294,12 +2481,12 @@
+ * 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)
+@@ -2307,7 +2494,7 @@
+ 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)
+@@ -2328,7 +2515,7 @@
+ 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;
+@@ -2366,7 +2553,7 @@
+ 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;
+@@ -2377,39 +2564,28 @@
+ *
+ * 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)
++if (!mohq_lock_set (pmod_data->pmohq_lock, 0, 500))
+ {
+- LM_ERR ("%sUnable to parse header!", pfncname);
++ LM_ERR ("%sUnable to read lock queue!\n", pfncname);
+ return -1;
+ }
+-if (!mohq_lock_set (pmod_data->pmohq_lock, 0, 2000))
+- {
+- LM_ERR ("%sUnable to lock calls!", 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))
+@@ -2423,22 +2599,51 @@
+ }
+ 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:
+@@ -2446,33 +2651,35 @@
+ * 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;
+ }
+
+ /**********
+@@ -2497,28 +2704,28 @@
+ 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;
+ }
+
+@@ -2528,12 +2735,12 @@
+ * 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;
+@@ -2546,15 +2753,27 @@
+ /**********
+ * 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)
+@@ -2573,7 +2792,7 @@
+ }
+ 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;
+ }
+@@ -2588,7 +2807,7 @@
+ 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;
+ }
+
+@@ -2612,24 +2831,24 @@
+ 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;
+ }
+
+@@ -2639,14 +2858,14 @@
+ * 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);
+@@ -2658,7 +2877,7 @@
+ 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;
+--- a/modules/mohqueue/mohq_funcs.h
++++ b/modules/mohqueue/mohq_funcs.h
+@@ -1,9 +1,7 @@
+ /*
+- * $Id$
++ * Copyright (C) 2013-15 Robert Boisvert
+ *
+- * Copyright (C) 2013 Robert Boisvert
+- *
+- * This file is part of the mohqueue module for sip-router, a free SIP server.
++ * This file is part of the mohqueue module for Kamailio, a free SIP server.
+ *
+ * The mohqueue module is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+--- a/modules/mohqueue/mohq_locks.c
++++ b/modules/mohqueue/mohq_locks.c
+@@ -1,10 +1,8 @@
+ /*
+- * $Id$
++ * Copyright (C) 2013-15 Robert Boisvert
+ *
+- * Copyright (C) 2013 Robert Boisvert
++ * This file is part of the mohqueue module for Kamailio, a free SIP server.
+ *
+- * This file is part of the mohqueue module for sip-router, a free SIP server.
+- *
+ * The mohqueue module is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+@@ -103,12 +101,12 @@
+ 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;
+ }
+@@ -140,7 +138,7 @@
+ 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--;
+--- a/modules/mohqueue/mohq_locks.h
++++ b/modules/mohqueue/mohq_locks.h
+@@ -1,9 +1,7 @@
+ /*
+- * $Id$
++ * Copyright (C) 2013-15 Robert Boisvert
+ *
+- * Copyright (C) 2013 Robert Boisvert
+- *
+- * This file is part of the mohqueue module for sip-router, a free SIP server.
++ * This file is part of the mohqueue module for Kamailio, a free SIP server.
+ *
+ * The mohqueue module is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
diff --git a/main/kamailio/APKBUILD b/main/kamailio/APKBUILD
index ccf91bb8e..e6589894a 100644
--- a/main/kamailio/APKBUILD
+++ b/main/kamailio/APKBUILD
@@ -13,7 +13,7 @@ _gittag=HEAD
pkgver=4.2.5
-pkgrel=0
+pkgrel=1
[ -z "${_gitcommit}" ] && _suffix="_src" || _suffix="-${_gitcommit}"
pkgdesc="Open Source SIP Server"
@@ -227,6 +227,7 @@ source="http://www.kamailio.org/pub/kamailio/$pkgver/src/kamailio-${pkgver}${_su
0001-musl-fixes.patch
kamailio-4.2-ipops-srv-query.patch
DMQ-multi-notify.patch
+ 0002-mohqueue-v0-11.patch
default_ctl.patch
kamctl_build.patch
@@ -496,6 +497,7 @@ bad1ac2d4c95043df271d2ea6d37627a kamailio-4.2-backslash.patch
4685288dc54680597b00f956dc95d4d6 0001-musl-fixes.patch
e9c0ba8192a1a4f2a08a2e2add20e3d7 kamailio-4.2-ipops-srv-query.patch
7df723eb9e14df28adfff8643d99a1a9 DMQ-multi-notify.patch
+2ebca868c6f99ffc12f544b7585d11bf 0002-mohqueue-v0-11.patch
841fa62c432c5d8aeb57ad70d2ec3030 default_ctl.patch
d0052e6054884b9cec955af4480c7c85 kamctl_build.patch
299706d97e30a4f0d9b4c873df422866 kamailio.cfg
@@ -505,6 +507,7 @@ d7e59be721ed0ad4621d404493b9a519708d801e9d4914b0164b819fa1abcd13 kamailio-4.2-b
b98555ff304b51b82c6cf7e01d757b15ea4f05bd2e603c84d4384df6a6be62b6 0001-musl-fixes.patch
7e33c95bdb942e4ed6d54e14476cad2ee7edfc256b1f250e5f133d9e8a9b2a67 kamailio-4.2-ipops-srv-query.patch
384eeaa5b253228341dc7a74ec61314db4b8f2f1c9c2f3bdf9ba189d2d56911d DMQ-multi-notify.patch
+67367f0ebd85dcdfde1fbf4ac964fd70e6ee16cddcb81e7320b0eceddf91d08f 0002-mohqueue-v0-11.patch
755efa4ad126c672bc67c53268260b57f7da1f454cdc1a1601778ed7c7d5f0e5 default_ctl.patch
e00eefed792acbc1ee6eca8fa7389f9973bd53b68fa7abc573f19f1ff26812a1 kamctl_build.patch
8b742ff710ef67ff59ec07a260690ebcdda24fb6f0b7b64dc50433a1bacf99f2 kamailio.cfg
@@ -514,6 +517,7 @@ a9bb1e8f9f373264b8351ddae099a36a46ddd46fdec09e468d297ba4f64bb4896e7d6e599da70a42
dea7ef2ccf01357576045ba375d41301e2447b4454324007c7ca1862322835c57045852017192ca5434b32dd1b7a2e9669209b7111889dab335b74f042d0f11f 0001-musl-fixes.patch
b5c048b6e06de0c7514c14d0ec99bbe939eaa956d9d9d3dd5f48b1bcbcff06dbd6498d384427253fb655997a10ec5fa31dcc5cfd2f8cc5c64dcd531649133781 kamailio-4.2-ipops-srv-query.patch
7ddf6444c15f7338e7aab779ea5b75f4fd936b51cf5d9ba0d09e813566e527f74e59e100661d2b27db99e5fa042614c83e8145e999a8b6bfcfab71c9595bb626 DMQ-multi-notify.patch
+3e6c961e7674bc7b464ea3b8694b35962dae7a432cad724ea0bd9e6cb9dd62bb898ad4dd09270d847d6473d3ed62bc7a08f5683f69d72b462d083a6ab5c44eae 0002-mohqueue-v0-11.patch
2321d8afe29b53057ce21e0552dfb80fd6a0e7dc0caf3c4798a8b253518f4c8c546797302933373f4b055a4531329a36ee2d7117b0a88fe39cf153bfef91a656 default_ctl.patch
4c2c9bde3a4c44feca2863bb03cb031aa55e1c3df21dc7c0acb3a392c34cb36d9a132bcbdf451a0624f8ec202152f1cf238c89280c32f1c04312ce80427a18c6 kamctl_build.patch
c1abf69b48847dc8c7ab0d11ef9adb531aa4635f9d44db6933981edc5a47df374664fb24867b19aa64abbcc9777bf1cd0360d9aea54e27b081065928c61e0f0b kamailio.cfg