diff --git a/Makefile b/Makefile index 86e4a4464936b7e06beb7ab8d005a934a81c0677..8894d28fe84ff274af66ecbee109a7a6d1a66a49 100755 --- a/Makefile +++ b/Makefile @@ -476,6 +476,7 @@ bininstall: all rm -f $(DESTDIR)$(ASTVARLIBDIR)/sounds/voicemail mkdir -p $(DESTDIR)$(ASTVARLIBDIR)/sounds mkdir -p $(DESTDIR)$(ASTLOGDIR)/cdr-csv + mkdir -p $(DESTDIR)$(ASTLOGDIR)/cdr-custom mkdir -p $(DESTDIR)$(ASTVARLIBDIR)/keys mkdir -p $(DESTDIR)$(ASTVARLIBDIR)/firmware mkdir -p $(DESTDIR)$(ASTVARLIBDIR)/firmware/iax diff --git a/UPGRADE.txt b/UPGRADE.txt index 89f2ed2a55e962b56c3a1dc01a74f3bdaa59fc8d..64836acf57e8e74c9920cab49e55dbbb45774057 100755 --- a/UPGRADE.txt +++ b/UPGRADE.txt @@ -26,3 +26,10 @@ Applications: * The CallerPres application has been removed. Use SetCallerPres instead. It accepts both numeric and symbolic names. + +Queues: + +* A queue is now considered empty not only if there are no members but if + none of the members are available (e.g. agents not logged on). To + restore the original behavior, use "leavewhenempty=strict" or + "joinwhenempty=strict" instead of "=yes" for those options. diff --git a/apps/app_queue.c b/apps/app_queue.c index 9e6ac2d64ba0255a804645e1869e543b66a09705..78783563de56b3189350983da5c07d4155b445a3 100755 --- a/apps/app_queue.c +++ b/apps/app_queue.c @@ -3,7 +3,7 @@ * * True call queues with optional send URL on answer * - * Copyright (C) 1999-2004, Digium, Inc. + * Copyright (C) 1999-2005, Digium, Inc. * * Mark Spencer <markster@digium.com> * @@ -14,8 +14,8 @@ * Each dynamic agent in each queue is now stored in the astdb. * When asterisk is restarted, each agent will be automatically * readded into their recorded queues. This feature can be - * configured with the 'peristent_members=<1|0>' KVP under the - * '[general]' group in queues.conf. The default is on. + * configured with the 'persistent_members=<1|0>' setting in the + * '[general]' category in queues.conf. The default is on. * * 2004-06-04: Priorities in queues added by inAccess Networks (work funded by Hellas On Line (HOL) www.hol.gr). * @@ -123,9 +123,11 @@ static char *descrip = " The optional URL will be sent to the called party if the channel supports\n" "it.\n" " The timeout will cause the queue to fail out after a specified number of\n" -"seconds, checked between each queues.conf 'timeout' and 'retry' cycle.\n"; +"seconds, checked between each queues.conf 'timeout' and 'retry' cycle.\n" +" This application sets the following channel variable upon completion:\n" +" QUEUESTATUS The status of the call as a text string, one of\n" +" TIMEOUT | FULL | JOINEMPTY | LEAVEEMPTY | JOINUNAVAIL | LEAVEUNAVAIL\n"; -/* PHM 06/26/03 */ static char *app_aqm = "AddQueueMember" ; static char *app_aqm_synopsis = "Dynamically adds queue members" ; static char *app_aqm_descrip = @@ -176,27 +178,35 @@ static char *app_upqm_descrip = static const char *pm_family = "/Queue/PersistentMembers"; /* The maximum lengh of each persistent member queue database entry */ #define PM_MAX_LEN 2048 + /* queues.conf [general] option */ static int queue_persistent_members = 0; + /* queues.conf per-queue weight option */ static int use_weight = 0; +enum queue_result { + QUEUE_UNKNOWN = 0, + QUEUE_TIMEOUT = 1, + QUEUE_JOINEMPTY = 2, + QUEUE_LEAVEEMPTY = 3, + QUEUE_JOINUNAVAIL = 4, + QUEUE_LEAVEUNAVAIL = 5, + QUEUE_FULL = 6, +}; -#define QUEUE_FLAG_RINGBACKONLY (1 << 0) -#define QUEUE_FLAG_MUSICONHOLD (1 << 1) -#define QUEUE_FLAG_DATAQUALITY (1 << 2) -#define QUEUE_FLAG_REDIR_IN (1 << 3) -#define QUEUE_FLAG_REDIR_OUT (1 << 4) -#define QUEUE_FLAG_DISCON_IN (1 << 5) -#define QUEUE_FLAG_DISCON_OUT (1 << 6) -#define QUEUE_FLAG_MONJOIN (1 << 7) /* Should we join the two files when we are done with the call */ -#define QUEUE_FLAG_DEAD (1 << 8) /* Whether the queue is dead or not */ -#define QUEUE_FLAG_JOINEMPTY (1 << 9) /* Do we care if the queue has no members? */ -#define QUEUE_FLAG_EVENTWHENCALLED (1 << 10) /* Generate an event when the agent is called (before pickup) */ -#define QUEUE_FLAG_LEAVEWHENEMPTY (1 << 11) /* If all agents leave the queue, remove callers from the queue */ -#define QUEUE_FLAG_REPORTHOLDTIME (1 << 12) /* Should we report caller hold time to answering member? */ -#define QUEUE_FLAG_WRAPPED (1 << 13) /* Round Robin - wrapped around? */ -#define QUEUE_FLAG_TIMEOUTRESTART (1 << 14) /* Restart timer when member call */ +const struct { + enum queue_result id; + char *text; +} queue_results[] = { + { QUEUE_UNKNOWN, "UNKNOWN" }, + { QUEUE_TIMEOUT, "TIMEOUT" }, + { QUEUE_JOINEMPTY,"JOINEMPTY" }, + { QUEUE_LEAVEEMPTY, "LEAVEEMPTY" }, + { QUEUE_JOINUNAVAIL, "JOINUNAVAIL" }, + { QUEUE_LEAVEUNAVAIL, "LEAVEUNAVAIL" }, + { QUEUE_FULL, "FULL" }, +}; /* We define a custom "local user" structure because we use it not only for keeping track of what is in use but @@ -208,7 +218,6 @@ struct localuser { int stillgoing; int metric; int oldstatus; - unsigned int flags; /* flag bits */ time_t lastcall; struct member *member; struct localuser *next; @@ -244,22 +253,37 @@ struct member { struct member *next; /* Next member */ }; +/* values used in multi-bit flags in ast_call_queue */ +#define QUEUE_EMPTY_NORMAL 1 +#define QUEUE_EMPTY_STRICT 2 +#define ANNOUNCEHOLDTIME_ALWAYS 1 +#define ANNOUNCEHOLDTIME_ONCE 2 + struct ast_call_queue { - ast_mutex_t lock; - char name[80]; /* Name of the queue */ - char moh[80]; /* Name of musiconhold to be used */ + ast_mutex_t lock; + char name[80]; /* Name */ + char moh[80]; /* Music On Hold class to be used */ char announce[80]; /* Announcement to play when call is answered */ - char context[80]; /* Context for this queue */ - unsigned int flags; /* flag bits */ - int strategy; /* Queueing strategy */ + char context[80]; /* Exit context */ + struct { + unsigned int monjoin:1; + unsigned int dead:1; + unsigned int joinempty:2; + unsigned int eventwhencalled:1; + unsigned int leavewhenempty:2; + unsigned int reportholdtime:1; + unsigned int wrapped:1; + unsigned int timeoutrestart:1; + unsigned int announceholdtime:2; + unsigned int strategy:3; + }; int announcefrequency; /* How often to announce their position */ int roundingseconds; /* How many seconds do we round to? */ - int announceholdtime; /* When to announce holdtime: 0 = never, -1 = every announcement, 1 = only once */ - int holdtime; /* Current avg holdtime for this queue, based on recursive boxcar filter */ + int holdtime; /* Current avg holdtime, based on recursive boxcar filter */ int callscompleted; /* Number of queue calls completed */ int callsabandoned; /* Number of queue calls abandoned */ int servicelevel; /* seconds setting for servicelevel*/ - int callscompletedinsl; /* Number of queue calls answered with servicelevel*/ + int callscompletedinsl; /* Number of calls answered with servicelevel*/ char monfmt[8]; /* Format to use when recording calls */ char sound_next[80]; /* Sound file: "Your call is now first in line" (def. queue-youarenext) */ char sound_thereare[80]; /* Sound file: "There are currently" (def. queue-thereare) */ @@ -271,26 +295,37 @@ struct ast_call_queue { char sound_thanks[80]; /* Sound file: "Thank you for your patience." (def. queue-thankyou) */ char sound_reporthold[80]; /* Sound file: "Hold time" (def. queue-reporthold) */ - int count; /* How many entries are in the queue */ - int maxlen; /* Max number of entries in queue */ + int count; /* How many entries */ + int maxlen; /* Max number of entries */ int wrapuptime; /* Wrapup Time */ int retry; /* Retry calling everyone after this amount of time */ int timeout; /* How long to wait for an answer */ - int weight; /* This queue's respective weight */ + int weight; /* Respective weight */ /* Queue strategy things */ int rrpos; /* Round Robin - position */ int memberdelay; /* Seconds to delay connecting member to caller */ - struct member *members; /* Member channels to be tried */ - struct queue_ent *head; /* Start of the actual queue */ + struct member *members; /* Head of the list of members */ + struct queue_ent *head; /* Head of the list of callers */ struct ast_call_queue *next; /* Next call queue */ }; static struct ast_call_queue *queues = NULL; AST_MUTEX_DEFINE_STATIC(qlock); +static void set_queue_result(struct ast_channel *chan, enum queue_result res) +{ + int i; + + for (i = 0; i < sizeof(queue_results) / sizeof(queue_results[0]); i++) { + if (queue_results[i].id == res) { + pbx_builtin_setvar_helper(chan, "QUEUESTATUS", queue_results[i].text); + return; + } + } +} static char *int2strat(int strategy) { @@ -313,8 +348,7 @@ static int strat2int(char *strategy) } /* Insert the 'new' entry after the 'prev' entry of queue 'q' */ -static inline void insert_entry(struct ast_call_queue *q, - struct queue_ent *prev, struct queue_ent *new, int *pos) +static inline void insert_entry(struct ast_call_queue *q, struct queue_ent *prev, struct queue_ent *new, int *pos) { struct queue_ent *cur; @@ -333,24 +367,31 @@ static inline void insert_entry(struct ast_call_queue *q, new->opos = *pos; } -static int has_no_members(struct ast_call_queue *q) +enum queue_member_status { + QUEUE_NO_MEMBERS, + QUEUE_NO_REACHABLE_MEMBERS, + QUEUE_NORMAL +}; + +static enum queue_member_status get_member_status(const struct ast_call_queue *q) { struct member *member; - int empty = 1; - member = q->members; - while(empty && member) { - switch(member->status) { - case AST_DEVICE_UNAVAILABLE: + enum queue_member_status result = QUEUE_NO_MEMBERS; + + for (member = q->members; member; member = member->next) { + switch (member->status) { case AST_DEVICE_INVALID: - /* Not logged on, etc */ + /* nothing to do */ + break; + case AST_DEVICE_UNAVAILABLE: + result = QUEUE_NO_REACHABLE_MEMBERS; break; default: - /* Not empty */ - empty = 0; + return QUEUE_NORMAL; } - member = member->next; } - return empty; + + return result; } struct statechange { @@ -372,7 +413,6 @@ static void *changethread(void *data) *loc = '\0'; loc++; } else { - ast_log(LOG_WARNING, "Can't change device '%s' with no technology!\n", sc->dev); free(sc); return NULL; } @@ -432,7 +472,7 @@ static int statechange_queue(const char *dev, int state, void *ign) return 0; } -static int join_queue(char *queuename, struct queue_ent *qe) +static int join_queue(char *queuename, struct queue_ent *qe, enum queue_result *reason) { struct ast_call_queue *q; struct queue_ent *cur, *prev = NULL; @@ -443,9 +483,17 @@ static int join_queue(char *queuename, struct queue_ent *qe) ast_mutex_lock(&qlock); for (q = queues; q; q = q->next) { if (!strcasecmp(q->name, queuename)) { + enum queue_member_status stat; /* This is our one */ ast_mutex_lock(&q->lock); - if ((!has_no_members(q) || ast_test_flag(q, QUEUE_FLAG_JOINEMPTY)) && (!q->maxlen || (q->count < q->maxlen))) { + stat = get_member_status(q); + if (!q->joinempty && (stat == QUEUE_NO_MEMBERS)) + *reason = QUEUE_JOINEMPTY; + else if ((q->joinempty == QUEUE_EMPTY_NORMAL) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) + *reason = QUEUE_JOINUNAVAIL; + else if (q->maxlen && (q->count >= q->maxlen)) + *reason = QUEUE_FULL; + else { /* There's space for us, put us at the right position inside * the queue. * Take into account the priority of the calling user */ @@ -494,6 +542,7 @@ static void free_members(struct ast_call_queue *q, int all) { /* Free non-dynamic members */ struct member *curm, *next, *prev; + curm = q->members; prev = NULL; while(curm) { @@ -513,6 +562,7 @@ static void free_members(struct ast_call_queue *q, int all) static void destroy_queue(struct ast_call_queue *q) { struct ast_call_queue *cur, *prev = NULL; + ast_mutex_lock(&qlock); for (cur = queues; cur; cur = cur->next) { if (cur == q) { @@ -591,7 +641,8 @@ static int say_position(struct queue_ent *qe) /* If the hold time is >1 min, if it's enabled, and if it's not supposed to be only once and we have already said it, say it */ - if ((avgholdmins+avgholdsecs) > 0 && (qe->parent->announceholdtime) && (!(qe->parent->announceholdtime==1 && qe->last_pos)) ) { + if ((avgholdmins+avgholdsecs) > 0 && (qe->parent->announceholdtime) && + (!(qe->parent->announceholdtime == ANNOUNCEHOLDTIME_ONCE) && qe->last_pos)) { res += play_file(qe->chan, qe->parent->sound_holdtime); if(avgholdmins>0) { if (avgholdmins < 2) { @@ -652,6 +703,7 @@ static void leave_queue(struct queue_ent *qe) struct ast_call_queue *q; struct queue_ent *cur, *prev = NULL; int pos = 0; + q = qe->parent; if (!q) return; @@ -683,16 +735,17 @@ ast_log(LOG_NOTICE, "Queue '%s' Leave, Channel '%s'\n", q->name, qe->chan->name cur = cur->next; } ast_mutex_unlock(&q->lock); - if (ast_test_flag(q, QUEUE_FLAG_DEAD) && !q->count) { + if (q->dead && !q->count) { /* It's dead and nobody is in it, so kill it */ destroy_queue(q); } } -static void hanguptree(struct localuser *outgoing, struct ast_channel *exception) +/* Hang up a list of outgoing calls */ +static void hangupcalls(struct localuser *outgoing, struct ast_channel *exception) { - /* Hang up a tree of stuff */ struct localuser *oo; + while(outgoing) { /* Hangup any existing lines we have open */ if (outgoing->chan && (outgoing->chan != exception)) @@ -706,6 +759,7 @@ static void hanguptree(struct localuser *outgoing, struct ast_channel *exception static int update_status(struct ast_call_queue *q, struct member *member, int status) { struct member *cur; + /* Since a reload could have taken place, we have to traverse the list to be sure it's still valid */ ast_mutex_lock(&q->lock); @@ -746,10 +800,10 @@ static int update_dial_status(struct ast_call_queue *q, struct member *member, i return update_status(q, member, status); } -static int compare_weight(struct ast_call_queue *rq, struct member *member) -{ /* traverse all defined queues which have calls waiting and contain this member return 0 if no other queue has precedence (higher weight) or 1 if found */ +static int compare_weight(struct ast_call_queue *rq, struct member *member) +{ struct ast_call_queue *q; struct member *mem; int found = 0; @@ -780,8 +834,6 @@ static int compare_weight(struct ast_call_queue *rq, struct member *member) return found; } - - static int ring_entry(struct queue_ent *qe, struct localuser *tmp, int *busies) { int res; @@ -876,7 +928,7 @@ static int ring_entry(struct queue_ent *qe, struct localuser *tmp, int *busies) (*busies)++; return 0; } else { - if (ast_test_flag(qe->parent, QUEUE_FLAG_EVENTWHENCALLED)) { + if (qe->parent->eventwhencalled) { manager_event(EVENT_FLAG_AGENT, "AgentCalled", "AgentCalled: %s\r\n" "ChannelCalling: %s\r\n" @@ -901,6 +953,7 @@ static int ring_one(struct queue_ent *qe, struct localuser *outgoing, int *busie struct localuser *cur; struct localuser *best; int bestmetric=0; + do { best = NULL; cur = outgoing; @@ -946,6 +999,7 @@ static int store_next(struct queue_ent *qe, struct localuser *outgoing) struct localuser *cur; struct localuser *best; int bestmetric=0; + best = NULL; cur = outgoing; while(cur) { @@ -964,7 +1018,7 @@ static int store_next(struct queue_ent *qe, struct localuser *outgoing) qe->parent->rrpos = best->metric % 1000; } else { /* Just increment rrpos */ - if (!ast_test_flag(qe->parent, QUEUE_FLAG_WRAPPED)) { + if (qe->parent->wrapped) { /* No more channels, start over */ qe->parent->rrpos = 0; } else { @@ -972,13 +1026,14 @@ static int store_next(struct queue_ent *qe, struct localuser *outgoing) qe->parent->rrpos++; } } - ast_clear_flag(qe->parent, QUEUE_FLAG_WRAPPED); + qe->parent->wrapped = 0; return 0; } static int valid_exit(struct queue_ent *qe, char digit) { char tmp[2]; + if (ast_strlen_zero(qe->context)) return 0; tmp[0] = digit; @@ -994,7 +1049,7 @@ static int valid_exit(struct queue_ent *qe, char digit) #define AST_MAX_WATCHERS 256 -#define BUILD_STATS do { \ +#define BUILD_WATCHERS do { \ o = outgoing; \ found = -1; \ pos = 1; \ @@ -1014,7 +1069,7 @@ static int valid_exit(struct queue_ent *qe, char digit) } \ } while(0) -static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser *outgoing, int *to, struct ast_flags *flags, char *digit, int prebusies) +static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser *outgoing, int *to, char *digit, int prebusies, int caller_disconnect) { char *queue = qe->parent->name; struct localuser *o; @@ -1034,12 +1089,12 @@ static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser struct ast_channel *in = qe->chan; while(*to && !peer) { - BUILD_STATS; + BUILD_WATCHERS; if ((found < 0) && stillgoing && !qe->parent->strategy) { /* On "ringall" strategy we only move to the next penalty level when *all* ringing phones are done in the current penalty level */ ring_one(qe, outgoing, &numbusies); - BUILD_STATS; + BUILD_WATCHERS; } if (found < 0) { if (numlines == (numbusies + numnochan)) { @@ -1058,7 +1113,6 @@ static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser if (option_verbose > 2) ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name); peer = o; - ast_copy_flags(flags, o, QUEUE_FLAG_REDIR_IN | QUEUE_FLAG_REDIR_OUT | QUEUE_FLAG_DISCON_IN | QUEUE_FLAG_DISCON_OUT); } } else if (o->chan && (o->chan == winner)) { if (!ast_strlen_zero(o->chan->call_forward)) { @@ -1141,11 +1195,9 @@ static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser case AST_CONTROL_ANSWER: /* This is our guy if someone answered. */ if (!peer) { - ast_copy_flags(flags, o, QUEUE_FLAG_REDIR_IN | QUEUE_FLAG_REDIR_OUT | QUEUE_FLAG_DISCON_IN | QUEUE_FLAG_DISCON_OUT); if (option_verbose > 2) ast_verbose( VERBOSE_PREFIX_3 "%s answered %s\n", o->chan->name, in->name); peer = o; - ast_copy_flags(flags, o, QUEUE_FLAG_REDIR_IN & QUEUE_FLAG_REDIR_OUT & QUEUE_FLAG_DISCON_IN & QUEUE_FLAG_DISCON_OUT); } break; case AST_CONTROL_BUSY: @@ -1157,7 +1209,7 @@ static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser ast_hangup(o->chan); o->chan = NULL; if (qe->parent->strategy) { - if (ast_test_flag(qe->parent, QUEUE_FLAG_TIMEOUTRESTART)) + if (qe->parent->timeoutrestart) *to = orig; ring_one(qe, outgoing, &numbusies); } @@ -1172,7 +1224,7 @@ static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser ast_hangup(o->chan); o->chan = NULL; if (qe->parent->strategy) { - if (ast_test_flag(qe->parent, QUEUE_FLAG_TIMEOUTRESTART)) + if (qe->parent->timeoutrestart) *to = orig; ring_one(qe, outgoing, &numbusies); } @@ -1201,7 +1253,7 @@ static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser ast_hangup(o->chan); o->chan = NULL; if (qe->parent->strategy) { - if (ast_test_flag(qe->parent, QUEUE_FLAG_TIMEOUTRESTART)) + if (qe->parent->timeoutrestart) *to = orig; ring_one(qe, outgoing, &numbusies); } @@ -1222,7 +1274,7 @@ static struct localuser *wait_for_answer(struct queue_ent *qe, struct localuser *to=-1; return NULL; } - if (f && (f->frametype == AST_FRAME_DTMF) && ast_test_flag(flags, QUEUE_FLAG_DISCON_OUT) && (f->subclass == '*')) { + if (f && (f->frametype == AST_FRAME_DTMF) && caller_disconnect && (f->subclass == '*')) { if (option_verbose > 3) ast_verbose(VERBOSE_PREFIX_3 "User hit %c to disconnect call.\n", f->subclass); *to=0; @@ -1264,21 +1316,35 @@ static int is_our_turn(struct queue_ent *qe) return res; } -static int wait_our_turn(struct queue_ent *qe, int ringing) +static int wait_our_turn(struct queue_ent *qe, int ringing, enum queue_result *reason) { int res = 0; /* This is the holding pen for callers 2 through maxlen */ for (;;) { + enum queue_member_status stat; + if (is_our_turn(qe)) break; /* If we have timed out, break out */ - if (qe->expire && (time(NULL) > qe->expire)) + if (qe->expire && (time(NULL) > qe->expire)) { + *reason = QUEUE_TIMEOUT; break; + } + + stat = get_member_status(qe->parent); /* leave the queue if no agents, if enabled */ - if (ast_test_flag(qe->parent, QUEUE_FLAG_LEAVEWHENEMPTY) && has_no_members(qe->parent)) { + if (qe->parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) { + *reason = QUEUE_LEAVEEMPTY; + leave_queue(qe); + break; + } + + /* leave the queue if no reachable agents, if enabled */ + if ((qe->parent->leavewhenempty == QUEUE_EMPTY_NORMAL) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) { + *reason = QUEUE_LEAVEUNAVAIL; leave_queue(qe); break; } @@ -1298,6 +1364,7 @@ static int wait_our_turn(struct queue_ent *qe, int ringing) static int update_queue(struct ast_call_queue *q, struct member *member) { struct member *cur; + /* Since a reload could have taken place, we have to traverse the list to be sure it's still valid */ ast_mutex_lock(&q->lock); @@ -1324,24 +1391,23 @@ static int calc_metric(struct ast_call_queue *q, struct member *mem, int pos, st break; case QUEUE_STRATEGY_ROUNDROBIN: if (!pos) { - if (!ast_test_flag(q, QUEUE_FLAG_WRAPPED)) { + if (!q->wrapped) { /* No more channels, start over */ q->rrpos = 0; } else { /* Prioritize next entry */ q->rrpos++; } - ast_clear_flag(q, QUEUE_FLAG_WRAPPED); + q->wrapped = 0; } /* Fall through */ case QUEUE_STRATEGY_RRMEMORY: if (pos < q->rrpos) { tmp->metric = 1000 + pos; } else { - if (pos > q->rrpos) { + if (pos > q->rrpos) /* Indicate there is another priority */ - ast_set_flag(q, QUEUE_FLAG_WRAPPED); - } + q->wrapped = 1; tmp->metric = pos; } tmp->metric += mem->penalty * 1000000; @@ -1368,32 +1434,56 @@ static int calc_metric(struct ast_call_queue *q, struct member *mem, int pos, st return 0; } -static int try_calling(struct queue_ent *qe, char *ooptions, char *announceoverride, char *url, int *go_on) +static int try_calling(struct queue_ent *qe, const char *options, char *announceoverride, const char *url, int *go_on) { struct member *cur; struct localuser *outgoing=NULL, *tmp = NULL; int to; - struct ast_flags flags; char restofit[AST_MAX_EXTENSION]; char oldexten[AST_MAX_EXTENSION]=""; char oldcontext[AST_MAX_EXTENSION]=""; char queuename[256]=""; char *newnum; - char *options; char *monitorfilename; struct ast_channel *peer; struct ast_channel *which; struct localuser *lpeer; struct member *member; int res = 0, bridge = 0; - int zapx = 2; int numbusies = 0; int x=0; char *announce = NULL; char digit = 0; time_t callstart; time_t now; - struct ast_bridge_config config; + struct ast_bridge_config bridge_config; + char nondataquality = 1; + + memset(&bridge_config, 0, sizeof(bridge_config)); + + for (; options && *options; options++) + switch (*options) { + case 't': + ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_REDIRECT); + break; + case 'T': + ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_REDIRECT); + break; + case 'd': + nondataquality = 0; + break; + case 'h': + ast_set_flag(&(bridge_config.features_callee), AST_FEATURE_DISCONNECT); + break; + case 'H': + ast_set_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT); + break; + case 'n': + if ((now - qe->start >= qe->parent->timeout)) + *go_on = 1; + break; + } + /* Hold the lock while we setup the outgoing calls */ if (use_weight) ast_mutex_lock(&qlock); @@ -1408,9 +1498,9 @@ static int try_calling(struct queue_ent *qe, char *ooptions, char *announceoverr announce = qe->announce; if (announceoverride && !ast_strlen_zero(announceoverride)) announce = announceoverride; + while(cur) { - /* Get a technology/[device:]number pair */ - tmp = malloc(sizeof(struct localuser)); + tmp = malloc(sizeof(*tmp)); if (!tmp) { ast_mutex_unlock(&qe->parent->lock); if (use_weight) @@ -1418,37 +1508,8 @@ static int try_calling(struct queue_ent *qe, char *ooptions, char *announceoverr ast_log(LOG_WARNING, "Out of memory\n"); goto out; } - memset(tmp, 0, sizeof(struct localuser)); + memset(tmp, 0, sizeof(*tmp)); tmp->stillgoing = -1; - options = ooptions; - for (; options && *options; options++) - switch (*options) { - case 't': - ast_set_flag(tmp, QUEUE_FLAG_REDIR_IN); - break; - case 'T': - ast_set_flag(tmp, QUEUE_FLAG_REDIR_OUT); - break; - case 'r': - ast_set_flag(tmp, QUEUE_FLAG_RINGBACKONLY); - break; - case 'm': - ast_set_flag(tmp, QUEUE_FLAG_MUSICONHOLD); - break; - case 'd': - ast_set_flag(tmp, QUEUE_FLAG_DATAQUALITY); - break; - case 'h': - ast_set_flag(tmp, QUEUE_FLAG_DISCON_IN); - break; - case 'H': - ast_set_flag(tmp, QUEUE_FLAG_DISCON_OUT); - break; - case 'n': - if ((now - qe->start >= qe->parent->timeout)) - *go_on = 1; - break; - } if (option_debug) { if (url) ast_log(LOG_DEBUG, "Queue with URL=%s_\n", url); @@ -1490,7 +1551,7 @@ static int try_calling(struct queue_ent *qe, char *ooptions, char *announceoverr ast_mutex_unlock(&qe->parent->lock); if (use_weight) ast_mutex_unlock(&qlock); - lpeer = wait_for_answer(qe, outgoing, &to, &flags, &digit, numbusies); + lpeer = wait_for_answer(qe, outgoing, &to, &digit, numbusies, ast_test_flag(&(bridge_config.features_caller), AST_FEATURE_DISCONNECT)); ast_mutex_lock(&qe->parent->lock); if (qe->parent->strategy == QUEUE_STRATEGY_RRMEMORY) { store_next(qe, outgoing); @@ -1521,20 +1582,16 @@ static int try_calling(struct queue_ent *qe, char *ooptions, char *announceoverr we will always return with -1 so that it is hung up properly after the conversation. */ qe->handled++; - if (!strcmp(qe->chan->type,"Zap")) { - zapx = !ast_test_flag(tmp, QUEUE_FLAG_DATAQUALITY); - ast_channel_setoption(qe->chan,AST_OPTION_TONE_VERIFY,&zapx,sizeof(char),0); - } - if (!strcmp(peer->type,"Zap")) { - zapx = !ast_test_flag(tmp, QUEUE_FLAG_DATAQUALITY); - ast_channel_setoption(peer,AST_OPTION_TONE_VERIFY,&zapx,sizeof(char),0); - } + if (!strcmp(qe->chan->type,"Zap")) + ast_channel_setoption(qe->chan, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0); + if (!strcmp(peer->type,"Zap")) + ast_channel_setoption(peer, AST_OPTION_TONE_VERIFY, &nondataquality, sizeof(nondataquality), 0); /* Update parameters for the queue */ recalc_holdtime(qe); member = lpeer->member; - hanguptree(outgoing, peer); + hangupcalls(outgoing, peer); outgoing = NULL; - if (announce || ast_test_flag(qe->parent, QUEUE_FLAG_REPORTHOLDTIME) || qe->parent->memberdelay) { + if (announce || qe->parent->reportholdtime || qe->parent->memberdelay) { int res2; res2 = ast_autoservice_start(qe->chan); if (!res2) { @@ -1546,7 +1603,7 @@ static int try_calling(struct queue_ent *qe, char *ooptions, char *announceoverr if (play_file(peer, announce)) ast_log(LOG_WARNING, "Announcement file '%s' is unavailable, continuing anyway...\n", announce); } - if (!res2 && ast_test_flag(qe->parent, QUEUE_FLAG_REPORTHOLDTIME)) { + if (!res2 && qe->parent->reportholdtime) { if (!play_file(peer, qe->parent->sound_reporthold)) { int holdtime; time_t now; @@ -1567,13 +1624,13 @@ static int try_calling(struct queue_ent *qe, char *ooptions, char *announceoverr /* Agent must have hung up */ ast_log(LOG_WARNING, "Agent on %s hungup on the customer. They're going to be pissed.\n", peer->name); ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "AGENTDUMP", "%s", ""); - if (ast_test_flag(qe->parent, QUEUE_FLAG_EVENTWHENCALLED)) { + if (qe->parent->eventwhencalled) { manager_event(EVENT_FLAG_AGENT, "AgentDump", - "Queue: %s\r\n" - "Uniqueid: %s\r\n" - "Channel: %s\r\n" - "Member: %s\r\n", - queuename, qe->chan->uniqueid, peer->name, member->interface); + "Queue: %s\r\n" + "Uniqueid: %s\r\n" + "Channel: %s\r\n" + "Member: %s\r\n", + queuename, qe->chan->uniqueid, peer->name, member->interface); } ast_hangup(peer); goto out; @@ -1602,80 +1659,68 @@ static int try_calling(struct queue_ent *qe, char *ooptions, char *announceoverr /* Begin Monitoring */ if (qe->parent->monfmt && *qe->parent->monfmt) { monitorfilename = pbx_builtin_getvar_helper(qe->chan, "MONITOR_FILENAME"); - if(pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper( qe->chan, "MONITOR_EXEC_ARGS")) + if (pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC") || pbx_builtin_getvar_helper(qe->chan, "MONITOR_EXEC_ARGS")) which = qe->chan; else which = peer; - if(monitorfilename) { + if (monitorfilename) ast_monitor_start(which, qe->parent->monfmt, monitorfilename, 1 ); - } else { + else ast_monitor_start(which, qe->parent->monfmt, qe->chan->cdr->uniqueid, 1 ); - } - if(ast_test_flag(qe->parent, QUEUE_FLAG_MONJOIN)) { + if (qe->parent->monjoin) ast_monitor_setjoinfiles(which, 1); - } } /* Drop out of the queue at this point, to prepare for next caller */ leave_queue(qe); - if( url && !ast_strlen_zero(url) && ast_channel_supports_html(peer) ) { + if (url && !ast_strlen_zero(url) && ast_channel_supports_html(peer)) { if (option_debug) ast_log(LOG_DEBUG, "app_queue: sendurl=%s.\n", url); - ast_channel_sendurl( peer, url ); + ast_channel_sendurl(peer, url); } ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "CONNECT", "%ld", (long)time(NULL) - qe->start); - if (ast_test_flag(qe->parent, QUEUE_FLAG_EVENTWHENCALLED)) { + if (qe->parent->eventwhencalled) manager_event(EVENT_FLAG_AGENT, "AgentConnect", - "Queue: %s\r\n" - "Uniqueid: %s\r\n" - "Channel: %s\r\n" - "Member: %s\r\n" - "Holdtime: %ld\r\n", - queuename, qe->chan->uniqueid, peer->name, member->interface, (long)time(NULL) - qe->start); - } + "Queue: %s\r\n" + "Uniqueid: %s\r\n" + "Channel: %s\r\n" + "Member: %s\r\n" + "Holdtime: %ld\r\n", + queuename, qe->chan->uniqueid, peer->name, member->interface, + (long)time(NULL) - qe->start); strncpy(oldcontext, qe->chan->context, sizeof(oldcontext) - 1); strncpy(oldexten, qe->chan->exten, sizeof(oldexten) - 1); time(&callstart); - memset(&config,0,sizeof(struct ast_bridge_config)); - - if (ast_test_flag(&flags, QUEUE_FLAG_REDIR_IN)) - ast_set_flag(&(config.features_callee), AST_FEATURE_REDIRECT); - if (ast_test_flag(&flags, QUEUE_FLAG_REDIR_OUT)) - ast_set_flag(&(config.features_caller), AST_FEATURE_REDIRECT); - if (ast_test_flag(&flags, QUEUE_FLAG_DISCON_IN)) - ast_set_flag(&(config.features_callee), AST_FEATURE_DISCONNECT); - if (ast_test_flag(&flags, QUEUE_FLAG_DISCON_OUT)) - ast_set_flag(&(config.features_caller), AST_FEATURE_DISCONNECT); - bridge = ast_bridge_call(qe->chan,peer,&config); + bridge = ast_bridge_call(qe->chan,peer, &bridge_config); if (strcasecmp(oldcontext, qe->chan->context) || strcasecmp(oldexten, qe->chan->exten)) { ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "TRANSFER", "%s|%s", qe->chan->exten, qe->chan->context); } else if (qe->chan->_softhangup) { - ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETECALLER", "%ld|%ld", (long)(callstart - qe->start), (long)(time(NULL) - callstart)); - if (ast_test_flag(qe->parent, QUEUE_FLAG_EVENTWHENCALLED)) { + ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETECALLER", "%ld|%ld", + (long)(callstart - qe->start), (long)(time(NULL) - callstart)); + if (qe->parent->eventwhencalled) manager_event(EVENT_FLAG_AGENT, "AgentComplete", - "Queue: %s\r\n" - "Uniqueid: %s\r\n" - "Channel: %s\r\n" - "Member: %s\r\n" - "HoldTime: %ld\r\n" - "TalkTime: %ld\r\n" - "Reason: caller\r\n", - queuename, qe->chan->uniqueid, peer->name, member->interface, (long)(callstart - qe->start), (long)(time(NULL) - callstart)); - } + "Queue: %s\r\n" + "Uniqueid: %s\r\n" + "Channel: %s\r\n" + "Member: %s\r\n" + "HoldTime: %ld\r\n" + "TalkTime: %ld\r\n" + "Reason: caller\r\n", + queuename, qe->chan->uniqueid, peer->name, member->interface, + (long)(callstart - qe->start), (long)(time(NULL) - callstart)); } else { ast_queue_log(queuename, qe->chan->uniqueid, peer->name, "COMPLETEAGENT", "%ld|%ld", (long)(callstart - qe->start), (long)(time(NULL) - callstart)); - if (ast_test_flag(qe->parent, QUEUE_FLAG_EVENTWHENCALLED)) { + if (qe->parent->eventwhencalled) manager_event(EVENT_FLAG_AGENT, "AgentComplete", - "Queue: %s\r\n" - "Uniqueid: %s\r\n" - "Channel: %s\r\n" - "HoldTime: %ld\r\n" - "TalkTime: %ld\r\n" - "Reason: agent\r\n", - queuename, qe->chan->uniqueid, peer->name, (long)(callstart - qe->start), (long)(time(NULL) - callstart)); - } - + "Queue: %s\r\n" + "Uniqueid: %s\r\n" + "Channel: %s\r\n" + "HoldTime: %ld\r\n" + "TalkTime: %ld\r\n" + "Reason: agent\r\n", + queuename, qe->chan->uniqueid, peer->name, (long)(callstart - qe->start), + (long)(time(NULL) - callstart)); } if(bridge != AST_PBX_NO_HANGUP_PEER) @@ -1687,7 +1732,7 @@ static int try_calling(struct queue_ent *qe, char *ooptions, char *announceoverr res = bridge; /* bridge error, stay in the queue */ } out: - hanguptree(outgoing, NULL); + hangupcalls(outgoing, NULL); return res; } @@ -1695,11 +1740,10 @@ static int wait_a_bit(struct queue_ent *qe) { /* Don't need to hold the lock while we setup the outgoing calls */ int retrywait = qe->parent->retry * 1000; + return ast_waitfordigit(qe->chan, retrywait); } -/* [PHM 06/26/03] */ - static struct member * interface_exists(struct ast_call_queue *q, char *interface) { struct member *mem; @@ -2236,6 +2280,7 @@ static int queue_exec(struct ast_channel *chan, void *data) char *user_priority; int prio; char *queuetimeoutstr = NULL; + enum queue_result reason = QUEUE_UNKNOWN; /* whether to exit Queue application after the timeout hits */ int go_on = 0; @@ -2274,10 +2319,10 @@ static int queue_exec(struct ast_channel *chan, void *data) if (sscanf(user_priority, "%d", &prio) == 1) { if (option_debug) ast_log(LOG_DEBUG, "%s: Got priority %d from ${QUEUE_PRIO}.\n", - chan->name, prio); + chan->name, prio); } else { ast_log(LOG_WARNING, "${QUEUE_PRIO}: Invalid value (%s), channel %s.\n", - user_priority, chan->name); + user_priority, chan->name); prio = 0; } } else { @@ -2286,23 +2331,20 @@ static int queue_exec(struct ast_channel *chan, void *data) prio = 0; } - if (options) { - if (strchr(options, 'r')) { - ringing = 1; - } - } + if (options && (strchr(options, 'r'))) + ringing = 1; if (option_debug) ast_log(LOG_DEBUG, "queue: %s, options: %s, url: %s, announce: %s, expires: %ld, priority: %d\n", - queuename, options, url, announceoverride, (long)qe.expire, (int)prio); + queuename, options, url, announceoverride, (long)qe.expire, (int)prio); qe.chan = chan; qe.prio = (int)prio; qe.last_pos_said = 0; qe.last_pos = 0; - if (!join_queue(queuename, &qe)) { - ast_queue_log(queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", url ? url : "", chan->cid.cid_num ? chan->cid.cid_num : ""); - /* Start music on hold */ + if (!join_queue(queuename, &qe, &reason)) { + ast_queue_log(queuename, chan->uniqueid, "NONE", "ENTERQUEUE", "%s|%s", url ? url : "", + chan->cid.cid_num ? chan->cid.cid_num : ""); check_turns: if (ringing) { ast_indicate(chan, AST_CONTROL_RINGING); @@ -2312,7 +2354,7 @@ check_turns: for (;;) { /* This is the wait loop for callers 2 through maxlen */ - res = wait_our_turn(&qe, ringing); + res = wait_our_turn(&qe, ringing, &reason); /* If they hungup, return immediately */ if (res < 0) { /* Record this abandoned call */ @@ -2339,8 +2381,11 @@ check_turns: /* they may dial a digit from the queue context; */ /* or, they may timeout. */ + enum queue_member_status stat; + /* Leave if we have exceeded our queuetimeout */ if (qe.expire && (time(NULL) > qe.expire)) { + reason = QUEUE_TIMEOUT; res = 0; break; } @@ -2363,14 +2408,25 @@ check_turns: break; } + stat = get_member_status(qe.parent); + /* leave the queue if no agents, if enabled */ - if (ast_test_flag(qe.parent, QUEUE_FLAG_LEAVEWHENEMPTY) && has_no_members(qe.parent)) { + if (qe.parent->leavewhenempty && (stat == QUEUE_NO_MEMBERS)) { + reason = QUEUE_LEAVEEMPTY; + res = 0; + break; + } + + /* leave the queue if no reachable agents, if enabled */ + if ((qe.parent->leavewhenempty == QUEUE_EMPTY_NORMAL) && (stat == QUEUE_NO_REACHABLE_MEMBERS)) { + reason = QUEUE_LEAVEUNAVAIL; res = 0; break; } /* Leave if we have exceeded our queuetimeout */ if (qe.expire && (time(NULL) > qe.expire)) { + reason = QUEUE_TIMEOUT; res = 0; break; } @@ -2396,6 +2452,7 @@ check_turns: res = -1; } ast_queue_log(queuename, chan->uniqueid, "NONE", "EXITWITHTIMEOUT", "%d", qe.pos); + reason = QUEUE_TIMEOUT; res = 0; break; } @@ -2422,9 +2479,12 @@ check_turns: ast_stopstream(chan); } leave_queue(&qe); + if (reason != QUEUE_UNKNOWN) + set_queue_result(chan, reason); } else { ast_log(LOG_WARNING, "Unable to join queue '%s'\n", queuename); - res = 0; + set_queue_result(chan, reason); + res = 0; } LOCAL_USER_REMOVE(u); return res; @@ -2450,7 +2510,7 @@ static void reload_queues(void) /* Mark all queues as dead for the moment */ q = queues; while(q) { - ast_set_flag(q, QUEUE_FLAG_DEAD); + q->dead = 1; q = q->next; } /* Chug through config file */ @@ -2480,7 +2540,7 @@ static void reload_queues(void) if (!new) ast_mutex_lock(&q->lock); /* Re-initialize the queue */ - ast_clear_flag(q, QUEUE_FLAG_DEAD); + q->dead = 0; q->retry = DEFAULT_RETRY; q->timeout = -1; q->maxlen = 0; @@ -2545,7 +2605,7 @@ static void reload_queues(void) } else if (!strcasecmp(var->name, "timeout")) { q->timeout = atoi(var->value); } else if (!strcasecmp(var->name, "monitor-join")) { - ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_MONJOIN); + q->monjoin = ast_true(var->value); } else if (!strcasecmp(var->name, "monitor-format")) { strncpy(q->monfmt, var->value, sizeof(q->monfmt) - 1); } else if (!strcasecmp(var->name, "queue-youarenext")) { @@ -2575,7 +2635,12 @@ static void reload_queues(void) q->roundingseconds=0; } } else if (!strcasecmp(var->name, "announce-holdtime")) { - q->announceholdtime = (!strcasecmp(var->value,"once")) ? 1 : ast_true(var->value); + if (!strcasecmp(var->value, "once")) + q->announceholdtime = ANNOUNCEHOLDTIME_ONCE; + else if (ast_true(var->value)) + q->announceholdtime = ANNOUNCEHOLDTIME_ALWAYS; + else + q->announceholdtime = 0; } else if (!strcasecmp(var->name, "retry")) { q->retry = atoi(var->value); } else if (!strcasecmp(var->name, "wrapuptime")) { @@ -2591,13 +2656,23 @@ static void reload_queues(void) q->strategy = 0; } } else if (!strcasecmp(var->name, "joinempty")) { - ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_JOINEMPTY); + if (!strcasecmp(var->value, "strict")) + q->joinempty = QUEUE_EMPTY_STRICT; + else if (ast_true(var->value)) + q->joinempty = QUEUE_EMPTY_NORMAL; + else + q->joinempty = 0; } else if (!strcasecmp(var->name, "leavewhenempty")) { - ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_LEAVEWHENEMPTY); + if (!strcasecmp(var->value, "strict")) + q->leavewhenempty = QUEUE_EMPTY_STRICT; + else if (ast_true(var->value)) + q->leavewhenempty = QUEUE_EMPTY_NORMAL; + else + q->leavewhenempty = 0; } else if (!strcasecmp(var->name, "eventwhencalled")) { - ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_EVENTWHENCALLED); + q->eventwhencalled = ast_true(var->value); } else if (!strcasecmp(var->name, "reportholdtime")) { - ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_REPORTHOLDTIME); + q->reportholdtime = ast_true(var->value); } else if (!strcasecmp(var->name, "memberdelay")) { q->memberdelay = atoi(var->value); } else if (!strcasecmp(var->name, "weight")) { @@ -2605,7 +2680,7 @@ static void reload_queues(void) if (q->weight) use_weight++; } else if (!strcasecmp(var->name, "timeoutrestart")) { - ast_set2_flag(q, ast_true(var->value), QUEUE_FLAG_TIMEOUTRESTART); + q->timeoutrestart = ast_true(var->value); } else { ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s at line %d of queue.conf\n", cat, var->name, var->lineno); } @@ -2637,7 +2712,7 @@ static void reload_queues(void) ql = NULL; while(q) { qn = q->next; - if (ast_test_flag(q, QUEUE_FLAG_DEAD)) { + if (q->dead) { if (ql) ql->next = q->next; else diff --git a/channel.c b/channel.c index d2ac71a2473a975d9dfc67993717fbd041d35cd6..ba42f9ad247c38aa3307e13a1f4e5d2fe5c2445c 100755 --- a/channel.c +++ b/channel.c @@ -2219,14 +2219,14 @@ int ast_channel_supports_html(struct ast_channel *chan) return 0; } -int ast_channel_sendhtml(struct ast_channel *chan, int subclass, char *data, int datalen) +int ast_channel_sendhtml(struct ast_channel *chan, int subclass, const char *data, int datalen) { if (chan->tech->send_html) return chan->tech->send_html(chan, subclass, data, datalen); return -1; } -int ast_channel_sendurl(struct ast_channel *chan, char *url) +int ast_channel_sendurl(struct ast_channel *chan, const char *url) { if (chan->tech->send_html) return chan->tech->send_html(chan, AST_HTML_URL, url, strlen(url) + 1); diff --git a/channels/chan_agent.c b/channels/chan_agent.c index 1d592827bf193f16ab6e3e87d22172efa238efb9..9043eaf8cb85520a1ce129748a77aa68f1495993 100755 --- a/channels/chan_agent.c +++ b/channels/chan_agent.c @@ -201,7 +201,7 @@ static int agent_hangup(struct ast_channel *ast); static int agent_answer(struct ast_channel *ast); static struct ast_frame *agent_read(struct ast_channel *ast); static int agent_write(struct ast_channel *ast, struct ast_frame *f); -static int agent_sendhtml(struct ast_channel *ast, int subclass, char *data, int datalen); +static int agent_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen); static int agent_indicate(struct ast_channel *ast, int condition); static int agent_fixup(struct ast_channel *oldchan, struct ast_channel *newchan); static struct ast_channel *agent_bridgedchannel(struct ast_channel *chan, struct ast_channel *bridge); @@ -450,7 +450,7 @@ static struct ast_frame *agent_read(struct ast_channel *ast) return f; } -static int agent_sendhtml(struct ast_channel *ast, int subclass, char *data, int datalen) +static int agent_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen) { struct agent_pvt *p = ast->tech_pvt; int res = -1; diff --git a/channels/chan_iax2.c b/channels/chan_iax2.c index 6c852cf018600bef87b284618f2734162d6db8c7..c44dc97f1e633d248795724f8d24b4c8db8c73cd 100755 --- a/channels/chan_iax2.c +++ b/channels/chan_iax2.c @@ -653,11 +653,11 @@ static ast_mutex_t iaxsl[IAX_MAX_CALLS]; static struct timeval lastused[IAX_MAX_CALLS]; -static int send_command(struct chan_iax2_pvt *, char, int, unsigned int, char *, int, int); -static int send_command_locked(unsigned short callno, char, int, unsigned int, char *, int, int); -static int send_command_immediate(struct chan_iax2_pvt *, char, int, unsigned int, char *, int, int); -static int send_command_final(struct chan_iax2_pvt *, char, int, unsigned int, char *, int, int); -static int send_command_transfer(struct chan_iax2_pvt *, char, int, unsigned int, char *, int); +static int send_command(struct chan_iax2_pvt *, char, int, unsigned int, const char *, int, int); +static int send_command_locked(unsigned short callno, char, int, unsigned int, const char *, int, int); +static int send_command_immediate(struct chan_iax2_pvt *, char, int, unsigned int, const char *, int, int); +static int send_command_final(struct chan_iax2_pvt *, char, int, unsigned int, const char *, int, int); +static int send_command_transfer(struct chan_iax2_pvt *, char, int, unsigned int, const char *, int); static struct iax2_user *build_user(const char *name, struct ast_variable *v, int temponly); static void destroy_user(struct iax2_user *user); static int expire_registry(void *data); @@ -670,9 +670,9 @@ static int iax2_provision(struct sockaddr_in *end, char *dest, const char *templ static struct ast_channel *iax2_request(const char *type, int format, void *data, int *cause); static int iax2_devicestate(void *data); static int iax2_digit(struct ast_channel *c, char digit); -static int iax2_sendtext(struct ast_channel *c, char *text); +static int iax2_sendtext(struct ast_channel *c, const char *text); static int iax2_sendimage(struct ast_channel *c, struct ast_frame *img); -static int iax2_sendhtml(struct ast_channel *c, int subclass, char *data, int datalen); +static int iax2_sendhtml(struct ast_channel *c, int subclass, const char *data, int datalen); static int iax2_call(struct ast_channel *c, char *dest, int timeout); static int iax2_hangup(struct ast_channel *c); static int iax2_answer(struct ast_channel *c); @@ -681,7 +681,7 @@ static int iax2_write(struct ast_channel *c, struct ast_frame *f); static int iax2_indicate(struct ast_channel *c, int condition); static int iax2_setoption(struct ast_channel *c, int option, void *data, int datalen); static int iax2_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc); -static int iax2_transfer(struct ast_channel *c, char *dest); +static int iax2_transfer(struct ast_channel *c, const char *dest); static int iax2_fixup(struct ast_channel *oldchannel, struct ast_channel *newchan); static const struct ast_channel_tech iax2_tech = { @@ -2487,7 +2487,7 @@ static int iax2_digit(struct ast_channel *c, char digit) return send_command_locked(PTR_TO_CALLNO(c->tech_pvt), AST_FRAME_DTMF, digit, 0, NULL, 0, -1); } -static int iax2_sendtext(struct ast_channel *c, char *text) +static int iax2_sendtext(struct ast_channel *c, const char *text) { return send_command_locked(PTR_TO_CALLNO(c->tech_pvt), AST_FRAME_TEXT, @@ -2499,7 +2499,7 @@ static int iax2_sendimage(struct ast_channel *c, struct ast_frame *img) return send_command_locked(PTR_TO_CALLNO(c->tech_pvt), AST_FRAME_IMAGE, img->subclass, 0, img->data, img->datalen, -1); } -static int iax2_sendhtml(struct ast_channel *c, int subclass, char *data, int datalen) +static int iax2_sendhtml(struct ast_channel *c, int subclass, const char *data, int datalen) { return send_command_locked(PTR_TO_CALLNO(c->tech_pvt), AST_FRAME_HTML, subclass, 0, data, datalen, -1); } @@ -3214,7 +3214,7 @@ static int iax2_indicate(struct ast_channel *c, int condition) return send_command_locked(callno, AST_FRAME_CONTROL, condition, 0, NULL, 0, -1); } -static int iax2_transfer(struct ast_channel *c, char *dest) +static int iax2_transfer(struct ast_channel *c, const char *dest) { unsigned short callno = PTR_TO_CALLNO(c->tech_pvt); struct iax_ie_data ied; @@ -4484,7 +4484,7 @@ static int iax2_write(struct ast_channel *c, struct ast_frame *f) return res; } -static int __send_command(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, char *data, int datalen, int seqno, +static int __send_command(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const char *data, int datalen, int seqno, int now, int transfer, int final) { struct ast_frame f; @@ -4495,16 +4495,16 @@ static int __send_command(struct chan_iax2_pvt *i, char type, int command, unsig f.mallocd = 0; f.offset = 0; f.src = (char *)__FUNCTION__; - f.data = data; + f.data = (char *)data; return iax2_send(i, &f, ts, seqno, now, transfer, final); } -static int send_command(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, char *data, int datalen, int seqno) +static int send_command(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const char *data, int datalen, int seqno) { return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 0); } -static int send_command_locked(unsigned short callno, char type, int command, unsigned int ts, char *data, int datalen, int seqno) +static int send_command_locked(unsigned short callno, char type, int command, unsigned int ts, const char *data, int datalen, int seqno) { int res; ast_mutex_lock(&iaxsl[callno]); @@ -4514,25 +4514,25 @@ static int send_command_locked(unsigned short callno, char type, int command, un } #ifdef BRIDGE_OPTIMIZATION -static int forward_command(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, char *data, int datalen, int seqno) +static int forward_command(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const char *data, int datalen, int seqno) { return __send_command(iaxs[i->bridgecallno], type, command, ts, data, datalen, seqno, 0, 0, 0); } #endif -static int send_command_final(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, char *data, int datalen, int seqno) +static int send_command_final(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const char *data, int datalen, int seqno) { /* It is assumed that the callno has already been locked */ iax2_predestroy_nolock(i->callno); return __send_command(i, type, command, ts, data, datalen, seqno, 0, 0, 1); } -static int send_command_immediate(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, char *data, int datalen, int seqno) +static int send_command_immediate(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const char *data, int datalen, int seqno) { return __send_command(i, type, command, ts, data, datalen, seqno, 1, 0, 0); } -static int send_command_transfer(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, char *data, int datalen) +static int send_command_transfer(struct chan_iax2_pvt *i, char type, int command, unsigned int ts, const char *data, int datalen) { return __send_command(i, type, command, ts, data, datalen, 0, 0, 1, 0); } diff --git a/channels/chan_local.c b/channels/chan_local.c index 95b1cdad9774278c56d030060480f5ec4ba2e552..05a20992e4ca0e8114333f4d1f5ec7854a880706 100755 --- a/channels/chan_local.c +++ b/channels/chan_local.c @@ -61,7 +61,7 @@ static struct ast_frame *local_read(struct ast_channel *ast); static int local_write(struct ast_channel *ast, struct ast_frame *f); static int local_indicate(struct ast_channel *ast, int condition); static int local_fixup(struct ast_channel *oldchan, struct ast_channel *newchan); -static int local_sendhtml(struct ast_channel *ast, int subclass, char *data, int datalen); +static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen); static const struct ast_channel_tech local_tech = { .type = type, @@ -264,7 +264,7 @@ static int local_digit(struct ast_channel *ast, char digit) return res; } -static int local_sendhtml(struct ast_channel *ast, int subclass, char *data, int datalen) +static int local_sendhtml(struct ast_channel *ast, int subclass, const char *data, int datalen) { struct local_pvt *p = ast->tech_pvt; int res = -1; @@ -273,7 +273,7 @@ static int local_sendhtml(struct ast_channel *ast, int subclass, char *data, int ast_mutex_lock(&p->lock); isoutbound = IS_OUTBOUND(ast, p); f.subclass = subclass; - f.data = data; + f.data = (char *)data; f.datalen = datalen; res = local_queue_frame(p, isoutbound, &f, ast); ast_mutex_unlock(&p->lock); diff --git a/channels/chan_mgcp.c b/channels/chan_mgcp.c index 75e6c669664b275676b42358301c04ce3683b3a1..04f7d675e56e982e035146374407505dd0bcafed 100755 --- a/channels/chan_mgcp.c +++ b/channels/chan_mgcp.c @@ -120,6 +120,7 @@ static const char config[] = "mgcp.conf"; #define MGCP_DTMF_RFC2833 (1 << 0) #define MGCP_DTMF_INBAND (1 << 1) +#define MGCP_DTMF_HYBRID (1 << 2) #define DEFAULT_MGCP_GW_PORT 2427 /* From RFC 2705 */ #define DEFAULT_MGCP_CA_PORT 2727 /* From RFC 2705 */ @@ -988,6 +989,8 @@ static int mgcp_hangup(struct ast_channel *ast) if ((p->dtmfmode & MGCP_DTMF_INBAND) && p->dsp) { /* SC: check whether other channel is active. */ if (!sub->next->owner) { + if (p->dtmfmode & MGCP_DTMF_HYBRID) + p->dtmfmode &= ~MGCP_DTMF_INBAND; if (mgcpdebug) { ast_verbose(VERBOSE_PREFIX_2 "MGCP free dsp on %s@%s\n", p->name, p->parent->name); } @@ -1377,7 +1380,7 @@ static struct ast_channel *mgcp_new(struct mgcp_subchannel *sub, int state) if (sub->rtp) tmp->fds[0] = ast_rtp_fd(sub->rtp); tmp->type = type; - if (i->dtmfmode & MGCP_DTMF_INBAND) { + if (i->dtmfmode & (MGCP_DTMF_INBAND | MGCP_DTMF_HYBRID)) { i->dsp = ast_dsp_new(); ast_dsp_set_features(i->dsp,DSP_FEATURE_DTMF_DETECT); /* SC: this is to prevent clipping of dtmf tones during dsp processing */ @@ -2617,6 +2620,10 @@ static void *mgcp_ss(void *data) } ast_setstate(chan, AST_STATE_RING); /*zt_enable_ec(p);*/ + if (p->dtmfmode & MGCP_DTMF_HYBRID) { + p->dtmfmode |= MGCP_DTMF_INBAND; + ast_indicate(chan, -1); + } res = ast_pbx_run(chan); if (res) { ast_log(LOG_WARNING, "PBX exited non-zero\n"); @@ -3608,6 +3615,8 @@ static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v) dtmfmode = MGCP_DTMF_INBAND; else if (!strcasecmp(v->value, "rfc2833")) dtmfmode = MGCP_DTMF_RFC2833; + else if (!strcasecmp(v->value, "hybrid")) + dtmfmode = MGCP_DTMF_HYBRID; else if (!strcasecmp(v->value, "none")) dtmfmode = 0; else @@ -3702,6 +3711,8 @@ static struct mgcp_gateway *build_gateway(char *cat, struct ast_variable *v) e->capability = capability; e->parent = gw; e->dtmfmode = dtmfmode; + if (!ep_reload && e->sub->rtp) + e->dtmfmode |= MGCP_DTMF_INBAND; e->adsi = adsi; e->type = TYPE_LINE; e->immediate = immediate; diff --git a/channels/chan_phone.c b/channels/chan_phone.c index 81958e0781d58c9151333706c212e49f636b6a60..62778ed76f4e1ced6d81ab94c8c4851e519d420d 100755 --- a/channels/chan_phone.c +++ b/channels/chan_phone.c @@ -139,7 +139,7 @@ static int phone_answer(struct ast_channel *ast); static struct ast_frame *phone_read(struct ast_channel *ast); static int phone_write(struct ast_channel *ast, struct ast_frame *frame); static struct ast_frame *phone_exception(struct ast_channel *ast); -static int phone_send_text(struct ast_channel *ast, char *text); +static int phone_send_text(struct ast_channel *ast, const char *text); static const struct ast_channel_tech phone_tech = { .type = type, @@ -536,7 +536,7 @@ static struct ast_frame *phone_read(struct ast_channel *ast) return &p->fr; } -static int phone_write_buf(struct phone_pvt *p, char *buf, int len, int frlen) +static int phone_write_buf(struct phone_pvt *p, const char *buf, int len, int frlen) { int res; /* Store as much of the buffer as we can, then write fixed frames */ @@ -567,7 +567,7 @@ static int phone_write_buf(struct phone_pvt *p, char *buf, int len, int frlen) return len; } -static int phone_send_text(struct ast_channel *ast, char *text) +static int phone_send_text(struct ast_channel *ast, const char *text) { int length = strlen(text); return phone_write_buf(ast->tech_pvt, text, length, length) == diff --git a/channels/chan_sip.c b/channels/chan_sip.c index 023ecd4a0067e4ed0f03451c53ec561581d1685f..4ae182c2239f4c23a94bbf4f372d31f53fea6f70 100755 --- a/channels/chan_sip.c +++ b/channels/chan_sip.c @@ -653,9 +653,9 @@ static int transmit_request_with_auth(struct sip_pvt *p, int sipmethod, int inc, static int transmit_invite(struct sip_pvt *p, int sipmethod, int sendsdp, char *auth, char *authheader, char *vxml_url, char *distinctive_ring, char *osptoken, int addsipheaders, int init); static int transmit_reinvite_with_sdp(struct sip_pvt *p); static int transmit_info_with_digit(struct sip_pvt *p, char digit); -static int transmit_message_with_text(struct sip_pvt *p, char *text); -static int transmit_refer(struct sip_pvt *p, char *dest); -static int sip_sipredirect(struct sip_pvt *p, char *dest); +static int transmit_message_with_text(struct sip_pvt *p, const char *text); +static int transmit_refer(struct sip_pvt *p, const char *dest); +static int sip_sipredirect(struct sip_pvt *p, const char *dest); static struct sip_peer *temp_peer(char *name); static int do_proxy_auth(struct sip_pvt *p, struct sip_request *req, char *header, char *respheader, int sipmethod, int init); static void free_old_route(struct sip_route *route); @@ -670,17 +670,16 @@ static int callevents = 0; static struct ast_channel *sip_request(const char *type, int format, void *data, int *cause); static int sip_devicestate(void *data); -static int sip_sendtext(struct ast_channel *ast, char *text); +static int sip_sendtext(struct ast_channel *ast, const char *text); static int sip_call(struct ast_channel *ast, char *dest, int timeout); static int sip_hangup(struct ast_channel *ast); static int sip_answer(struct ast_channel *ast); static struct ast_frame *sip_read(struct ast_channel *ast); static int sip_write(struct ast_channel *ast, struct ast_frame *frame); static int sip_indicate(struct ast_channel *ast, int condition); -static int sip_transfer(struct ast_channel *ast, char *dest); +static int sip_transfer(struct ast_channel *ast, const char *dest); static int sip_fixup(struct ast_channel *oldchan, struct ast_channel *newchan); static int sip_senddigit(struct ast_channel *ast, char digit); -static int sip_sendtext(struct ast_channel *ast, char *text); static int clear_realm_authentication(struct sip_auth *authlist); /* Clear realm authentication list (at reload) */ static struct sip_auth *add_realm_authentication(struct sip_auth *authlist, char *configuration, int lineno); /* Add realm authentication in list */ static struct sip_auth *find_realm_authentication(struct sip_auth *authlist, char *realm); /* Find authentication for a specific realm */ @@ -1178,7 +1177,7 @@ static char *ditch_braces(char *tmp) /*--- sip_sendtext: Send SIP MESSAGE text within a call ---*/ /* Called from PBX core text message functions */ -static int sip_sendtext(struct ast_channel *ast, char *text) +static int sip_sendtext(struct ast_channel *ast, const char *text) { struct sip_pvt *p = ast->tech_pvt; int debug=sip_debug_test_pvt(p); @@ -2098,7 +2097,7 @@ static int sip_senddigit(struct ast_channel *ast, char digit) /*--- sip_transfer: Transfer SIP call */ -static int sip_transfer(struct ast_channel *ast, char *dest) +static int sip_transfer(struct ast_channel *ast, const char *dest) { struct sip_pvt *p = ast->tech_pvt; int res; @@ -3122,7 +3121,7 @@ static int add_blank_header(struct sip_request *req) } /*--- add_line: Add content (not header) to SIP message */ -static int add_line(struct sip_request *req, char *line) +static int add_line(struct sip_request *req, const char *line) { if (req->len >= sizeof(req->data) - 4) { ast_log(LOG_WARNING, "Out of space, can't add anymore\n"); @@ -3573,7 +3572,7 @@ static int transmit_response_with_auth(struct sip_pvt *p, char *msg, struct sip_ } /*--- add_text: Add text body to SIP message ---*/ -static int add_text(struct sip_request *req, char *text) +static int add_text(struct sip_request *req, const char *text) { /* XXX Convert \n's to \r\n's XXX */ int len = strlen(text); @@ -4603,7 +4602,7 @@ static int transmit_register(struct sip_registry *r, int sipmethod, char *auth, } /*--- transmit_message_with_text: Transmit text with SIP MESSAGE method ---*/ -static int transmit_message_with_text(struct sip_pvt *p, char *text) +static int transmit_message_with_text(struct sip_pvt *p, const char *text) { struct sip_request req; reqprep(&req, p, SIP_MESSAGE, 0, 1); @@ -4612,7 +4611,7 @@ static int transmit_message_with_text(struct sip_pvt *p, char *text) } /*--- transmit_refer: Transmit SIP REFER message ---*/ -static int transmit_refer(struct sip_pvt *p, char *dest) +static int transmit_refer(struct sip_pvt *p, const char *dest) { struct sip_request req; char from[256]; @@ -10633,7 +10632,7 @@ static int sip_getheader(struct ast_channel *chan, void *data) /* Called by the transfer() dialplan application through the sip_transfer() */ /* pbx interface function if the call is in ringing state */ /* coded by Martin Pycko (m78pl@yahoo.com) */ -static int sip_sipredirect(struct sip_pvt *p, char *dest) +static int sip_sipredirect(struct sip_pvt *p, const char *dest) { char *cdest; char *extension, *host, *port; diff --git a/channels/chan_zap.c b/channels/chan_zap.c index d10886531347c427ea563dcbd463fbb853314766..c68f0ff488f98c0b1336a19a27868d57455e2f3c 100755 --- a/channels/chan_zap.c +++ b/channels/chan_zap.c @@ -299,7 +299,7 @@ static int restart_monitor(void); static int zt_bridge(struct ast_channel *c0, struct ast_channel *c1, int flags, struct ast_frame **fo, struct ast_channel **rc); -static int zt_sendtext(struct ast_channel *c, char *text); +static int zt_sendtext(struct ast_channel *c, const char *text); static inline int zt_get_event(int fd) { @@ -615,7 +615,7 @@ static struct zt_pvt { static struct ast_channel *zt_request(const char *type, int format, void *data, int *cause); static int zt_digit(struct ast_channel *ast, char digit); -static int zt_sendtext(struct ast_channel *c, char *text); +static int zt_sendtext(struct ast_channel *c, const char *text); static int zt_call(struct ast_channel *ast, char *rdest, int timeout); static int zt_hangup(struct ast_channel *ast); static int zt_answer(struct ast_channel *ast); @@ -10189,7 +10189,7 @@ int load_module(void) return res; } -static int zt_sendtext(struct ast_channel *c, char *text) +static int zt_sendtext(struct ast_channel *c, const char *text) { #define END_SILENCE_LEN 400 #define HEADER_MS 50 diff --git a/configs/mgcp.conf.sample b/configs/mgcp.conf.sample index 2af96c9b317963bd7c627d7de764e260558c2c41..63e7255576b47ff7addeb579424ba8e203304abc 100755 --- a/configs/mgcp.conf.sample +++ b/configs/mgcp.conf.sample @@ -45,7 +45,7 @@ ; ;context=local ;host=dynamic -;dtmfmode=none ; DTMF Mode can be 'none', 'rfc2833', or 'inband'. Default is none. +;dtmfmode=none ; DTMF Mode can be 'none', 'rfc2833', or 'inband' or 'hybrid' which starts in none and moves to inband. Default is none. ;slowsequence=yes ; The DPH100M does not follow MGCP standards for sequencing ;line => aaln/1 diff --git a/configs/queues.conf.sample b/configs/queues.conf.sample index 0c3447ffa8d21cb76ca3064d92abe4c7c2c72589..983b89dcdd17e5b2f2fc98b8e99ef816eef8a673 100755 --- a/configs/queues.conf.sample +++ b/configs/queues.conf.sample @@ -122,14 +122,21 @@ persistentmembers = yes ; ; monitor-join = yes ; -; If you wish to allow queues that have no members currently to be joined, set this to yes +; This setting controls whether callers can join a queue with no members. There are three +; choices: +; +; yes - callers can join a queue with no members or only unavailable members +; no - callers cannot join a queue with no members or only unavailable members +; strict - callers cannot join a queue with no members ; ; joinempty = yes ; -; If you wish to remove callers from the queue if there are no agents present, set this to yes +; If you wish to remove callers from the queue when new callers cannot join, set this setting +; to one of the same choices for 'joinwhenempty' ; ; leavewhenempty = yes ; +; ; Asterisk can generate AgentCalled events when an agent is rung, if this is turned on ; (may generate a LOT of extra manager events) ; diff --git a/doc/README.variables b/doc/README.variables index f65ef29d1620711984625c4f5dd7bee0c55210c8..83d3011dd33e37e248af2a88de052babe7fafca9 100755 --- a/doc/README.variables +++ b/doc/README.variables @@ -340,6 +340,8 @@ ${MONITOR_EXEC} Application to execute after monitoring a call ${MONITOR_EXEC_ARGS} Arguments to application ${MONITOR_FILENAME} File for monitoring (recording) calls in queue ${QUEUE_PRIO} Queue priority +${QUEUESTATUS} Status of the call, one of: + (TIMEOUT | FULL | JOINEMPTY | LEAVEEMPTY | JOINUNAVAIL | LEAVEUNAVAIL) ${RECORDED_FILE} * Recorded file in record() ${TALK_DETECED} * Result from talkdetect() ${TOUCH_MONITOR} The filename base to use with Touch Monitor (auto record) diff --git a/include/asterisk/channel.h b/include/asterisk/channel.h index a28135c12fe26874ca3c6be20f41773750dca93e..92c50003138ab0a54b8d949753895c283cdfcb90 100755 --- a/include/asterisk/channel.h +++ b/include/asterisk/channel.h @@ -115,13 +115,13 @@ struct ast_channel_tech { int (* const write)(struct ast_channel *chan, struct ast_frame *frame); /*! Display or transmit text */ - int (* const send_text)(struct ast_channel *chan, char *text); + int (* const send_text)(struct ast_channel *chan, const char *text); /*! Display or send an image */ int (* const send_image)(struct ast_channel *chan, struct ast_frame *frame); /*! Send HTML data */ - int (* const send_html)(struct ast_channel *chan, int subclass, char *data, int len); + int (* const send_html)(struct ast_channel *chan, int subclass, const char *data, int len); /*! Handle an exception, reading a frame */ struct ast_frame * (* const exception)(struct ast_channel *chan); @@ -143,7 +143,7 @@ struct ast_channel_tech { int (* const queryoption)(struct ast_channel *chan, int option, void *data, int *datalen); /*! Blind transfer other side */ - int (* const transfer)(struct ast_channel *chan, char *newdest); + int (* const transfer)(struct ast_channel *chan, const char *newdest); /*! Write a frame, in standard format */ int (* const write_video)(struct ast_channel *chan, struct ast_frame *frame); @@ -841,11 +841,11 @@ int ast_channel_supports_html(struct ast_channel *channel); /*! Sends HTML on given channel */ /*! Send HTML or URL on link. Returns 0 on success or -1 on failure */ -int ast_channel_sendhtml(struct ast_channel *channel, int subclass, char *data, int datalen); +int ast_channel_sendhtml(struct ast_channel *channel, int subclass, const char *data, int datalen); /*! Sends a URL on a given link */ /*! Send URL on link. Returns 0 on success or -1 on failure */ -int ast_channel_sendurl(struct ast_channel *channel, char *url); +int ast_channel_sendurl(struct ast_channel *channel, const char *url); /*! Defers DTMF */ /*! Defer DTMF so that you only read things like hangups and audio. Returns diff --git a/include/asterisk/tdd.h b/include/asterisk/tdd.h index 9c5313b8c34af5966519fc453d892dd310f13324..669b68ce95fc25c51ac488bbd5d484aa8c0eb197 100755 --- a/include/asterisk/tdd.h +++ b/include/asterisk/tdd.h @@ -35,7 +35,7 @@ extern void tdd_init(void); * This function creates a stream of TDD data in ulaw format. It returns the size * (in bytes) of the data (if it returns a size of 0, there is probably an error) */ -extern int tdd_generate(struct tdd_state *tdd, unsigned char *buf, char *string); +extern int tdd_generate(struct tdd_state *tdd, unsigned char *buf, const char *string); /*! Create a TDD state machine */ /*! diff --git a/tdd.c b/tdd.c index e2a6cc839ccc0db3088c31c16b57dca218e3c0b7..a3664e82ed80bca77fcda99ba1716303740daeaa 100755 --- a/tdd.c +++ b/tdd.c @@ -233,7 +233,7 @@ static inline float tdd_getcarrier(float *cr, float *ci, int bit) PUT_TDD_STOP; /* Stop bit */ \ } while(0); -int tdd_generate(struct tdd_state *tdd, unsigned char *buf, char *str) +int tdd_generate(struct tdd_state *tdd, unsigned char *buf, const char *str) { int bytes=0; int i,x;