📄 chan_skinny.c
字号:
/* time_t lastouttime; */ /* Unused */ int progress; int ringing; int onhold; /* int lastout; */ /* Unused */ int cxmode; int nat; int outgoing; int alreadygone; struct skinny_subchannel *next; struct skinny_line *parent;};struct skinny_line { ast_mutex_t lock; char name[80]; char label[24]; /* Label that shows next to the line buttons */ char accountcode[AST_MAX_ACCOUNT_CODE]; char exten[AST_MAX_EXTENSION]; /* Extension where to start */ char context[AST_MAX_CONTEXT]; char language[MAX_LANGUAGE]; char cid_num[AST_MAX_EXTENSION]; /* Caller*ID */ char cid_name[AST_MAX_EXTENSION]; /* Caller*ID */ char lastcallerid[AST_MAX_EXTENSION]; /* Last Caller*ID */ char call_forward[AST_MAX_EXTENSION]; char mailbox[AST_MAX_EXTENSION]; char mohinterpret[MAX_MUSICCLASS]; char mohsuggest[MAX_MUSICCLASS]; char lastnumberdialed[AST_MAX_EXTENSION]; /* Last number that was dialed - used for redial */ int curtone; /* Current tone being played */ ast_group_t callgroup; ast_group_t pickupgroup; int callwaiting; int transfer; int threewaycalling; int mwiblink; int cancallforward; int callreturn; int dnd; /* How does this affect callwait? Do we just deny a skinny_request if we're dnd? */ int hascallerid; int hidecallerid; int amaflags; int type; int instance; int group; int needdestroy; int capability; int nonCodecCapability; int onhooktime; int msgstate; /* voicemail message state */ int immediate; int hookstate; int nat; struct ast_codec_pref prefs; struct skinny_subchannel *sub; struct skinny_line *next; struct skinny_device *parent;};struct skinny_speeddial { ast_mutex_t lock; char label[42]; char exten[AST_MAX_EXTENSION]; int instance; struct skinny_speeddial *next; struct skinny_device *parent;};struct skinny_addon { ast_mutex_t lock; char type[10]; struct skinny_addon *next; struct skinny_device *parent;};static struct skinny_device { /* A device containing one or more lines */ char name[80]; char id[16]; char version_id[16]; int type; int registered; int lastlineinstance; int lastcallreference; int capability; int earlyrtp; char exten[AST_MAX_EXTENSION]; struct sockaddr_in addr; struct in_addr ourip; struct skinny_line *lines; struct skinny_speeddial *speeddials; struct skinny_addon *addons; struct ast_codec_pref prefs; struct ast_ha *ha; struct skinnysession *session; struct skinny_device *next;} *devices = NULL;struct skinny_paging_device { char name[80]; char id[16]; struct skinny_device ** devices; struct skinny_paging_device *next;};static struct skinnysession { pthread_t t; ast_mutex_t lock; struct sockaddr_in sin; int fd; char inbuf[SKINNY_MAX_PACKET]; char outbuf[SKINNY_MAX_PACKET]; struct skinny_device *device; struct skinnysession *next;} *sessions = NULL;static struct ast_channel *skinny_request(const char *type, int format, void *data, int *cause);static int skinny_call(struct ast_channel *ast, char *dest, int timeout);static int skinny_hangup(struct ast_channel *ast);static int skinny_answer(struct ast_channel *ast);static struct ast_frame *skinny_read(struct ast_channel *ast);static int skinny_write(struct ast_channel *ast, struct ast_frame *frame);static int skinny_indicate(struct ast_channel *ast, int ind, const void *data, size_t datalen);static int skinny_fixup(struct ast_channel *oldchan, struct ast_channel *newchan);static int skinny_senddigit_begin(struct ast_channel *ast, char digit);static int skinny_senddigit_end(struct ast_channel *ast, char digit, unsigned int duration);static int handle_time_date_req_message(struct skinny_req *req, struct skinnysession *s);static const struct ast_channel_tech skinny_tech = { .type = "Skinny", .description = tdesc, .capabilities = ((AST_FORMAT_MAX_AUDIO << 1) - 1), .properties = AST_CHAN_TP_WANTSJITTER | AST_CHAN_TP_CREATESJITTER, .requester = skinny_request, .call = skinny_call, .hangup = skinny_hangup, .answer = skinny_answer, .read = skinny_read, .write = skinny_write, .indicate = skinny_indicate, .fixup = skinny_fixup, .send_digit_begin = skinny_senddigit_begin, .send_digit_end = skinny_senddigit_end,/* .bridge = ast_rtp_bridge, */};static void *get_button_template(struct skinnysession *s, struct button_definition_template *btn){ struct skinny_device *d = s->device; struct skinny_addon *a = d->addons; int i; switch (d->type) { case SKINNY_DEVICE_30SPPLUS: case SKINNY_DEVICE_30VIP: /* 13 rows, 2 columns */ for (i = 0; i < 4; i++) (btn++)->buttonDefinition = BT_LINE; (btn++)->buttonDefinition = BT_REDIAL; (btn++)->buttonDefinition = BT_VOICEMAIL; (btn++)->buttonDefinition = BT_CALLPARK; (btn++)->buttonDefinition = BT_FORWARDALL; (btn++)->buttonDefinition = BT_CONFERENCE; for (i = 0; i < 4; i++) (btn++)->buttonDefinition = BT_NONE; for (i = 0; i < 13; i++) (btn++)->buttonDefinition = BT_SPEEDDIAL; break; case SKINNY_DEVICE_12SPPLUS: case SKINNY_DEVICE_12SP: case SKINNY_DEVICE_12: /* 6 rows, 2 columns */ for (i = 0; i < 2; i++) (btn++)->buttonDefinition = BT_LINE; (btn++)->buttonDefinition = BT_REDIAL; for (i = 0; i < 3; i++) (btn++)->buttonDefinition = BT_SPEEDDIAL; (btn++)->buttonDefinition = BT_HOLD; (btn++)->buttonDefinition = BT_TRANSFER; (btn++)->buttonDefinition = BT_FORWARDALL; (btn++)->buttonDefinition = BT_CALLPARK; (btn++)->buttonDefinition = BT_VOICEMAIL; (btn++)->buttonDefinition = BT_CONFERENCE; break; case SKINNY_DEVICE_7910: (btn++)->buttonDefinition = BT_LINE; (btn++)->buttonDefinition = BT_HOLD; (btn++)->buttonDefinition = BT_TRANSFER; (btn++)->buttonDefinition = BT_DISPLAY; (btn++)->buttonDefinition = BT_VOICEMAIL; (btn++)->buttonDefinition = BT_CONFERENCE; (btn++)->buttonDefinition = BT_FORWARDALL; for (i = 0; i < 2; i++) (btn++)->buttonDefinition = BT_SPEEDDIAL; (btn++)->buttonDefinition = BT_REDIAL; break; case SKINNY_DEVICE_7960: case SKINNY_DEVICE_7961: case SKINNY_DEVICE_7961GE: case SKINNY_DEVICE_7962: case SKINNY_DEVICE_7965: for (i = 0; i < 6; i++) (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL; break; case SKINNY_DEVICE_7940: case SKINNY_DEVICE_7941: case SKINNY_DEVICE_7941GE: case SKINNY_DEVICE_7942: case SKINNY_DEVICE_7945: for (i = 0; i < 2; i++) (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL; break; case SKINNY_DEVICE_7935: case SKINNY_DEVICE_7936: for (i = 0; i < 2; i++) (btn++)->buttonDefinition = BT_LINE; break; case SKINNY_DEVICE_ATA186: (btn++)->buttonDefinition = BT_LINE; break; case SKINNY_DEVICE_7970: case SKINNY_DEVICE_7971: case SKINNY_DEVICE_7975: case SKINNY_DEVICE_CIPC: for (i = 0; i < 8; i++) (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL; break; case SKINNY_DEVICE_7985: /* XXX I have no idea what the buttons look like on these. */ ast_log(LOG_WARNING, "Unsupported device type '%d (7985)' found.\n", d->type); break; case SKINNY_DEVICE_7912: case SKINNY_DEVICE_7911: case SKINNY_DEVICE_7905: (btn++)->buttonDefinition = BT_LINE; (btn++)->buttonDefinition = BT_HOLD; break; case SKINNY_DEVICE_7920: /* XXX I don't know if this is right. */ for (i = 0; i < 4; i++) (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL; break; case SKINNY_DEVICE_7921: for (i = 0; i < 6; i++) (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL; break; case SKINNY_DEVICE_7902: ast_log(LOG_WARNING, "Unsupported device type '%d (7902)' found.\n", d->type); break; case SKINNY_DEVICE_7906: ast_log(LOG_WARNING, "Unsupported device type '%d (7906)' found.\n", d->type); break; case SKINNY_DEVICE_7931: ast_log(LOG_WARNING, "Unsupported device type '%d (7931)' found.\n", d->type); break; case SKINNY_DEVICE_7937: ast_log(LOG_WARNING, "Unsupported device type '%d (7937)' found.\n", d->type); break; case SKINNY_DEVICE_7914: ast_log(LOG_WARNING, "Unsupported device type '%d (7914)' found. Expansion module registered by itself?\n", d->type); break; case SKINNY_DEVICE_SCCPGATEWAY_AN: case SKINNY_DEVICE_SCCPGATEWAY_BRI: ast_log(LOG_WARNING, "Unsupported device type '%d (SCCP gateway)' found.\n", d->type); break; default: ast_log(LOG_WARNING, "Unknown device type '%d' found.\n", d->type); break; } for (a = d->addons; a; a = a->next) { if (!strcasecmp(a->type, "7914")) { for (i = 0; i < 14; i++) (btn++)->buttonDefinition = BT_CUST_LINESPEEDDIAL; } else { ast_log(LOG_WARNING, "Unknown addon type '%s' found. Skipping.\n", a->type); } } return btn;}static struct skinny_req *req_alloc(size_t size, int response_message){ struct skinny_req *req; if (!(req = ast_calloc(1, skinny_header_size + size + 4))) return NULL; req->len = htolel(size+4); req->e = htolel(response_message); return req;}static struct skinny_line *find_line_by_instance(struct skinny_device *d, int instance){ struct skinny_line *l; if (!instance) instance = 1; for (l = d->lines; l; l = l->next) { if (l->instance == instance) break; } if (!l) { ast_log(LOG_WARNING, "Could not find line with instance '%d' on device '%s'\n", instance, d->name); } return l;}static struct skinny_line *find_line_by_name(const char *dest){ struct skinny_line *l; struct skinny_device *d; char line[256]; char *at; char *device; ast_copy_string(line, dest, sizeof(line)); at = strchr(line, '@'); if (!at) { ast_log(LOG_NOTICE, "Device '%s' has no @ (at) sign!\n", dest); return NULL; } *at++ = '\0'; device = at; ast_mutex_lock(&devicelock); for (d = devices; d; d = d->next) { if (!strcasecmp(d->name, device)) { if (skinnydebug) ast_verbose("Found device: %s\n", d->name); /* Found the device */ for (l = d->lines; l; l = l->next) { /* Search for the right line */ if (!strcasecmp(l->name, line)) { ast_mutex_unlock(&devicelock); return l; } } } } /* Device not found */ ast_mutex_unlock(&devicelock); return NULL;}/* It's quicker/easier to find the subchannel when we know the instance number too */static struct skinny_subchannel *find_subchannel_by_instance_reference(struct skinny_device *d, int instance, int reference){ struct skinny_line *l = find_line_by_instance(d, instance); struct skinny_subchannel *sub; if (!l) { return NULL; } if (!reference) sub = l->sub; else { for (sub = l->sub; sub; sub = sub->next) { if (sub->callid == reference) break; } } if (!sub) { ast_log(LOG_WARNING, "Could not find subchannel with reference '%d' on '%s'\n", reference, d->name); } return sub;}/* Find the subchannel when we only have the callid - this shouldn't happen often */static struct skinny_subchannel *find_subchannel_by_reference(struct skinny_device *d, int reference){ struct skinny_line *l; struct skinny_subchannel *sub = NULL; for (l = d->lines; l; l = l->next) { for (sub = l->sub; sub; sub = sub->next) { if (sub->callid == reference) break; } if (sub) break; } if (!l) { ast_log(LOG_WARNING, "Could not find any lines that contained a subchannel with reference '%d' on device '%s'\n", reference, d->name); } else { if (!sub) { ast_log(LOG_WARNING, "Could not find subchannel with reference '%d' on '%s@%s'\n", reference, l->name, d->name); } } return sub;}static struct skinny_speeddial *find_speeddial_by_instance(struct skinny_device *d, int instance){ struct skinny_speeddial *sd; for (sd = d->speeddials; sd; sd = sd->next) { if (sd->instance == instance) break; } if (!sd) { ast_log(LOG_WARNING, "Could not find speeddial with instance '%d' on device '%s'\n", instance, d->name); } return sd;}static int codec_skinny2ast(enum skinny_codecs skinnycodec){ switch (skinnycodec) { case SKINNY_CODEC_ALAW: return AST_FORMAT_ALAW; case SKINNY_CODEC_ULAW: return AST_FORMAT_ULAW; case SKINNY_CODEC_G723_1: return AST_FORMAT_G723_1; case SKINNY_CODEC_G729A: return AST_FORMAT_G729A; case SKINNY_CODEC_G726_32: return AST_FORMAT_G726_AAL2; /* XXX Is this right? */ case SKINNY_CODEC_H261: return AST_FORMAT_H261; case SKINNY_CODEC_H263: return AST_FORMAT_H263; default: return 0; }}static int codec_ast2skinny(int astcodec){ switch (astcodec) { case AST_FORMAT_ALAW: return SKINNY_CODEC_ALAW; case AST_FORMAT_ULAW: return SKINNY_CODEC_ULAW; case AST_FORMAT_G723_1: return SKINNY_CODEC_G723_1; case AST_FORMAT_G729A: return SKINNY_CODEC_G729A; case AST_FORMAT_G726_AAL2: /* XXX Is this right? */ return SKINNY_CODEC_G726_32; case AST_FORMAT_H261: return SKINNY_CODEC_H261; case AST_FORMAT_H263: return SKINNY_CODEC_H263; default: return 0; }}static int skinny_register(struct skinny_req *req, struct skinnysession *s){ struct skinny_device *d; struct sockaddr_in sin; socklen_t slen; ast_mutex_lock(&devicelock); for (d = devices; d; d = d->next) { if (!strcasecmp(req->data.reg.name, d->id) && ast_apply_ha(d->ha, &(s->sin))) { s->device = d;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -