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 3 (Latest)

1 2 3
1 2 3

  1. /branches/1.4/apps/app_queue.c: Loading...
/branches/1.4/apps/app_queue.c
Revision 184672 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
			}

    
   
925
			ao2_ref(mem, -1);
913
		}
926
		}
914
		ast_mutex_unlock(&q->lock);
927
		ast_mutex_unlock(&q->lock);
915
		if (ret)
928
		if (ret)
916
			break;
929
			break;
917
	}
930
	}
[+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);
1119
			ast_log(LOG_WARNING, "Unknown keyword in queue '%s': %s\n", q->name, param);
1107
		}
1120
		}
1108
	}
1121
	}
1109
}
1122
}
1110

    
   
1123

   
1111
static void rt_handle_member_record(struct call_queue *q, char *interface, const char *membername, const char *penalty_str, const char *paused_str)
1124
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
{
1125
{
1113
	struct member *m, tmpmem;
1126
	struct member *m, tmpmem;
1114
	int penalty = 0;
1127
	int penalty = 0;
1115
	int paused  = 0;
1128
	int paused  = 0;
1116

    
   
1129

   
[+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));
1143
	ast_copy_string(tmpmem.interface, interface, sizeof(tmpmem.interface));
1131
	m = ao2_find(q->members, &tmpmem, OBJ_POINTER);
1144
	m = ao2_find(q->members, &tmpmem, OBJ_POINTER);
1132

    
   
1145

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

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

    
   
1162
			remove_from_interfaces(m->state_interface);

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

    
   
1164
			add_to_interfaces(m->state_interface);

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

    
   
1170

   
[+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);
1175
	struct ao2_iterator mem_iter = ao2_iterator_init(q->members, 0);
1158

    
   
1176

   
1159
	while ((cur = ao2_iterator_next(&mem_iter))) {
1177
	while ((cur = ao2_iterator_next(&mem_iter))) {
1160
		if (all || !cur->dynamic) {
1178
		if (all || !cur->dynamic) {
1161
			ao2_unlink(q->members, cur);
1179
			ao2_unlink(q->members, cur);
1162
			remove_from_interfaces(cur->interface);
1180
			remove_from_interfaces(cur->state_interface);
1163
			q->membercount--;
1181
			q->membercount--;
1164
		}
1182
		}
1165
		ao2_ref(cur, -1);
1183
		ao2_ref(cur, -1);
1166
	}
1184
	}
1167
}
1185
}
[+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

    
   
1294

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

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

    
   
1302

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

    
   
1365

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

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

    
   
1373

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

    
   
1877

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

    
   
1879

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

    
   
1883

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

    
   
3277

   
3258

    
   
3278

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

    
   
3303

   
3284
		res = snprintf(value + value_len, sizeof(value) - value_len, "%s%s;%d;%d;%s",
3304
		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);
3305
			value_len ? "|" : "", cur_member->interface, cur_member->penalty, cur_member->paused, cur_member->membername, cur_member->state_interface);
3286

    
   
3306

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

    
   
3308

   
3289
		if (res != strlen(value + value_len)) {
3309
		if (res != strlen(value + value_len)) {
3290
			ast_log(LOG_WARNING, "Could not create persistent member string, out of space\n");
3310
			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"
3350
				"Queue: %s\r\n"
3331
				"Location: %s\r\n"
3351
				"Location: %s\r\n"
3332
				"MemberName: %s\r\n",
3352
				"MemberName: %s\r\n",
3333
				q->name, mem->interface, mem->membername);
3353
				q->name, mem->interface, mem->membername);
3334
			ao2_unlink(q->members, mem);
3354
			ao2_unlink(q->members, mem);

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

    
   
3357

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

    
   
3368

   
3348
	if (res == RES_OKAY)

   
3349
		remove_from_interfaces(interface);

   
3350

    
   

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

    
   
3370

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

    
   
3373

   
3356

    
   
3374

   
3357
static int add_to_queue(const char *queuename, const char *interface, const char *membername, int penalty, int paused, int dump)
3375
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
{
3376
{
3359
	struct call_queue *q;
3377
	struct call_queue *q;
3360
	struct member *new_member, *old_member;
3378
	struct member *new_member, *old_member;
3361
	int res = RES_NOSUCHQUEUE;
3379
	int res = RES_NOSUCHQUEUE;
3362

    
   
3380

   
[+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

    
   
3385

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

    
   
3387

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

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

    
   
3527

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

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

    
   
3533

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

    
   
3555

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

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

    
   
3761

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

    
   
3766

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

    
   
3768

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

    
   
3791

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

    
   
4324
		AST_APP_ARG(state_interface);
4303
	);
4325
	);
4304
	
4326
	
4305
	if (!(cfg = ast_config_load("queues.conf"))) {
4327
	if (!(cfg = ast_config_load("queues.conf"))) {
4306
		ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
4328
		ast_log(LOG_NOTICE, "No call queueing config file (queues.conf), so no call queues\n");
4307
		return 0;
4329
		return 0;
[+20] [20] 67 lines
[+20] static int reload_queues(void)
4375
						
4397
						
4376
						AST_NONSTANDARD_APP_ARGS(args, parse, ',');
4398
						AST_NONSTANDARD_APP_ARGS(args, parse, ',');
4377

    
   
4399

   
4378
						interface = args.interface;
4400
						interface = args.interface;
4379
						if (!ast_strlen_zero(args.penalty)) {
4401
						if (!ast_strlen_zero(args.penalty)) {
4380
							tmp = args.penalty;
4402
							tmp = ast_skip_blanks(args.penalty);
4381
							while (*tmp && *tmp < 33) tmp++;

   
4382
							penalty = atoi(tmp);
4403
							penalty = atoi(tmp);
4383
							if (penalty < 0) {
4404
							if (penalty < 0) {
4384
								penalty = 0;
4405
								penalty = 0;
4385
							}
4406
							}
4386
						} else
4407
						} else
4387
							penalty = 0;
4408
							penalty = 0;
4388

    
   
4409

   
4389
						if (!ast_strlen_zero(args.membername)) {
4410
						if (!ast_strlen_zero(args.membername)) {
4390
							membername = args.membername;
4411
							membername = ast_skip_blanks(args.membername);
4391
							while (*membername && *membername < 33) membername++;
4412
						}

    
   
4413

   

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

    
   
4415
							state_interface = ast_skip_blanks(args.state_interface);

    
   
4416
						} else {

    
   
4417
							state_interface = interface;
4392
						}
4418
						}
4393

    
   
4419

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

    
   
4423

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

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

    
   
4426
							remove_from_interfaces(cur->state_interface);

    
   
4427
						}

    
   
4428

   

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

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

    
   
4431
							add_to_interfaces(state_interface);

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

    
   
4436

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

   
4407
							add_to_interfaces(interface);

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

    
   
4454

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

    
   
4460

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

    
   
4783

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

    
   
4788

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

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

    
   
4795

   
4763
	if (ast_strlen_zero(queuename)) {
4796
	if (ast_strlen_zero(queuename)) {
4764
		astman_send_error(s, m, "'Queue' not specified.");
4797
		astman_send_error(s, m, "'Queue' not specified.");
4765
		return 0;
4798
		return 0;
4766
	}
4799
	}
[+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))
4811
	if (ast_strlen_zero(paused_s))
4779
		paused = 0;
4812
		paused = 0;
4780
	else
4813
	else
4781
		paused = abs(ast_true(paused_s));
4814
		paused = abs(ast_true(paused_s));
4782

    
   
4815

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

    
   
4891

   
4859
static int handle_queue_add_member(int fd, int argc, char *argv[])
4892
static int handle_queue_add_member(int fd, int argc, char *argv[])
4860
{
4893
{
4861
	char *queuename, *interface, *membername = NULL;
4894
	char *queuename, *interface, *membername = NULL, *state_interface = NULL;
4862
	int penalty;
4895
	int penalty;
4863

    
   
4896

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

    
   
4922

   
4890
	if (argc >= 10) {
4923
	if (argc >= 10) {
4891
		membername = argv[9];
4924
		membername = argv[9];
4892
	}
4925
	}
4893

    
   
4926

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

    
   
4928
		state_interface = argv[11];

    
   
4929
	}

    
   
4930

   

    
   
4931
	switch (add_to_queue(queuename, interface, membername, penalty, 0, queue_persistent_members, state_interface)) {
4895
	case RES_OKAY:
4932
	case RES_OKAY:
4896
		ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", "");
4933
		ast_queue_log(queuename, "CLI", interface, "ADDMEMBER", "%s", "");
4897
		ast_cli(fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
4934
		ast_cli(fd, "Added interface '%s' to queue '%s'\n", interface, queuename);
4898
		return RESULT_SUCCESS;
4935
		return RESULT_SUCCESS;
4899
	case RES_EXISTS:
4936
	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
		}
4971
		}
4935
	case 8: /* only one possible match, "as" */
4972
	case 8: /* only one possible match, "as" */
4936
		return state == 0 ? ast_strdup("as") : NULL;
4973
		return state == 0 ? ast_strdup("as") : NULL;
4937
	case 9:	/* Don't attempt to complete name of member (infinite possibilities) */
4974
	case 9:	/* Don't attempt to complete name of member (infinite possibilities) */
4938
		return NULL;
4975
		return NULL;

    
   
4976
	case 10:

    
   
4977
		return state == 0 ? ast_strdup("state_interface") : NULL;
4939
	default:
4978
	default:
4940
		return NULL;
4979
		return NULL;
4941
	}
4980
	}
4942
}
4981
}
4943

    
   
4982

   
[+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[] =
5056
static char queue_show_usage[] =
5018
"Usage: queue show\n"
5057
"Usage: queue show\n"
5019
"       Provides summary information on a specified queue.\n";
5058
"       Provides summary information on a specified queue.\n";
5020

    
   
5059

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

    
   
5062

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

    
   
5065

   
5027
static struct ast_cli_entry cli_show_queue_deprecated = {
5066
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.