Review Board 1.7.16


Backport of state_interface for app_queue in Asterisk 1.4

Review Request #116 - Created Jan. 5, 2009 and submitted

Mark Michelson
1.4
Reviewers
asterisk-dev
Asterisk
This is a backport of functionality that is already in all releases of Asterisk 1.6.

The functionality being added here is the ability to associate an interface with a queue member which is used to determine that member's device state.
A common usage for such functionality is to accurately determine the device state of a queue member who is called via the Agent or Local channel 
technologies. By specifying a more "concrete" interface to watch for device state, the queue application can more accurately decide the availability
of the queue member.

The policy for Asterisk 1.4 is to not introduce new functionality, and only make bug fixes. This case is one where the line has been blurred significantly
and so community feedback would be helpful. From a development standpoint, this violates the policy since most of what is being added is a new option for
queue members. From many users' perspectives, however, this is a means of solving a deficiency in the basic operations of queues. Please take a look at the
diff attached and comment on whether this would be problematic. It is implemented in such a way that any old dialplans, CLI commands, manager commands, etc.
will not need to be updated unless you are making use of this new functionality.

In internal discussions, the only point that was brought up was a possible problem that could aris if using persistent members. If you upgraded to a version 
that had the state interface functionality in it and then downgraded to a version which did not have state interface functionality, then the queue members' 
names loaded from the database would be wrong (they would have a semicolon and the state interface appended). Since the members' names are only used for display 
purposes, since the error may be easily corrected by reloading the queue configuration,and since the number of people likely to be affected by this is very 
small, I feel it's a risk worth taking.

Another potential problem I have thought of is that Asterisk 1.4 does not contain func_devstate. This means that this solution will only work if
you know for sure what endpoint will be dialed when a call is placed from a queue. To give an example, if you know that calling Local/2000 will always 
end up dialing SIP/2000, then this functionality will work great for you. If calling Local/2000 may end up dialing SIP/2000 or potentially SIP/3000 based 
on some dialplan logic, then this new functionality will not help you since you cannot use custom device states in the dialplan.
I used the scenario of issue 12970 as a basis for creating a test.

For the test, I created an Agent channel, Agent/1000, and had this line in the
dialplan:

exten => 1006,1,AgentCallbackLogin(1000,,1000@internal)

In the context "internal," extension 1000 is as follows:

exten => 1000,1,Dial(SIP/1000)

If it is not clear, All calls to Agent/1000 will eventually go to SIP/1000. I added
a line to my queues.conf file for my queue:

member => Agent/1000,,,SIP/1000

When I place an outbound call from SIP/1000, issuing the "queue show" command shows that
Agent/1000 is "in use." Attempting to place a call to the queue will not cause SIP/1000 to
ring since I have ringinuse=no for my queue. When SIP/1000 hangs up, the status returns to 
"not in use."



As another test, I tried implementing a common problem. In my queues.conf file, I added this
to my queue:

member => Local/1000,,,SIP/1000

As you may be able to guess, Local/1000 always dials SIP/1000. I placed a call to my queue
and answered with SIP/1000. At this point, issuing a "queue show" command showed that the
member Local/1000 was "in use." Then, from SIP/1000 I transferred the call to another endpoint.
Issuing a "queue show" command then showed Local/1000 as being "not in use."

Diff revision 2

This is not the most recent revision of the diff. The latest diff is revision 3. See what's changed.

1 2 3
1 2 3

  1. /branches/1.4/apps/app_queue.c: Loading...
/branches/1.4/apps/app_queue.c
Revision 183027 New Change
[20] 189 lines
[+20] [+] static char *descrip =
190
"             TIMEOUT | FULL | JOINEMPTY | LEAVEEMPTY | JOINUNAVAIL | LEAVEUNAVAIL\n";
190
"             TIMEOUT | FULL | JOINEMPTY | LEAVEEMPTY | JOINUNAVAIL | LEAVEUNAVAIL\n";
191

    
   
191

   
192
static char *app_aqm = "AddQueueMember" ;
192
static char *app_aqm = "AddQueueMember" ;
193
static char *app_aqm_synopsis = "Dynamically adds queue members" ;
193
static char *app_aqm_synopsis = "Dynamically adds queue members" ;
194
static char *app_aqm_descrip =
194
static char *app_aqm_descrip =
195
"   AddQueueMember(queuename[|interface[|penalty[|options[|membername]]]]):\n"
195
"   AddQueueMember(queuename[|interface[|penalty[|options[|membername[|state_interface]]]]]):\n"
196
"Dynamically adds interface to an existing queue.\n"
196
"Dynamically adds interface to an existing queue.\n"
197
"If the interface is already in the queue and there exists an n+101 priority\n"
197
"If the interface is already in the queue and there exists an n+101 priority\n"
198
"then it will then jump to this priority.  Otherwise it will return an error\n"
198
"then it will then jump to this priority.  Otherwise it will return an error\n"
199
"The option string may contain zero or more of the following characters:\n"
199
"The option string may contain zero or more of the following characters:\n"
200
"       'j' -- jump to +101 priority when appropriate.\n"
200
"       'j' -- jump to +101 priority when appropriate.\n"
201
"  This application sets the following channel variable upon completion:\n"
201
"  This application sets the following channel variable upon completion:\n"
202
"     AQMSTATUS    The status of the attempt to add a queue member as a \n"
202
"     AQMSTATUS    The status of the attempt to add a queue member as a \n"
203
"                     text string, one of\n"
203
"                     text string, one of\n"
204
"           ADDED | MEMBERALREADY | NOSUCHQUEUE \n"
204
"           ADDED | MEMBERALREADY | NOSUCHQUEUE \n"

    
   
205
"If a device is provided in the state_interface parameter, then this will\n"

    
   
206
"be the device which will be used to determine the device state of the\n"

    
   
207
"added queue member.\n"
205
"Example: AddQueueMember(techsupport|SIP/3000)\n"
208
"Example: AddQueueMember(techsupport|SIP/3000)\n"
206
"";
209
"";
207

    
   
210

   
208
static char *app_rqm = "RemoveQueueMember" ;
211
static char *app_rqm = "RemoveQueueMember" ;
209
static char *app_rqm_synopsis = "Dynamically removes queue members" ;
212
static char *app_rqm_synopsis = "Dynamically removes queue members" ;
[+20] [20] 142 lines
[+20] [+] struct queue_ent {
352
	struct queue_ent *next;             /*!< The next queue entry */
355
	struct queue_ent *next;             /*!< The next queue entry */
353
};
356
};
354

    
   
357

   
355
struct member {
358
struct member {
356
	char interface[80];                 /*!< Technology/Location */
359
	char interface[80];                 /*!< Technology/Location */

    
   
360
	char state_interface[80];			/*!< Technology/Location from which to read device state changes */
357
	char membername[80];                /*!< Member name to use in queue logs */
361
	char membername[80];                /*!< Member name to use in queue logs */
358
	int penalty;                        /*!< Are we a last resort? */
362
	int penalty;                        /*!< Are we a last resort? */
359
	int calls;                          /*!< Number of calls serviced by this member */
363
	int calls;                          /*!< Number of calls serviced by this member */
360
	int dynamic;                        /*!< Are we dynamically added? */
364
	int dynamic;                        /*!< Are we dynamically added? */
361
	int realtime;                       /*!< Is this member realtime? */
365
	int realtime;                       /*!< Is this member realtime? */
[+20] [20] 234 lines
[+20] [+] static int update_status(const char *interface, const int status)
596
		ast_mutex_lock(&q->lock);
600
		ast_mutex_lock(&q->lock);
597
		mem_iter = ao2_iterator_init(q->members, 0);
601
		mem_iter = ao2_iterator_init(q->members, 0);
598
		while ((cur = ao2_iterator_next(&mem_iter))) {
602
		while ((cur = ao2_iterator_next(&mem_iter))) {
599
			char *tmp_interface;
603
			char *tmp_interface;
600
			char *slash_pos;
604
			char *slash_pos;
601
			tmp_interface = ast_strdupa(cur->interface);
605
			tmp_interface = ast_strdupa(cur->state_interface);
602
			if ((slash_pos = strchr(tmp_interface, '/')))
606
			if ((slash_pos = strchr(tmp_interface, '/')))
603
				if ((slash_pos = strchr(slash_pos + 1, '/')))
607
				if ((slash_pos = strchr(slash_pos + 1, '/')))
604
					*slash_pos = '\0';
608
					*slash_pos = '\0';
605

    
   
609

   
606
			if (strcasecmp(interface, tmp_interface)) {
610
			if (strcasecmp(interface, tmp_interface)) {
[+20] [20] 142 lines
[+20] [+] static int statechange_queue(const char *dev, int state, void *ign)
749
	ast_mutex_unlock(&device_state.lock);
753
	ast_mutex_unlock(&device_state.lock);
750

    
   
754

   
751
	return 0;
755
	return 0;
752
}
756
}
753
/*! \brief allocate space for new queue member and set fields based on parameters passed */
757
/*! \brief allocate space for new queue member and set fields based on parameters passed */
754
static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused)
758
static struct member *create_queue_member(const char *interface, const char *membername, int penalty, int paused, const char *state_interface)
755
{
759
{
756
	struct member *cur;
760
	struct member *cur;
757
	
761
	
758
	if ((cur = ao2_alloc(sizeof(*cur), NULL))) {
762
	if ((cur = ao2_alloc(sizeof(*cur), NULL))) {
759
		cur->penalty = penalty;
763
		cur->penalty = penalty;
760
		cur->paused = paused;
764
		cur->paused = paused;
761
		ast_copy_string(cur->interface, interface, sizeof(cur->interface));
765
		ast_copy_string(cur->interface, interface, sizeof(cur->interface));

    
   
766
		if (!ast_strlen_zero(state_interface)) {

    
   
767
			ast_copy_string(cur->state_interface, state_interface, sizeof(cur->state_interface));

    
   
768
		} else {

    
   
769
			ast_copy_string(cur->state_interface, interface, sizeof(cur->state_interface));

    
   
770
		}
762
		if (!ast_strlen_zero(membername))
771
		if (!ast_strlen_zero(membername))
763
			ast_copy_string(cur->membername, membername, sizeof(cur->membername));
772
			ast_copy_string(cur->membername, membername, sizeof(cur->membername));
764
		else
773
		else
765
			ast_copy_string(cur->membername, interface, sizeof(cur->membername));
774
			ast_copy_string(cur->membername, interface, sizeof(cur->membername));
766
		if (!strchr(cur->interface, '/'))
775
		if (!strchr(cur->interface, '/'))
767
			ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
776
			ast_log(LOG_WARNING, "No location at interface '%s'\n", interface);
768
		cur->status = ast_device_state(interface);
777
		cur->status = ast_device_state(cur->state_interface);
769
	}
778
	}
770

    
   
779

   
771
	return cur;
780
	return cur;
772
}
781
}
773

    
   
782

   
[+20] [20] 123 lines
[+20] [+] static int add_to_interfaces(const char *interface)
897
}
906
}
898

    
   
907

   
899
static int interface_exists_global(const char *interface)
908
static int interface_exists_global(const char *interface)
900
{
909
{
901
	struct call_queue *q;
910
	struct call_queue *q;
902
	struct member *mem, tmpmem;
911
	struct member *mem;

    
   
912
	struct ao2_iterator mem_iter;
903
	int ret = 0;
913
	int ret = 0;
904

    
   
914

   
905
	ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));

   
906

    
   

   
907
	AST_LIST_LOCK(&queues);
915
	AST_LIST_LOCK(&queues);
908
	AST_LIST_TRAVERSE(&queues, q, list) {
916
	AST_LIST_TRAVERSE(&queues, q, list) {
909
		ast_mutex_lock(&q->lock);
917
		ast_mutex_lock(&q->lock);
910
		if ((mem = ao2_find(q->members, &tmpmem, OBJ_POINTER))) {
918
		mem_iter = ao2_iterator_init(q->members, 0);

    
   
919
		while ((mem = ao2_iterator_next(&mem_iter))) {

    
   
920
			if (!strcasecmp(mem->state_interface, interface)) {
911
			ao2_ref(mem, -1);
921
				ao2_ref(mem, -1);
912
			ret = 1;
922
				ret = 1;

    
   
923
				break;

    
   
924
			}
913
		}
925
		}
914
		ast_mutex_unlock(&q->lock);
926
		ast_mutex_unlock(&q->lock);
915
		if (ret)
927
		if (ret)
916
			break;
928
			break;
917
	}
929
	}
[+20] [20] 188 lines
[+20] [+] static void queue_set_param(struct call_queue *q, const char *param, const char *val, int linenum, int failunknown)
1106
			ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
1118
			ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
1107
		}
1119
		}
1108
	}
1120
	}
1109
}
1121
}
1110

    
   
1122

   
1111
static void rt_handle_member_record(struct call_queue *q, char *interface, const char *membername, const char *penalty_str, const char *paused_str)
1123
static void rt_handle_member_record(struct call_queue *q, char *interface, const char *membername, const char *penalty_str, const char *paused_str, const char *state_interface)
1112
{
1124
{
1113
	struct member *m, tmpmem;
1125
	struct member *m, tmpmem;
1114
	int penalty = 0;
1126
	int penalty = 0;
1115
	int paused  = 0;
1127
	int paused  = 0;
1116

    
   
1128

   
[+20] [20] 13 lines
[+20] static void rt_handle_member_record(struct call_queue *q, char *interface, const char *membername, const char *penalty_str, const char *paused_str) [+] static void rt_handle_member_record(struct call_queue *q, char *interface, const char *membername, const char *penalty_str, const char *paused_str, const char *state_interface)
1130
	ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
1142
	ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
1131
	m = ao2_find(q->members, &tmpmem, OBJ_POINTER);
1143
	m = ao2_find(q->members, &tmpmem, OBJ_POINTER);
1132

    
   
1144

   
1133
	/* Create a new one if not found, else update penalty */
1145
	/* Create a new one if not found, else update penalty */
1134
	if (!m) {
1146
	if (!m) {
1135
		if ((m = create_queue_member(interface, membername, penalty, paused))) {
1147
		if ((m = create_queue_member(interface, membername, penalty, paused, state_interface))) {
1136
			m->dead = 0;
1148
			m->dead = 0;
1137
			m->realtime = 1;
1149
			m->realtime = 1;
1138
			add_to_interfaces(interface);
1150
			add_to_interfaces(m->state_interface);
1139
			ao2_link(q->members, m);
1151
			ao2_link(q->members, m);
1140
			ao2_ref(m, -1);
1152
			ao2_ref(m, -1);
1141
			m = NULL;
1153
			m = NULL;
1142
			q->membercount++;
1154
			q->membercount++;
1143
		}
1155
		}
1144
	} else {
1156
	} else {
1145
		m->dead = 0;	/* Do not delete this one. */
1157
		m->dead = 0;	/* Do not delete this one. */
1146
		if (paused_str)
1158
		if (paused_str)
1147
			m->paused = paused;
1159
			m->paused = paused;

    
   
1160
		if (strcasecmp(state_interface, m->state_interface)) {

    
   
1161
			remove_from_interfaces(m->state_interface);

    
   
1162
			ast_copy_string(m->state_interface, state_interface, sizeof(m->state_interface));

    
   
1163
			add_to_interfaces(m->state_interface);

    
   
1164
		}
1148
		m->penalty = penalty;
1165
		m->penalty = penalty;
1149
		ao2_ref(m, -1);
1166
		ao2_ref(m, -1);
1150
	}
1167
	}
1151
}
1168
}
1152

    
   
1169

   
[+20] [20] 4 lines
[+20] [+] static void free_members(struct call_queue *q, int all)
1157
	struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
1174
	struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
1158

    
   
1175

   
1159
	while ((cur = ao2_iterator_next(&mem_iter))) {
1176
	while ((cur = ao2_iterator_next(&mem_iter))) {
1160
		if (all || !cur->dynamic) {
1177
		if (all || !cur->dynamic) {
1161
			ao2_unlink(q->members, cur);
1178
			ao2_unlink(q->members, cur);
1162
			remove_from_interfaces(cur->interface);
1179
			remove_from_interfaces(cur->state_interface);
1163
			q->membercount--;
1180
			q->membercount--;
1164
		}
1181
		}
1165
		ao2_ref(cur, -1);
1182
		ao2_ref(cur, -1);
1166
	}
1183
	}
1167
}
1184
}
[+20] [20] 108 lines
[+20] [+] static struct call_queue *find_queue_by_name_rt(const char *queuename, struct ast_variable *queue_vars, struct ast_config *member_config)
1276

    
   
1293

   
1277
	while ((interface = ast_category_browse(member_config, interface))) {
1294
	while ((interface = ast_category_browse(member_config, interface))) {
1278
		rt_handle_member_record(q, interface,
1295
		rt_handle_member_record(q, interface,
1279
			ast_variable_retrieve(member_config, interface, "membername"),
1296
			ast_variable_retrieve(member_config, interface, "membername"),
1280
			ast_variable_retrieve(member_config, interface, "penalty"),
1297
			ast_variable_retrieve(member_config, interface, "penalty"),
1281
			ast_variable_retrieve(member_config, interface, "paused"));
1298
			ast_variable_retrieve(member_config, interface, "paused"),

    
   
1299
			S_OR(ast_variable_retrieve(member_config, interface, "state_interface"),interface));
1282
	}
1300
	}
1283

    
   
1301

   
1284
	/* Delete all realtime members that have been deleted in DB. */
1302
	/* Delete all realtime members that have been deleted in DB. */
1285
	mem_iter = ao2_iterator_init(q->members, 0);
1303
	mem_iter = ao2_iterator_init(q->members, 0);
1286
	while ((m = ao2_iterator_next(&mem_iter))) {
1304
	while ((m = ao2_iterator_next(&mem_iter))) {
1287
		if (m->dead) {
1305
		if (m->dead) {
1288
			ao2_unlink(q->members, m);
1306
			ao2_unlink(q->members, m);
1289
			ast_mutex_unlock(&q->lock);
1307
			ast_mutex_unlock(&q->lock);
1290
			remove_from_interfaces(m->interface);
1308
			remove_from_interfaces(m->state_interface);
1291
			ast_mutex_lock(&q->lock);
1309
			ast_mutex_lock(&q->lock);
1292
			q->membercount--;
1310
			q->membercount--;
1293
		}
1311
		}
1294
		ao2_ref(m, -1);
1312
		ao2_ref(m, -1);
1295
	}
1313
	}
[+20] [20] 50 lines
[+20] [+] static void update_realtime_members(struct call_queue *q)
1346

    
   
1364

   
1347
	while ((interface = ast_category_browse(member_config, interface))) {
1365
	while ((interface = ast_category_browse(member_config, interface))) {
1348
		rt_handle_member_record(q, interface,
1366
		rt_handle_member_record(q, interface,
1349
			S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface),
1367
			S_OR(ast_variable_retrieve(member_config, interface, "membername"), interface),
1350
			ast_variable_retrieve(member_config, interface, "penalty"),
1368
			ast_variable_retrieve(member_config, interface, "penalty"),
1351
			ast_variable_retrieve(member_config, interface, "paused"));
1369
			ast_variable_retrieve(member_config, interface, "paused"),

    
   
1370
			S_OR(ast_variable_retrieve(member_config, interface, "state_interface"), interface));
1352
	}
1371
	}
1353

    
   
1372

   
1354
	/* Delete all realtime members that have been deleted in DB. */
1373
	/* Delete all realtime members that have been deleted in DB. */
1355
	mem_iter = ao2_iterator_init(q->members, 0);
1374
	mem_iter = ao2_iterator_init(q->members, 0);
1356
	while ((m = ao2_iterator_next(&mem_iter))) {
1375
	while ((m = ao2_iterator_next(&mem_iter))) {
1357
		if (m->dead) {
1376
		if (m->dead) {
1358
			ao2_unlink(q->members, m);
1377
			ao2_unlink(q->members, m);
1359
			ast_mutex_unlock(&q->lock);
1378
			ast_mutex_unlock(&q->lock);
1360
			remove_from_interfaces(m->interface);
1379
			remove_from_interfaces(m->state_interface);
1361
			ast_mutex_lock(&q->lock);
1380
			ast_mutex_lock(&q->lock);
1362
			q->membercount--;
1381
			q->membercount--;
1363
		}
1382
		}
1364
		ao2_ref(m, -1);
1383
		ao2_ref(m, -1);
1365
	}
1384
	}
[+20] [20] 487 lines
[+20] [+] static int ring_entry(struct queue_ent *qe, struct callattempt *tmp, int *busies)
1853
	if (!tmp->chan) {			/* If we can't, just go on to the next call */
1872
	if (!tmp->chan) {			/* If we can't, just go on to the next call */
1854
		if (qe->chan->cdr)
1873
		if (qe->chan->cdr)
1855
			ast_cdr_busy(qe->chan->cdr);
1874
			ast_cdr_busy(qe->chan->cdr);
1856
		tmp->stillgoing = 0;
1875
		tmp->stillgoing = 0;
1857

    
   
1876

   
1858
		update_status(tmp->member->interface, ast_device_state(tmp->member->interface));
1877
		update_status(tmp->member->interface, ast_device_state(tmp->member->state_interface));
1859

    
   
1878

   
1860
		ast_mutex_lock(&qe->parent->lock);
1879
		ast_mutex_lock(&qe->parent->lock);
1861
		qe->parent->rrpos++;
1880
		qe->parent->rrpos++;
1862
		ast_mutex_unlock(&qe->parent->lock);
1881
		ast_mutex_unlock(&qe->parent->lock);
1863

    
   
1882

   
[+20] [20] 1392 lines
[+20] [+] static struct member *interface_exists(struct call_queue *q, const char *interface)
3256
}
3275
}
3257

    
   
3276

   
3258

    
   
3277

   
3259
/* Dump all members in a specific queue to the database
3278
/* Dump all members in a specific queue to the database
3260
 *
3279
 *
3261
 * <pm_family>/<queuename> = <interface>;<penalty>;<paused>[|...]
3280
 * <pm_family>/<queuename> = <interface>;<penalty>;<paused>;<state_interface>[|...]
3262
 *
3281
 *
3263
 */
3282
 */
3264
static void dump_queue_members(struct call_queue *pm_queue)
3283
static void dump_queue_members(struct call_queue *pm_queue)
3265
{
3284
{
3266
	struct member *cur_member;
3285
	struct member *cur_member;
[+20] [20] 12 lines
[+20] static void dump_queue_members(struct call_queue *pm_queue)
3279
		if (!cur_member->dynamic) {
3298
		if (!cur_member->dynamic) {
3280
			ao2_ref(cur_member, -1);
3299
			ao2_ref(cur_member, -1);
3281
			continue;
3300
			continue;
3282
		}
3301
		}
3283

    
   
3302

   
3284
		res = snprintf(value + value_len, sizeof(value) - value_len, "%s%s;%d;%d;%s",
3303
		res = snprintf(value + value_len, sizeof(value) - value_len, "%s%s;%d;%d;%s;%s",
3285
			value_len ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername);
3304
			value_len ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername, cur_member->state_interface);
3286

    
   
3305

   
3287
		ao2_ref(cur_member, -1);
3306
		ao2_ref(cur_member, -1);
3288

    
   
3307

   
3289
		if (res != strlen(value + value_len)) {
3308
		if (res != strlen(value + value_len)) {
3290
			ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
3309
			ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
[+20] [20] 39 lines
[+20] [+] static int remove_from_queue(const char *queuename, const char *interface)
3330
				"Queue: %s\r\n"
3349
				"Queue: %s\r\n"
3331
				"Location: %s\r\n"
3350
				"Location: %s\r\n"
3332
				"MemberName: %s\r\n",
3351
				"MemberName: %s\r\n",
3333
				q->name, mem->interface, mem->membername);
3352
				q->name, mem->interface, mem->membername);
3334
			ao2_unlink(q->members, mem);
3353
			ao2_unlink(q->members, mem);

    
   
3354
			remove_from_interfaces(mem->state_interface);
3335
			ao2_ref(mem, -1);
3355
			ao2_ref(mem, -1);
3336

    
   
3356

   
3337
			if (queue_persistent_members)
3357
			if (queue_persistent_members)
3338
				dump_queue_members(q);
3358
				dump_queue_members(q);
3339
			
3359
			
3340
			res = RES_OKAY;
3360
			res = RES_OKAY;
3341
		} else {
3361
		} else {
3342
			res = RES_EXISTS;
3362
			res = RES_EXISTS;
3343
		}
3363
		}
3344
		ast_mutex_unlock(&q->lock);
3364
		ast_mutex_unlock(&q->lock);
3345
		break;
3365
		break;
3346
	}
3366
	}
3347

    
   
3367

   
3348
	if (res == RES_OKAY)

   
3349
		remove_from_interfaces(interface);

   
3350

    
   

   
3351
	AST_LIST_UNLOCK(&queues);
3368
	AST_LIST_UNLOCK(&queues);
3352

    
   
3369

   
3353
	return res;
3370
	return res;
3354
}
3371
}
3355

    
   
3372

   
3356

    
   
3373

   
3357
static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump)
3374
static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump, const char *state_interface)
3358
{
3375
{
3359
	struct call_queue *q;
3376
	struct call_queue *q;
3360
	struct member *new_member, *old_member;
3377
	struct member *new_member, *old_member;
3361
	int res = RES_NOSUCHQUEUE;
3378
	int res = RES_NOSUCHQUEUE;
3362

    
   
3379

   
[+20] [20] 4 lines
[+20] static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump) [+] static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump, const char *state_interface)
3367

    
   
3384

   
3368
	AST_LIST_LOCK(&queues);
3385
	AST_LIST_LOCK(&queues);
3369

    
   
3386

   
3370
	ast_mutex_lock(&q->lock);
3387
	ast_mutex_lock(&q->lock);
3371
	if ((old_member = interface_exists(q, interface)) == NULL) {
3388
	if ((old_member = interface_exists(q, interface)) == NULL) {
3372
		add_to_interfaces(interface);
3389
		if ((new_member = create_queue_member(interface, membername, penalty, paused, state_interface))) {
3373
		if ((new_member = create_queue_member(interface, membername, penalty, paused))) {
3390
			add_to_interfaces(new_member->state_interface);
3374
			new_member->dynamic = 1;
3391
			new_member->dynamic = 1;
3375
			ao2_link(q->members, new_member);
3392
			ao2_link(q->members, new_member);
3376
			q->membercount++;
3393
			q->membercount++;
3377
			manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
3394
			manager_event(EVENT_FLAG_AGENT, "QueueMemberAdded",
3378
				"Queue: %s\r\n"
3395
				"Queue: %s\r\n"
[+20] [20] 81 lines
[+20] [+] static void reload_queue_members(void)
3460
	char *cur_ptr;
3477
	char *cur_ptr;
3461
	char *queue_name;
3478
	char *queue_name;
3462
	char *member;
3479
	char *member;
3463
	char *interface;
3480
	char *interface;
3464
	char *membername = NULL;
3481
	char *membername = NULL;

    
   
3482
	char *state_interface;
3465
	char *penalty_tok;
3483
	char *penalty_tok;
3466
	int penalty = 0;
3484
	int penalty = 0;
3467
	char *paused_tok;
3485
	char *paused_tok;
3468
	int paused = 0;
3486
	int paused = 0;
3469
	struct ast_db_entry *db_tree;
3487
	struct ast_db_entry *db_tree;
[+20] [20] 38 lines
[+20] static void reload_queue_members(void)
3508

    
   
3526

   
3509
			interface = strsep(&member, ";");
3527
			interface = strsep(&member, ";");
3510
			penalty_tok = strsep(&member, ";");
3528
			penalty_tok = strsep(&member, ";");
3511
			paused_tok = strsep(&member, ";");
3529
			paused_tok = strsep(&member, ";");
3512
			membername = strsep(&member, ";");
3530
			membername = strsep(&member, ";");

    
   
3531
			state_interface = strsep(&member,";");
3513

    
   
3532

   
3514
			if (!penalty_tok) {
3533
			if (!penalty_tok) {
3515
				ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
3534
				ast_log(LOG_WARNING, "Error parsing persistent member string for '%s' (penalty)\n", queue_name);
3516
				break;
3535
				break;
3517
			}
3536
			}
[+20] [20] 16 lines
[+20] static void reload_queue_members(void)
3534
				membername = interface;
3553
				membername = interface;
3535

    
   
3554

   
3536
			if (option_debug)
3555
			if (option_debug)
3537
				ast_log(LOG_DEBUG, "Reload Members: Queue: %s  Member: %s  Name: %s  Penalty: %d  Paused: %d\n", queue_name, interface, membername, penalty, paused);
3556
				ast_log(LOG_DEBUG, "Reload Members: Queue: %s  Member: %s  Name: %s  Penalty: %d  Paused: %d\n", queue_name, interface, membername, penalty, paused);
3538
			
3557
			
3539
			if (add_to_queue(queue_name, interface, membername, penalty, paused, 0) == RES_OUTOFMEMORY) {
3558
			if (add_to_queue(queue_name, interface, membername, penalty, paused, 0, state_interface) == RES_OUTOFMEMORY) {
3540
				ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
3559
				ast_log(LOG_ERROR, "Out of Memory when reloading persistent queue member\n");
3541
				break;
3560
				break;
3542
			}
3561
			}
3543
		}
3562
		}
3544
	}
3563
	}
[+20] [20] 188 lines
[+20] [+] static int aqm_exec(struct ast_channel *chan, void *data)
3733
		AST_APP_ARG(queuename);
3752
		AST_APP_ARG(queuename);
3734
		AST_APP_ARG(interface);
3753
		AST_APP_ARG(interface);
3735
		AST_APP_ARG(penalty);
3754
		AST_APP_ARG(penalty);
3736
		AST_APP_ARG(options);
3755
		AST_APP_ARG(options);
3737
		AST_APP_ARG(membername);
3756
		AST_APP_ARG(membername);

    
   
3757
		AST_APP_ARG(state_interface);
3738
	);
3758
	);
3739
	int penalty = 0;
3759
	int penalty = 0;
3740

    
   
3760

   
3741
	if (ast_strlen_zero(data)) {
3761
	if (ast_strlen_zero(data)) {
3742
		ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|[interface]|[penalty][|options][|membername]])\n");
3762
		ast_log(LOG_WARNING, "AddQueueMember requires an argument (queuename[|interface[|penalty[|options[|membername[|state_interface]]]]])\n");
3743
		return -1;
3763
		return -1;
3744
	}
3764
	}
3745

    
   
3765

   
3746
	parse = ast_strdupa(data);
3766
	parse = ast_strdupa(data);
3747

    
   
3767

   
[+20] [20] 18 lines
[+20] static int aqm_exec(struct ast_channel *chan, void *data)
3766
	if (args.options) {
3786
	if (args.options) {
3767
		if (strchr(args.options, 'j'))
3787
		if (strchr(args.options, 'j'))
3768
			priority_jump = 1;
3788
			priority_jump = 1;
3769
	}
3789
	}
3770

    
   
3790

   
3771
	switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members)) {
3791
	switch (add_to_queue(args.queuename, args.interface, args.membername, penalty, 0, queue_persistent_members, args.state_interface)) {
3772
	case RES_OKAY:
3792
	case RES_OKAY:
3773
		ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", "");
3793
		ast_queue_log(args.queuename, chan->uniqueid, args.interface, "ADDMEMBER", "%s", "");
3774
		ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
3794
		ast_log(LOG_NOTICE, "Added interface '%s' to queue '%s'\n", args.interface, args.queuename);
3775
		pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
3795
		pbx_builtin_setvar_helper(chan, "AQMSTATUS", "ADDED");
3776
		res = 0;
3796
		res = 0;
[+20] [20] 514 lines
[+20] [+] static int reload_queues(void)
4291
	struct member *cur, *newm;
4311
	struct member *cur, *newm;
4292
	struct ao2_iterator mem_iter;
4312
	struct ao2_iterator mem_iter;
4293
	int new;
4313
	int new;
4294
	const char *general_val = NULL;
4314
	const char *general_val = NULL;
4295
	char parse[80];
4315
	char parse[80];
4296
	char *interface;
4316
	char *interface, *state_interface;
4297
	char *membername = NULL;
4317
	char *membername = NULL;
4298
	int penalty;
4318
	int penalty;
4299
	AST_DECLARE_APP_ARGS(args,
4319
	AST_DECLARE_APP_ARGS(args,
4300
		AST_APP_ARG(interface);
4320
		AST_APP_ARG(interface);
4301
		AST_APP_ARG(penalty);
4321
		AST_APP_ARG(penalty);
4302
		AST_APP_ARG(membername);
4322
		AST_APP_ARG(membername);

    
   
4323
		AST_APP_ARG(state_interface);
4303
	);
4324
	);
4304
	
4325
	
4305
	if (!(cfg = ast_config_load("queues.conf"))) {
4326
	if (!(cfg = ast_config_load("queues.conf"))) {
4306
		ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
4327
		ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
4307
		return 0;
4328
		return 0;
[+20] [20] 81 lines
[+20] static int reload_queues(void)
4389
						if (!ast_strlen_zero(args.membername)) {
4410
						if (!ast_strlen_zero(args.membername)) {
4390
							membername = args.membername;
4411
							membername = args.membername;
4391
							while (*membername && *membername < 33) membername++;
4412
							while (*membername && *membername < 33) membername++;
4392
						}
4413
						}
4393

    
   
4414

   

    
   
4415
						if (!ast_strlen_zero(args.state_interface)) {

    
   
4416
							state_interface = args.state_interface;

    
   
4417
							while (*state_interface && *state_interface < 33) state_interface++;

    
   
4418
						} else {

    
   
4419
							state_interface = interface;

    
   
4420
						}

    
   
4421

   
4394
						/* Find the old position in the list */
4422
						/* Find the old position in the list */
4395
						ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
4423
						ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
4396
						cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK);
4424
						cur = ao2_find(q->members, &tmpmem, OBJ_POINTER | OBJ_UNLINK);
4397

    
   
4425

   
4398
						newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0);
4426
						/* Only attempt removing from interfaces list if the new state_interface is different than the old one */

    
   
4427
						if (cur && strcasecmp(cur->state_interface, state_interface)) {

    
   
4428
							remove_from_interfaces(cur->state_interface);

    
   
4429
						}

    
   
4430

   

    
   
4431
						newm = create_queue_member(interface, membername, penalty, cur ? cur->paused : 0, state_interface);

    
   
4432
						if (!cur || (cur && strcasecmp(cur->state_interface, state_interface))) {

    
   
4433
							add_to_interfaces(state_interface);

    
   
4434
						}
4399
						ao2_link(q->members, newm);
4435
						ao2_link(q->members, newm);
4400
						ao2_ref(newm, -1);
4436
						ao2_ref(newm, -1);
4401
						newm = NULL;
4437
						newm = NULL;
4402

    
   
4438

   
4403
						if (cur)
4439
						if (cur)
4404
							ao2_ref(cur, -1);
4440
							ao2_ref(cur, -1);
4405
						else {
4441
						else {
4406
							/* Add them to the master int list if necessary */

   
4407
							add_to_interfaces(interface);

   
4408
							q->membercount++;
4442
							q->membercount++;
4409
						}
4443
						}
4410
					} else {
4444
					} else {
4411
						queue_set_param(q, var->name, var->value, var->lineno, 1);
4445
						queue_set_param(q, var->name, var->value, var->lineno, 1);
4412
					}
4446
					}
[+20] [20] 7 lines
[+20] static int reload_queues(void)
4420
						continue;
4454
						continue;
4421
					}
4455
					}
4422

    
   
4456

   
4423
					q->membercount--;
4457
					q->membercount--;
4424
					ao2_unlink(q->members, cur);
4458
					ao2_unlink(q->members, cur);
4425
					remove_from_interfaces(cur->interface);
4459
					remove_from_interfaces(cur->state_interface);
4426
					ao2_ref(cur, -1);
4460
					ao2_ref(cur, -1);
4427
				}
4461
				}
4428

    
   
4462

   
4429
				if (q->strategy == QUEUE_STRATEGY_ROUNDROBIN)
4463
				if (q->strategy == QUEUE_STRATEGY_ROUNDROBIN)
4430
					rr_dep_warning();
4464
					rr_dep_warning();
[+20] [20] 318 lines
[+20] [+] static int manager_queues_status(struct mansession *s, const struct message *m)
4749
	return RESULT_SUCCESS;
4783
	return RESULT_SUCCESS;
4750
}
4784
}
4751

    
   
4785

   
4752
static int manager_add_queue_member(struct mansession *s, const struct message *m)
4786
static int manager_add_queue_member(struct mansession *s, const struct message *m)
4753
{
4787
{
4754
	const char *queuename, *interface, *penalty_s, *paused_s, *membername;
4788
	const char *queuename, *interface, *penalty_s, *paused_s, *membername, *state_interface;
4755
	int paused, penalty = 0;
4789
	int paused, penalty = 0;
4756

    
   
4790

   
4757
	queuename = astman_get_header(m, "Queue");
4791
	queuename = astman_get_header(m, "Queue");
4758
	interface = astman_get_header(m, "Interface");
4792
	interface = astman_get_header(m, "Interface");
4759
	penalty_s = astman_get_header(m, "Penalty");
4793
	penalty_s = astman_get_header(m, "Penalty");
4760
	paused_s = astman_get_header(m, "Paused");
4794
	paused_s = astman_get_header(m, "Paused");
4761
	membername = astman_get_header(m, "MemberName");
4795
	membername = astman_get_header(m, "MemberName");

    
   
4796
	state_interface = astman_get_header(m, "StateInterface");
4762

    
   
4797

   
4763
	if (ast_strlen_zero(queuename)) {
4798
	if (ast_strlen_zero(queuename)) {
4764
		astman_send_error(s, m, "'Queue' not specified.");
4799
		astman_send_error(s, m, "'Queue' not specified.");
4765
		return 0;
4800
		return 0;
4766
	}
4801
	}
[+20] [20] 11 lines
[+20] static int manager_add_queue_member(struct mansession *s, const struct message *m)
4778
	if (ast_strlen_zero(paused_s))
4813
	if (ast_strlen_zero(paused_s))
4779
		paused = 0;
4814
		paused = 0;
4780
	else
4815
	else
4781
		paused = abs(ast_true(paused_s));
4816
		paused = abs(ast_true(paused_s));
4782

    
   
4817

   
4783
	switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members)) {
4818
	switch (add_to_queue(queuename, interface, membername, penalty, paused, queue_persistent_members, state_interface)) {
4784
	case RES_OKAY:
4819
	case RES_OKAY:
4785
		ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", "");
4820
		ast_queue_log(queuename, "MANAGER", interface, "ADDMEMBER", "%s", "");
4786
		astman_send_ack(s, m, "Added interface to queue");
4821
		astman_send_ack(s, m, "Added interface to queue");
4787
		break;
4822
		break;
4788
	case RES_EXISTS:
4823
	case RES_EXISTS:
[+20] [20] 65 lines
[+20] [+] static int manager_pause_queue_member(struct mansession *s, const struct message *m)
4854
	else
4889
	else
4855
		astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
4890
		astman_send_ack(s, m, paused ? "Interface paused successfully" : "Interface unpaused successfully");
4856
	return 0;
4891
	return 0;
4857
}
4892
}
4858

    
   
4893

   

    
   
4894
/* Check out BE... */
4859
static int handle_queue_add_member(int fd, int argc, char *argv[])
4895
static int handle_queue_add_member(int fd, int argc, char *argv[])
4860
{
4896
{
4861
	char *queuename, *interface, *membername = NULL;
4897
	char *queuename, *interface, *membername = NULL, *state_interface = NULL;
4862
	int penalty;
4898
	int penalty;
4863

    
   
4899

   
4864
	if ((argc != 6) && (argc != 8) && (argc != 10)) {
4900
	if ((argc != 6) && (argc != 8) && (argc != 10)) {
4865
		return RESULT_SHOWUSAGE;
4901
		return RESULT_SHOWUSAGE;
4866
	} else if (strcmp(argv[4], "to")) {
4902
	} else if (strcmp(argv[4], "to")) {
[+20] [20] 22 lines
[+20] static int handle_queue_add_member(int fd, int argc, char *argv[])
4889

    
   
4925

   
4890
	if (argc >= 10) {
4926
	if (argc >= 10) {
4891
		membername = argv[9];
4927
		membername = argv[9];
4892
	}
4928
	}
4893

    
   
4929

   
4894
	switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members)) {
4930
	if (argc >= 12) {

    
   
4931
		state_interface = argv[11];

    
   
4932
	}

    
   
4933

   

    
   
4934
	switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface)) {
4895
	case RES_OKAY:
4935
	case RES_OKAY:
4896
		ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", "");
4936
		ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", "");
4897
		ast_cli(fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
4937
		ast_cli(fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
4898
		return RESULT_SUCCESS;
4938
		return RESULT_SUCCESS;
4899
	case RES_EXISTS:
4939
	case RES_EXISTS:
[+20] [20] 34 lines
[+20] [+] static char *complete_queue_add_member(const char *line, const char *word, int pos, int state)
4934
		}
4974
		}
4935
	case 8: /* only one possible match, "as" */
4975
	case 8: /* only one possible match, "as" */
4936
		return state == 0 ? ast_strdup("as") : NULL;
4976
		return state == 0 ? ast_strdup("as") : NULL;
4937
	case 9:	/* Don't attempt to complete name of member (infinite possibilities) */
4977
	case 9:	/* Don't attempt to complete name of member (infinite possibilities) */
4938
		return NULL;
4978
		return NULL;

    
   
4979
	case 10:

    
   
4980
		return state == 0 ? ast_strdup("state_interface") : NULL;
4939
	default:
4981
	default:
4940
		return NULL;
4982
		return NULL;
4941
	}
4983
	}
4942
}
4984
}
4943

    
   
4985

   
[+20] [20] 73 lines
[+20] [+] static char *complete_queue_remove_member(const char *line, const char *word, int pos, int state)
5017
static char queue_show_usage[] =
5059
static char queue_show_usage[] =
5018
"Usage: queue show\n"
5060
"Usage: queue show\n"
5019
"       Provides summary information on a specified queue.\n";
5061
"       Provides summary information on a specified queue.\n";
5020

    
   
5062

   
5021
static char qam_cmd_usage[] =
5063
static char qam_cmd_usage[] =
5022
"Usage: queue add member <channel> to <queue> [penalty <penalty>]\n";
5064
"Usage: queue add member <channel> to <queue> [penalty <penalty> [as <membername> [state_interface <state_interface>]]]\n";
5023

    
   
5065

   
5024
static char qrm_cmd_usage[] =
5066
static char qrm_cmd_usage[] =
5025
"Usage: queue remove member <channel> from <queue>\n";
5067
"Usage: queue remove member <channel> from <queue>\n";
5026

    
   
5068

   
5027
static struct ast_cli_entry cli_show_queue_deprecated = {
5069
static struct ast_cli_entry cli_show_queue_deprecated = {
[+20] [20] 117 lines
  1. /branches/1.4/apps/app_queue.c: Loading...

https://reviewboard.asterisk.org/ runs on a server provided by Digium, Inc. and uses bandwidth donated to the open source Asterisk community by API Digital Communications in Huntsville, AL USA.
Please report problems with this site to asteriskteam@digium.com.