2007-04-27 23:02:27 +00:00
|
|
|
/*
|
|
|
|
* An implementation of Common ISDN API 2.0 for Asterisk
|
|
|
|
*
|
2009-01-17 17:35:55 +00:00
|
|
|
* Copyright (C) 2005-2009 Cytronics & Melware
|
2007-04-27 23:02:27 +00:00
|
|
|
*
|
|
|
|
* Armin Schindler <armin@melware.de>
|
|
|
|
*
|
|
|
|
* This program is free software and may be modified and
|
|
|
|
* distributed under the terms of the GNU Public License.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
2007-04-29 22:28:30 +00:00
|
|
|
#include <errno.h>
|
|
|
|
#include <sys/signal.h>
|
2007-04-27 23:02:27 +00:00
|
|
|
|
2009-03-12 15:56:20 +00:00
|
|
|
#include "chan_capi_platform.h"
|
2007-04-27 23:02:27 +00:00
|
|
|
#include "chan_capi20.h"
|
|
|
|
#include "chan_capi.h"
|
|
|
|
#include "chan_capi_chat.h"
|
|
|
|
#include "chan_capi_utils.h"
|
|
|
|
|
2007-10-22 21:37:00 +00:00
|
|
|
#define CHAT_FLAG_MOH 0x0001
|
2007-04-27 23:02:27 +00:00
|
|
|
|
2009-04-30 15:22:27 +00:00
|
|
|
typedef enum {
|
|
|
|
RoomMemberDefault = 0, /* Rx/Tx by default, muted by operator */
|
|
|
|
RoomMemberListener = 1, /* Rx only, always muted */
|
|
|
|
RoomMemberOperator = 2 /* Rx/Tx, newer muted */
|
|
|
|
} room_member_type_t;
|
|
|
|
|
|
|
|
typedef enum {
|
|
|
|
RoomModeDefault = 0,
|
|
|
|
RoomModeMuted = 0,
|
|
|
|
} room_mode_t;
|
|
|
|
|
2009-04-07 22:20:28 +00:00
|
|
|
#define PLCI_PER_LX_REQUEST 8
|
|
|
|
|
2007-04-27 23:02:27 +00:00
|
|
|
struct capichat_s {
|
2007-04-30 15:19:28 +00:00
|
|
|
char name[16];
|
2007-04-27 23:02:27 +00:00
|
|
|
unsigned int number;
|
2007-10-22 21:37:00 +00:00
|
|
|
int active;
|
2009-04-30 15:22:27 +00:00
|
|
|
room_member_type_t room_member_type;
|
2007-04-27 23:02:27 +00:00
|
|
|
struct capi_pvt *i;
|
|
|
|
struct capichat_s *next;
|
|
|
|
};
|
|
|
|
|
2009-04-07 22:20:28 +00:00
|
|
|
struct _deffered_chat_capi_message;
|
|
|
|
typedef struct _deffered_chat_capi_message {
|
|
|
|
int busy;
|
|
|
|
_cdword datapath;
|
|
|
|
capi_prestruct_t p_struct;
|
|
|
|
unsigned char p_list[254];
|
|
|
|
} deffered_chat_capi_message_t;
|
|
|
|
|
2007-04-27 23:02:27 +00:00
|
|
|
static struct capichat_s *chat_list = NULL;
|
|
|
|
AST_MUTEX_DEFINE_STATIC(chat_lock);
|
|
|
|
|
2009-04-30 15:22:27 +00:00
|
|
|
/*
|
|
|
|
LOCALS
|
|
|
|
*/
|
|
|
|
const char* room_member_type_2_name (room_member_type_t room_member_type);
|
|
|
|
|
2007-04-27 23:02:27 +00:00
|
|
|
/*
|
2009-04-07 22:20:28 +00:00
|
|
|
* partial update the capi mixer for the given char room
|
2007-04-27 23:02:27 +00:00
|
|
|
*/
|
2009-04-10 07:23:20 +00:00
|
|
|
static struct capichat_s* update_capi_mixer_part(
|
|
|
|
struct capichat_s *chat_start,
|
|
|
|
int overall_found,
|
|
|
|
deffered_chat_capi_message_t* capi_msg,
|
|
|
|
int remove,
|
|
|
|
unsigned int roomnumber,
|
|
|
|
struct capi_pvt *i)
|
2007-04-27 23:02:27 +00:00
|
|
|
{
|
2009-04-10 07:23:20 +00:00
|
|
|
struct capi_pvt *ii, *ii_last = NULL;
|
2007-04-27 23:02:27 +00:00
|
|
|
struct capichat_s *room;
|
2009-04-07 22:20:28 +00:00
|
|
|
unsigned char* p_list = &capi_msg->p_list[0];
|
2007-04-27 23:02:27 +00:00
|
|
|
_cdword dest;
|
|
|
|
_cdword datapath;
|
2009-04-07 22:20:28 +00:00
|
|
|
capi_prestruct_t* p_struct = &capi_msg->p_struct;
|
2007-04-27 23:02:27 +00:00
|
|
|
unsigned int found = 0;
|
|
|
|
_cword j = 0;
|
2009-04-10 07:23:20 +00:00
|
|
|
struct capichat_s *new_chat_start = NULL;
|
2009-04-30 15:22:27 +00:00
|
|
|
room_member_type_t main_member_type = RoomMemberDefault;
|
|
|
|
|
|
|
|
room = chat_start;
|
|
|
|
while (room != 0) {
|
|
|
|
if (room->i == i) {
|
|
|
|
main_member_type = room->room_member_type;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
room = room->next;
|
|
|
|
}
|
2007-04-27 23:02:27 +00:00
|
|
|
|
2009-04-07 22:20:28 +00:00
|
|
|
room = chat_start;
|
2007-04-27 23:02:27 +00:00
|
|
|
while (room) {
|
|
|
|
if ((room->number == roomnumber) &&
|
2007-04-29 22:28:30 +00:00
|
|
|
(room->i != i)) {
|
2009-04-10 07:23:20 +00:00
|
|
|
if ((found >= PLCI_PER_LX_REQUEST) || ((j + 9) > sizeof(capi_msg->p_list))) {
|
2007-04-27 23:02:27 +00:00
|
|
|
/* maybe we need to split capi messages here */
|
2009-04-10 07:23:20 +00:00
|
|
|
new_chat_start = room;
|
2007-04-27 23:02:27 +00:00
|
|
|
break;
|
|
|
|
}
|
2009-04-07 22:20:28 +00:00
|
|
|
found++;
|
2007-04-29 22:28:30 +00:00
|
|
|
ii = room->i;
|
2009-04-09 13:45:52 +00:00
|
|
|
ii_last = ii;
|
2007-04-27 23:02:27 +00:00
|
|
|
p_list[j++] = 8;
|
2007-04-29 22:28:30 +00:00
|
|
|
p_list[j++] = (_cbyte)(ii->PLCI);
|
|
|
|
p_list[j++] = (_cbyte)(ii->PLCI >> 8);
|
|
|
|
p_list[j++] = (_cbyte)(ii->PLCI >> 16);
|
|
|
|
p_list[j++] = (_cbyte)(ii->PLCI >> 24);
|
2007-04-27 23:02:27 +00:00
|
|
|
dest = (remove) ? 0x00000000 : 0x00000003;
|
2009-04-14 21:58:03 +00:00
|
|
|
if (ii->channeltype == CAPI_CHANNELTYPE_NULL && ii->line_plci == 0) {
|
2007-04-29 22:28:30 +00:00
|
|
|
dest |= 0x00000030;
|
|
|
|
}
|
2009-04-30 15:22:27 +00:00
|
|
|
if (remove == 0) {
|
|
|
|
room_member_type_t room_member_type = room->room_member_type;
|
|
|
|
|
|
|
|
if (main_member_type == RoomMemberListener && room_member_type == RoomMemberListener) {
|
|
|
|
dest &= ~3U; /* Disable data transmission between two listener */
|
|
|
|
} else if (main_member_type == RoomMemberListener && room_member_type != RoomMemberListener) {
|
|
|
|
dest &= ~1U; /* Disable data transmission from main PLCI to member PLCI */
|
|
|
|
} else if (main_member_type != RoomMemberListener && room_member_type == RoomMemberListener) {
|
|
|
|
dest &= ~2U; /* Disable data transmission from member PLCI to main PLCI */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-04-27 23:02:27 +00:00
|
|
|
p_list[j++] = (_cbyte)(dest);
|
|
|
|
p_list[j++] = (_cbyte)(dest >> 8);
|
|
|
|
p_list[j++] = (_cbyte)(dest >> 16);
|
|
|
|
p_list[j++] = (_cbyte)(dest >> 24);
|
2008-02-24 12:57:52 +00:00
|
|
|
cc_verbose(3, 1, VERBOSE_PREFIX_3 CC_MESSAGE_NAME
|
|
|
|
" mixer: listed %s PLCI=0x%04x LI=0x%x\n", ii->vname, ii->PLCI, dest);
|
2007-04-27 23:02:27 +00:00
|
|
|
}
|
|
|
|
room = room->next;
|
|
|
|
}
|
|
|
|
|
2009-04-07 22:20:28 +00:00
|
|
|
if (found != 0) {
|
|
|
|
p_struct->wLen = j;
|
|
|
|
p_struct->info = p_list;
|
2007-04-27 23:02:27 +00:00
|
|
|
|
|
|
|
/* don't send DATA_B3 to me */
|
|
|
|
datapath = 0x00000000;
|
|
|
|
if (remove) {
|
|
|
|
/* now we need DATA_B3 again */
|
2009-04-14 21:58:03 +00:00
|
|
|
if (i->line_plci == 0) {
|
|
|
|
if (i->channeltype != CAPI_CHANNELTYPE_NULL) {
|
|
|
|
datapath = 0x0000000c;
|
|
|
|
} else {
|
|
|
|
datapath = 0x00000030;
|
|
|
|
}
|
2009-04-09 13:45:52 +00:00
|
|
|
}
|
2009-04-14 21:58:03 +00:00
|
|
|
|
2009-04-07 22:20:28 +00:00
|
|
|
if (overall_found == 1) {
|
2007-04-27 23:02:27 +00:00
|
|
|
/* only one left, enable DATA_B3 too */
|
2009-04-14 21:58:03 +00:00
|
|
|
if (ii_last->line_plci == 0) {
|
|
|
|
if (ii_last->channeltype != CAPI_CHANNELTYPE_NULL) {
|
|
|
|
p_list[5] |= 0x0c;
|
|
|
|
} else {
|
|
|
|
p_list[5] |= 0x30;
|
|
|
|
}
|
2009-04-09 13:45:52 +00:00
|
|
|
}
|
2007-04-27 23:02:27 +00:00
|
|
|
}
|
|
|
|
}
|
2009-04-14 21:58:03 +00:00
|
|
|
if (i->channeltype == CAPI_CHANNELTYPE_NULL && i->line_plci == 0) {
|
2007-05-12 11:28:04 +00:00
|
|
|
if (!remove) {
|
|
|
|
datapath |= 0x00000030;
|
|
|
|
}
|
2007-04-29 22:28:30 +00:00
|
|
|
}
|
2007-04-27 23:02:27 +00:00
|
|
|
|
2009-04-07 22:20:28 +00:00
|
|
|
capi_msg->busy = 1;
|
|
|
|
capi_msg->datapath = datapath;
|
|
|
|
}
|
|
|
|
|
|
|
|
return (new_chat_start);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void update_capi_mixer(int remove, unsigned int roomnumber, struct capi_pvt *i)
|
|
|
|
{
|
|
|
|
struct capichat_s *room;
|
|
|
|
unsigned int overall_found;
|
|
|
|
unsigned int nr_segments;
|
|
|
|
|
|
|
|
if (i->PLCI == 0) {
|
|
|
|
cc_verbose(2, 0, VERBOSE_PREFIX_3 CC_MESSAGE_NAME
|
|
|
|
" mixer: %s: PLCI is unset, abort.\n", i->vname);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
cc_mutex_lock(&chat_lock);
|
|
|
|
/*
|
|
|
|
Get overall amount of parties
|
2009-04-10 07:23:20 +00:00
|
|
|
*/
|
2009-04-07 22:20:28 +00:00
|
|
|
for (room = chat_list, overall_found = 0; room != 0; room = room->next) {
|
|
|
|
overall_found += ((room->number == roomnumber) && (room->i != i));
|
|
|
|
}
|
|
|
|
|
2009-04-07 22:26:59 +00:00
|
|
|
room = chat_list;
|
|
|
|
while (room != 0) {
|
|
|
|
if (room->number == roomnumber) {
|
|
|
|
room->active = overall_found + ((remove != 0) ? 0 : 1);
|
|
|
|
}
|
|
|
|
room = room->next;
|
|
|
|
}
|
|
|
|
|
2009-04-07 22:20:28 +00:00
|
|
|
nr_segments = overall_found/PLCI_PER_LX_REQUEST + (overall_found%PLCI_PER_LX_REQUEST != 0);
|
|
|
|
if (nr_segments != 0) {
|
|
|
|
deffered_chat_capi_message_t segments[nr_segments];
|
|
|
|
struct capichat_s *chat_start;
|
|
|
|
int segment_nr, nr;
|
|
|
|
|
|
|
|
for (segment_nr = 0, chat_start = chat_list; segment_nr < nr_segments && chat_start != 0; segment_nr++) {
|
|
|
|
segments[segment_nr].busy = 0;
|
|
|
|
chat_start = update_capi_mixer_part(chat_start, overall_found, &segments[segment_nr], remove, roomnumber, i);
|
|
|
|
}
|
|
|
|
|
|
|
|
cc_mutex_unlock(&chat_lock);
|
2007-04-30 14:02:22 +00:00
|
|
|
|
2009-04-07 22:20:28 +00:00
|
|
|
if (chat_start != 0) {
|
|
|
|
cc_log(LOG_ERROR, "%s:%s at %d.\n", __FILE__, __FUNCTION__, __LINE__);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (nr = 0; nr < segment_nr; nr++) {
|
|
|
|
if (segments[nr].busy != 0) {
|
|
|
|
cc_verbose(3, 1, VERBOSE_PREFIX_3 CC_MESSAGE_NAME
|
2009-04-10 07:23:20 +00:00
|
|
|
" mixer: %s PLCI=0x%04x LI=0x%x\n", i->vname, i->PLCI, segments[nr].datapath);
|
2009-04-07 22:20:28 +00:00
|
|
|
|
|
|
|
capi_sendf(NULL, 0, CAPI_FACILITY_REQ, i->PLCI, get_capi_MessageNumber(),
|
2009-04-10 07:23:20 +00:00
|
|
|
"w(w(dc))",
|
|
|
|
FACILITYSELECTOR_LINE_INTERCONNECT,
|
|
|
|
0x0001, /* CONNECT */
|
|
|
|
segments[nr].datapath,
|
|
|
|
&segments[nr].p_struct);
|
2009-04-07 22:20:28 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
2007-04-27 23:02:27 +00:00
|
|
|
}
|
2009-04-07 22:20:28 +00:00
|
|
|
|
|
|
|
cc_mutex_unlock(&chat_lock);
|
2007-04-27 23:02:27 +00:00
|
|
|
}
|
|
|
|
|
2009-04-07 22:20:28 +00:00
|
|
|
|
2007-04-27 23:02:27 +00:00
|
|
|
/*
|
|
|
|
* delete a chat member
|
|
|
|
*/
|
|
|
|
static void del_chat_member(struct capichat_s *room)
|
|
|
|
{
|
|
|
|
struct capichat_s *tmproom;
|
|
|
|
struct capichat_s *tmproom2 = NULL;
|
|
|
|
unsigned int roomnumber = room->number;
|
2007-04-29 22:28:30 +00:00
|
|
|
struct capi_pvt *i = room->i;
|
2007-04-27 23:02:27 +00:00
|
|
|
|
|
|
|
cc_mutex_lock(&chat_lock);
|
|
|
|
tmproom = chat_list;
|
|
|
|
while (tmproom) {
|
|
|
|
if (tmproom == room) {
|
|
|
|
if (!tmproom2) {
|
|
|
|
chat_list = tmproom->next;
|
|
|
|
} else {
|
|
|
|
tmproom2->next = tmproom->next;
|
|
|
|
}
|
2007-04-29 14:00:32 +00:00
|
|
|
cc_verbose(3, 0, VERBOSE_PREFIX_3 "%s: removed chat member from room '%s' (%d)\n",
|
|
|
|
room->i->vname, room->name, room->number);
|
2007-04-27 23:02:27 +00:00
|
|
|
free(room);
|
|
|
|
}
|
|
|
|
tmproom2 = tmproom;
|
|
|
|
tmproom = tmproom->next;
|
|
|
|
}
|
|
|
|
cc_mutex_unlock(&chat_lock);
|
|
|
|
|
2007-04-29 22:28:30 +00:00
|
|
|
update_capi_mixer(1, roomnumber, i);
|
2007-04-27 23:02:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* add a new chat member
|
|
|
|
*/
|
2009-04-30 15:22:27 +00:00
|
|
|
static struct capichat_s *add_chat_member(char *roomname, struct capi_pvt *i, room_member_type_t room_member_type)
|
2007-04-27 23:02:27 +00:00
|
|
|
{
|
|
|
|
struct capichat_s *room = NULL;
|
|
|
|
struct capichat_s *tmproom;
|
|
|
|
unsigned int roomnumber = 1;
|
|
|
|
|
|
|
|
room = malloc(sizeof(struct capichat_s));
|
|
|
|
if (room == NULL) {
|
2008-02-24 12:57:52 +00:00
|
|
|
cc_log(LOG_ERROR, "Unable to allocate chan_capi chat struct.\n");
|
2007-04-27 23:02:27 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
memset(room, 0, sizeof(struct capichat_s));
|
|
|
|
|
|
|
|
strncpy(room->name, roomname, sizeof(room->name));
|
|
|
|
room->name[sizeof(room->name) - 1] = 0;
|
|
|
|
room->i = i;
|
2009-04-30 15:22:27 +00:00
|
|
|
room->room_member_type = room_member_type;
|
|
|
|
|
2007-04-27 23:02:27 +00:00
|
|
|
cc_mutex_lock(&chat_lock);
|
|
|
|
|
|
|
|
tmproom = chat_list;
|
|
|
|
while (tmproom) {
|
|
|
|
if (!strcmp(tmproom->name, roomname)) {
|
|
|
|
roomnumber = tmproom->number;
|
|
|
|
break;
|
|
|
|
} else {
|
|
|
|
if (tmproom->number == roomnumber) {
|
|
|
|
roomnumber++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tmproom = tmproom->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
room->number = roomnumber;
|
|
|
|
|
|
|
|
room->next = chat_list;
|
|
|
|
chat_list = room;
|
|
|
|
|
|
|
|
cc_mutex_unlock(&chat_lock);
|
|
|
|
|
2009-04-30 15:22:27 +00:00
|
|
|
cc_verbose(3, 0, VERBOSE_PREFIX_3 "%s: added new chat member to room '%s' %s(%d)\n",
|
|
|
|
i->vname, roomname, room_member_type_2_name (room_member_type), roomnumber);
|
2007-04-27 23:02:27 +00:00
|
|
|
|
2007-04-29 22:28:30 +00:00
|
|
|
update_capi_mixer(0, roomnumber, i);
|
2007-04-27 23:02:27 +00:00
|
|
|
|
|
|
|
return room;
|
|
|
|
}
|
|
|
|
|
2007-04-29 22:28:30 +00:00
|
|
|
/*
|
|
|
|
* loop during chat
|
|
|
|
*/
|
2007-10-22 21:37:00 +00:00
|
|
|
static void chat_handle_events(struct ast_channel *c, struct capi_pvt *i,
|
|
|
|
struct capichat_s *room, unsigned int flags)
|
2007-04-29 22:28:30 +00:00
|
|
|
{
|
|
|
|
struct ast_frame *f;
|
|
|
|
int ms;
|
|
|
|
int exception;
|
|
|
|
int ready_fd;
|
2007-05-01 18:10:39 +00:00
|
|
|
int waitfd;
|
2007-04-29 22:28:30 +00:00
|
|
|
int nfds = 0;
|
|
|
|
struct ast_channel *rchan;
|
2007-05-01 18:10:39 +00:00
|
|
|
struct ast_channel *chan = c;
|
2007-10-22 21:37:00 +00:00
|
|
|
int moh_active = 0;
|
|
|
|
|
|
|
|
ast_indicate(chan, -1);
|
2007-04-29 22:28:30 +00:00
|
|
|
|
2007-05-01 18:10:39 +00:00
|
|
|
waitfd = i->readerfd;
|
2007-04-29 22:28:30 +00:00
|
|
|
if (i->channeltype == CAPI_CHANNELTYPE_NULL) {
|
|
|
|
nfds = 1;
|
|
|
|
ast_set_read_format(chan, capi_capability);
|
|
|
|
ast_set_write_format(chan, capi_capability);
|
|
|
|
}
|
|
|
|
|
2007-10-22 21:37:00 +00:00
|
|
|
if ((flags & CHAT_FLAG_MOH) && (room->active < 2)) {
|
2008-01-19 22:24:44 +00:00
|
|
|
#if defined(CC_AST_HAS_VERSION_1_6) || defined(CC_AST_HAS_VERSION_1_4)
|
2007-10-22 21:37:00 +00:00
|
|
|
ast_moh_start(chan, NULL, NULL);
|
2008-01-19 22:24:44 +00:00
|
|
|
#else
|
|
|
|
ast_moh_start(chan, NULL);
|
|
|
|
#endif
|
2007-10-22 21:37:00 +00:00
|
|
|
moh_active = 1;
|
|
|
|
}
|
|
|
|
|
2007-04-29 22:28:30 +00:00
|
|
|
while (1) {
|
|
|
|
ready_fd = 0;
|
|
|
|
ms = 100;
|
|
|
|
errno = 0;
|
|
|
|
exception = 0;
|
|
|
|
|
2007-05-01 18:10:39 +00:00
|
|
|
rchan = ast_waitfor_nandfds(&chan, 1, &waitfd, nfds, &exception, &ready_fd, &ms);
|
2007-04-29 22:28:30 +00:00
|
|
|
|
|
|
|
if (rchan) {
|
|
|
|
f = ast_read(chan);
|
|
|
|
if (!f) {
|
2007-05-01 16:05:09 +00:00
|
|
|
cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: chat: no frame, hangup.\n",
|
|
|
|
i->vname);
|
2007-04-29 22:28:30 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP)) {
|
2007-05-01 16:05:09 +00:00
|
|
|
cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: chat: hangup frame.\n",
|
|
|
|
i->vname);
|
2007-04-29 22:28:30 +00:00
|
|
|
ast_frfree(f);
|
|
|
|
break;
|
2007-05-01 18:10:39 +00:00
|
|
|
} else if (f->frametype == AST_FRAME_VOICE) {
|
2007-05-01 16:05:09 +00:00
|
|
|
cc_verbose(5, 1, VERBOSE_PREFIX_3 "%s: chat: voice frame.\n",
|
|
|
|
i->vname);
|
2007-04-29 22:28:30 +00:00
|
|
|
if (i->channeltype == CAPI_CHANNELTYPE_NULL) {
|
|
|
|
capi_write_frame(i, f);
|
|
|
|
}
|
2007-05-05 11:32:54 +00:00
|
|
|
} else if (f->frametype == AST_FRAME_NULL) {
|
|
|
|
/* ignore NULL frame */
|
|
|
|
cc_verbose(5, 1, VERBOSE_PREFIX_3 "%s: chat: NULL frame, ignoring.\n",
|
|
|
|
i->vname);
|
2007-05-01 18:10:39 +00:00
|
|
|
} else {
|
2007-05-05 11:32:54 +00:00
|
|
|
cc_verbose(3, 1, VERBOSE_PREFIX_3 "%s: chat: unhandled frame %d/%d.\n",
|
2007-05-01 18:10:39 +00:00
|
|
|
i->vname, f->frametype, f->subclass);
|
2007-04-29 22:28:30 +00:00
|
|
|
}
|
|
|
|
ast_frfree(f);
|
|
|
|
} else if (ready_fd == i->readerfd) {
|
|
|
|
if (exception) {
|
|
|
|
cc_verbose(1, 0, VERBOSE_PREFIX_3 "%s: chat: exception on readerfd\n",
|
|
|
|
i->vname);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
f = capi_read_pipeframe(i);
|
|
|
|
if (f->frametype == AST_FRAME_VOICE) {
|
|
|
|
ast_write(chan, f);
|
|
|
|
}
|
|
|
|
/* ignore other nullplci frames */
|
|
|
|
} else {
|
|
|
|
if ((ready_fd < 0) && ms) {
|
|
|
|
if (errno == 0 || errno == EINTR)
|
|
|
|
continue;
|
|
|
|
cc_log(LOG_WARNING, "%s: Wait failed (%s).\n",
|
|
|
|
chan->name, strerror(errno));
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2007-10-22 21:37:00 +00:00
|
|
|
if ((moh_active) && (room->active > 1)) {
|
|
|
|
ast_moh_stop(chan);
|
|
|
|
moh_active = 0;
|
|
|
|
}
|
2007-04-29 22:28:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2007-04-27 23:02:27 +00:00
|
|
|
/*
|
|
|
|
* start the chat
|
|
|
|
*/
|
|
|
|
int pbx_capi_chat(struct ast_channel *c, char *param)
|
|
|
|
{
|
|
|
|
struct capi_pvt *i = NULL;
|
2007-04-28 16:48:00 +00:00
|
|
|
char *roomname, *controller, *options;
|
2007-05-13 11:30:34 +00:00
|
|
|
char *p;
|
2007-04-27 23:02:27 +00:00
|
|
|
struct capichat_s *room;
|
2007-05-12 18:21:13 +00:00
|
|
|
ast_group_t tmpcntr;
|
2008-03-23 13:04:30 +00:00
|
|
|
unsigned long long contr = 0;
|
2007-10-22 21:37:00 +00:00
|
|
|
unsigned int flags = 0;
|
2009-04-30 15:22:27 +00:00
|
|
|
room_member_type_t room_member_type = RoomMemberDefault;
|
2007-04-27 23:02:27 +00:00
|
|
|
|
|
|
|
roomname = strsep(¶m, "|");
|
2007-05-13 11:30:34 +00:00
|
|
|
options = strsep(¶m, "|");
|
|
|
|
controller = param;
|
2007-04-27 23:02:27 +00:00
|
|
|
|
|
|
|
if (!roomname) {
|
2008-02-24 12:57:52 +00:00
|
|
|
cc_log(LOG_WARNING, CC_MESSAGE_NAME " chat requires room name.\n");
|
2007-04-27 23:02:27 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-04-28 16:48:00 +00:00
|
|
|
if (controller) {
|
2007-05-13 11:30:34 +00:00
|
|
|
for (p = controller; p && *p; p++) {
|
|
|
|
if (*p == '|') *p = ',';
|
|
|
|
}
|
2007-05-12 18:21:13 +00:00
|
|
|
tmpcntr = ast_get_group(controller);
|
2008-03-23 13:04:30 +00:00
|
|
|
contr = (unsigned long long)(tmpcntr >> 1);
|
2007-04-28 16:48:00 +00:00
|
|
|
}
|
|
|
|
|
2007-10-22 21:37:00 +00:00
|
|
|
while ((options) && (*options)) {
|
|
|
|
switch (*options) {
|
|
|
|
case 'm':
|
|
|
|
flags |= CHAT_FLAG_MOH;
|
|
|
|
break;
|
2009-04-30 15:22:27 +00:00
|
|
|
case 'l':
|
|
|
|
room_member_type = RoomMemberListener;
|
|
|
|
break;
|
|
|
|
case 'o':
|
|
|
|
room_member_type = RoomMemberOperator;
|
|
|
|
break;
|
|
|
|
|
2007-10-22 21:37:00 +00:00
|
|
|
default:
|
|
|
|
cc_log(LOG_WARNING, "Unknown chat option '%c'.\n",
|
|
|
|
*options);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
options++;
|
|
|
|
}
|
|
|
|
|
2008-02-24 12:57:52 +00:00
|
|
|
cc_verbose(3, 1, VERBOSE_PREFIX_3 CC_MESSAGE_NAME " chat: %s: roomname=%s "
|
2008-03-23 13:04:30 +00:00
|
|
|
"options=%s controller=%s (0x%llx)\n",
|
2007-05-13 11:30:34 +00:00
|
|
|
c->name, roomname, options, controller, contr);
|
|
|
|
|
2007-04-28 16:48:00 +00:00
|
|
|
if (c->tech == &capi_tech) {
|
|
|
|
i = CC_CHANNEL_PVT(c);
|
|
|
|
} else {
|
|
|
|
/* virtual CAPI channel */
|
2009-04-10 07:23:20 +00:00
|
|
|
i = pbx_check_resource_plci(c);
|
2009-04-09 22:44:44 +00:00
|
|
|
|
2009-04-10 07:23:20 +00:00
|
|
|
if (i == NULL) {
|
2009-04-09 22:44:44 +00:00
|
|
|
i = capi_mknullif(c, contr);
|
2009-04-10 07:23:20 +00:00
|
|
|
}
|
|
|
|
if (i == NULL) {
|
2007-04-28 16:48:00 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
2007-04-27 23:02:27 +00:00
|
|
|
|
2007-10-22 21:37:00 +00:00
|
|
|
if (c->_state != AST_STATE_UP) {
|
2007-04-28 10:09:58 +00:00
|
|
|
ast_answer(c);
|
2007-10-22 21:37:00 +00:00
|
|
|
}
|
2007-04-28 10:09:58 +00:00
|
|
|
|
2007-04-28 16:48:00 +00:00
|
|
|
capi_wait_for_answered(i);
|
|
|
|
if (!(capi_wait_for_b3_up(i))) {
|
|
|
|
goto out;
|
2007-04-28 10:09:58 +00:00
|
|
|
}
|
|
|
|
|
2009-04-30 15:22:27 +00:00
|
|
|
room = add_chat_member(roomname, i, room_member_type);
|
2007-04-27 23:02:27 +00:00
|
|
|
if (!room) {
|
2008-02-24 12:57:52 +00:00
|
|
|
cc_log(LOG_WARNING, "Unable to open " CC_MESSAGE_NAME " chat room.\n");
|
2007-04-27 23:02:27 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2007-04-30 15:19:28 +00:00
|
|
|
/* main loop */
|
2007-10-22 21:37:00 +00:00
|
|
|
chat_handle_events(c, i, room, flags);
|
2007-04-27 23:02:27 +00:00
|
|
|
|
|
|
|
del_chat_member(room);
|
|
|
|
|
2007-04-28 16:48:00 +00:00
|
|
|
out:
|
2007-05-08 16:30:03 +00:00
|
|
|
capi_remove_nullif(i);
|
2007-04-28 16:48:00 +00:00
|
|
|
|
2007-04-27 23:02:27 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2009-04-10 07:23:20 +00:00
|
|
|
struct capi_pvt* pbx_check_resource_plci(struct ast_channel *c)
|
2009-04-09 22:44:44 +00:00
|
|
|
{
|
|
|
|
struct capi_pvt *i = NULL;
|
|
|
|
const char* id = pbx_builtin_getvar_helper(c, "RESOURCEPLCI");
|
|
|
|
|
|
|
|
if (id != 0) {
|
|
|
|
i = (struct capi_pvt*)strtoul(id, NULL, 0);
|
2009-04-15 12:28:40 +00:00
|
|
|
if (i != 0 && capi_verify_resource_plci(i) != 0) {
|
|
|
|
cc_log(LOG_ERROR, "resource PLCI lost\n");
|
|
|
|
i = 0;
|
|
|
|
}
|
2009-04-09 22:44:44 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return (i);
|
|
|
|
}
|
|
|
|
|
|
|
|
int pbx_capi_chat_associate_resource_plci(struct ast_channel *c, char *param)
|
|
|
|
{
|
|
|
|
struct capi_pvt *i = NULL;
|
|
|
|
char *controller;
|
|
|
|
char *p;
|
|
|
|
ast_group_t tmpcntr;
|
|
|
|
unsigned long long contr = 0;
|
|
|
|
|
|
|
|
controller = param;
|
|
|
|
|
|
|
|
if (controller) {
|
|
|
|
for (p = controller; p && *p; p++) {
|
|
|
|
if (*p == '|') *p = ',';
|
|
|
|
}
|
|
|
|
tmpcntr = ast_get_group(controller);
|
|
|
|
contr = (unsigned long long)(tmpcntr >> 1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (c->tech != &capi_tech) {
|
2009-04-14 21:58:03 +00:00
|
|
|
i = capi_mkresourceif(c, contr, 0);
|
2009-04-10 07:23:20 +00:00
|
|
|
if (i != NULL) {
|
2009-04-09 22:44:44 +00:00
|
|
|
char buffer[24];
|
|
|
|
snprintf(buffer, sizeof(buffer)-1, "%p", i);
|
2009-04-15 12:28:40 +00:00
|
|
|
/**
|
|
|
|
Not sure ast_channel pointer does not change across the
|
|
|
|
use of resource PLCI. For this reason use variable to provide
|
|
|
|
the pointer to resource PLCI to resource PLCI user
|
|
|
|
|
|
|
|
\todo This is still possible that resource PLCI will be lost.
|
|
|
|
In case this happens this will be necessary to maintain one
|
|
|
|
live time stamp on resource PLCI and automatically remove
|
|
|
|
resource LCI if time stamp exceeds certail limit.
|
|
|
|
*/
|
2009-04-09 22:44:44 +00:00
|
|
|
pbx_builtin_setvar_helper(c, "RESOURCEPLCI", buffer);
|
2009-04-15 12:28:40 +00:00
|
|
|
|
2009-04-14 21:58:03 +00:00
|
|
|
capi_mkresourceif(c, contr, i);
|
2009-04-09 22:44:44 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-14 21:58:03 +00:00
|
|
|
return (0); /* Always return success in case c->tech == &capi_tech or to fallback to NULL PLCI */
|
2009-04-09 22:44:44 +00:00
|
|
|
}
|
|
|
|
|
2007-04-30 14:02:22 +00:00
|
|
|
/*
|
|
|
|
* do command capi chatinfo
|
|
|
|
*/
|
2008-01-19 22:24:44 +00:00
|
|
|
#ifdef CC_AST_HAS_VERSION_1_6
|
|
|
|
char *pbxcli_capi_chatinfo(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
|
|
|
|
#else
|
2007-04-30 14:02:22 +00:00
|
|
|
int pbxcli_capi_chatinfo(int fd, int argc, char *argv[])
|
2008-01-19 22:24:44 +00:00
|
|
|
#endif
|
2007-04-30 14:02:22 +00:00
|
|
|
{
|
|
|
|
struct capichat_s *room = NULL;
|
|
|
|
struct ast_channel *c;
|
2008-01-19 22:24:44 +00:00
|
|
|
#ifdef CC_AST_HAS_VERSION_1_6
|
|
|
|
int fd = a->fd;
|
|
|
|
|
|
|
|
if (cmd == CLI_INIT) {
|
2008-02-24 12:57:52 +00:00
|
|
|
e->command = CC_MESSAGE_NAME " chatinfo";
|
2008-01-19 22:24:44 +00:00
|
|
|
e->usage = chatinfo_usage;
|
|
|
|
return NULL;
|
|
|
|
} else if (cmd == CLI_GENERATE)
|
|
|
|
return NULL;
|
|
|
|
if (a->argc != e->args)
|
|
|
|
return CLI_SHOWUSAGE;
|
|
|
|
#else
|
2007-04-30 14:02:22 +00:00
|
|
|
|
|
|
|
if (argc != 2)
|
|
|
|
return RESULT_SHOWUSAGE;
|
2008-01-19 22:24:44 +00:00
|
|
|
#endif
|
2007-04-30 14:02:22 +00:00
|
|
|
|
|
|
|
if (chat_list == NULL) {
|
2008-02-24 12:57:52 +00:00
|
|
|
ast_cli(fd, "There are no members in " CC_MESSAGE_NAME " chat.\n");
|
2007-04-30 14:02:22 +00:00
|
|
|
return RESULT_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2008-02-24 12:57:52 +00:00
|
|
|
ast_cli(fd, CC_MESSAGE_NAME " chat\n");
|
2007-04-30 14:02:22 +00:00
|
|
|
ast_cli(fd, "Room# Roomname Member Caller\n");
|
|
|
|
|
|
|
|
cc_mutex_lock(&chat_lock);
|
|
|
|
room = chat_list;
|
|
|
|
while (room) {
|
|
|
|
c = room->i->owner;
|
2007-05-01 14:26:39 +00:00
|
|
|
if (!c) {
|
|
|
|
c = room->i->used;
|
|
|
|
}
|
|
|
|
if (!c) {
|
|
|
|
ast_cli(fd, "%3d %-12s%-30s\"%s\" <%s>\n",
|
|
|
|
room->number, room->name, room->i->vname,
|
|
|
|
"?", "?");
|
|
|
|
} else {
|
|
|
|
ast_cli(fd, "%3d %-12s%-30s\"%s\" <%s>\n",
|
|
|
|
room->number, room->name, c->name,
|
|
|
|
(c->cid.cid_name) ? c->cid.cid_name:"", c->cid.cid_num);
|
|
|
|
}
|
2007-04-30 14:02:22 +00:00
|
|
|
room = room->next;
|
|
|
|
}
|
|
|
|
cc_mutex_unlock(&chat_lock);
|
|
|
|
|
2008-01-19 22:24:44 +00:00
|
|
|
#ifdef CC_AST_HAS_VERSION_1_6
|
|
|
|
return CLI_SUCCESS;
|
|
|
|
#else
|
2007-04-30 14:02:22 +00:00
|
|
|
return RESULT_SUCCESS;
|
2008-01-19 22:24:44 +00:00
|
|
|
#endif
|
2007-04-30 14:02:22 +00:00
|
|
|
}
|
|
|
|
|
2009-04-30 15:22:27 +00:00
|
|
|
const char* room_member_type_2_name (room_member_type_t room_member_type) {
|
|
|
|
switch (room_member_type) {
|
|
|
|
case RoomMemberListener:
|
|
|
|
return("in listener mode ");
|
|
|
|
case RoomMemberOperator:
|
|
|
|
return("in operator mode ");
|
|
|
|
|
|
|
|
default:
|
|
|
|
return("");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|