dect
/
asterisk
Archived
13
0
Fork 0

Version 0.1.10 from FTP

git-svn-id: http://svn.digium.com/svn/asterisk/trunk@398 f38db490-d61c-443f-a65b-d21fe96a405b
This commit is contained in:
markster 2001-12-27 11:07:33 +00:00
parent 3c950432e5
commit fc3d66ee67
8 changed files with 1309 additions and 77 deletions

View File

@ -182,6 +182,13 @@ static int handle_sendtext(struct ast_channel *chan, int fd, int argc, char *arg
int res;
if (argc != 3)
return RESULT_SHOWUSAGE;
/* At the moment, the parser (perhaps broken) returns with
the last argument PLUS the newline at the end of the input
buffer. This probably needs to be fixed, but I wont do that
because other stuff may break as a result. The right way
would probably be to strip off the trailing newline before
parsing, then here, add a newline at the end of the string
before sending it to ast_sendtext --DUDE */
res = ast_sendtext(chan, argv[2]);
fdprintf(fd, "200 result=%d\n", res);
if (res >= 0)
@ -190,13 +197,47 @@ static int handle_sendtext(struct ast_channel *chan, int fd, int argc, char *arg
return RESULT_FAILURE;
}
static int handle_recvchar(struct ast_channel *chan, int fd, int argc, char *argv[])
{
int res;
if (argc != 3)
return RESULT_SHOWUSAGE;
res = ast_recvchar(chan,atoi(argv[2]));
if (res == 0) {
fdprintf(fd, "200 result=%d (timeout)\n", res);
return RESULT_SUCCESS;
}
if (res > 0) {
fdprintf(fd, "200 result=%d\n", res);
return RESULT_SUCCESS;
}
else {
fdprintf(fd, "200 result=%d (hangup)\n", res);
return RESULT_FAILURE;
}
}
static int handle_tddmode(struct ast_channel *chan, int fd, int argc, char *argv[])
{
int res,x;
if (argc != 3)
return RESULT_SHOWUSAGE;
if (!strncasecmp(argv[2],"on",2)) x = 1; else x = 0;
res = ast_channel_setoption(chan,AST_OPTION_TDD,&x,sizeof(char),0);
fdprintf(fd, "200 result=%d\n", res);
if (res >= 0)
return RESULT_SUCCESS;
else
return RESULT_FAILURE;
}
static int handle_sendimage(struct ast_channel *chan, int fd, int argc, char *argv[])
{
int res;
if (argc != 3)
return RESULT_SHOWUSAGE;
res = ast_send_image(chan, argv[2]);
if (!chan->softhangup)
if (!ast_check_hangup(chan))
res = 0;
fdprintf(fd, "200 result=%d\n", res);
if (res >= 0)
@ -235,7 +276,7 @@ static int handle_saynumber(struct ast_channel *chan, int fd, int argc, char *ar
return RESULT_SHOWUSAGE;
if (sscanf(argv[2], "%i", &num) != 1)
return RESULT_SHOWUSAGE;
res = ast_say_number(chan, num, chan->language);
res = ast_say_number(chan, num, AST_DIGIT_ANY, chan->language);
fdprintf(fd, "200 result=%d\n", res);
if (res >= 0)
return RESULT_SUCCESS;
@ -272,7 +313,7 @@ static int handle_setcontext(struct ast_channel *chan, int fd, int argc, char *a
if (argc != 3)
return RESULT_SHOWUSAGE;
strncpy(chan->context, argv[2], sizeof(chan->context));
strncpy(chan->context, argv[2], sizeof(chan->context)-1);
fdprintf(fd, "200 result=0\n");
return RESULT_SUCCESS;
}
@ -281,7 +322,7 @@ static int handle_setextension(struct ast_channel *chan, int fd, int argc, char
{
if (argc != 3)
return RESULT_SHOWUSAGE;
strncpy(chan->exten, argv[2], sizeof(chan->exten));
strncpy(chan->exten, argv[2], sizeof(chan->exten)-1);
fdprintf(fd, "200 result=0\n");
return RESULT_SUCCESS;
}
@ -450,6 +491,19 @@ static char usage_sendtext[] =
" consisting of greater than one word should be placed in quotes since the\n"
" command only accepts a single argument.\n";
static char usage_recvchar[] =
" Usage: RECEIVE CHAR <timeout>\n"
" Receives a character of text on a channel. Specify timeout to be the\n"
" maximum time to wait for input in milliseconds, or 0 for infinite. Most channels\n"
" do not support the reception of text. Returns the decimal value of the character\n"
" if one is received, or 0 if the channel does not support text reception. Returns\n"
" -1 only on error/hangup.\n";
static char usage_tddmode[] =
" Usage: TDD MODE <on|off>\n"
" Enable/Disable TDD transmission/reception on a channel. Returns 1 if\n"
" successful, or 0 if channel is not TDD-capable.\n";
static char usage_sendimage[] =
" Usage: SEND IMAGE <image>\n"
" Sends the given image on a channel. Most channels do not support the\n"
@ -500,6 +554,8 @@ static char usage_recordfile[] =
agi_command commands[] = {
{ { "wait", "for", "digit", NULL }, handle_waitfordigit, "Waits for a digit to be pressed", usage_waitfordigit },
{ { "send", "text", NULL }, handle_sendtext, "Sends text to channels supporting it", usage_sendtext },
{ { "receive", "char", NULL }, handle_recvchar, "Receives text from channels supporting it", usage_recvchar },
{ { "tdd", "mode", NULL }, handle_tddmode, "Sends text to channels supporting it", usage_tddmode },
{ { "stream", "file", NULL }, handle_streamfile, "Sends audio file on channel", usage_streamfile },
{ { "send", "image", NULL }, handle_sendimage, "Sends images to channels supporting it", usage_sendimage },
{ { "say", "number", NULL }, handle_saynumber, "Says a given number", usage_saynumber },
@ -677,6 +733,14 @@ static int run_agi(struct ast_channel *chan, char *request, int *fds, int pid)
pid = -1;
break;
}
#if 0
/* Un-comment this code to fix the problem with
the newline being included in the parsed
command string(s) output --DUDE */
/* get rid of trailing newline, if any */
if (*buf && buf[strlen(buf) - 1] == '\n')
buf[strlen(buf) - 1] = 0;
#endif
returnstatus |= agi_handle_command(chan, fds[1], buf);
/* If the handle_command returns -1, we need to stop */
if (returnstatus < 0) {
@ -709,7 +773,7 @@ static int agi_exec(struct ast_channel *chan, void *data)
}
strncpy(tmp, data, sizeof(tmp));
strncpy(tmp, data, sizeof(tmp)-1);
strtok(tmp, "|");
args = strtok(NULL, "|");
ringy = strtok(NULL,"|");

View File

@ -172,7 +172,7 @@ static int do_directory(struct ast_channel *chan, struct ast_config *cfg, char *
res = ast_waitstream(chan, AST_DIGIT_ANY);
ast_stopstream(chan);
} else {
res = ast_say_digit_str(chan, v->name, chan->language);
res = ast_say_digit_str(chan, v->name, AST_DIGIT_ANY, chan->language);
}
ahem:
if (!res)
@ -184,9 +184,9 @@ ahem:
ast_stopstream(chan);
if (res > -1) {
if (res == '1') {
strncpy(chan->exten, v->name, sizeof(chan->exten));
strncpy(chan->exten, v->name, sizeof(chan->exten)-1);
chan->priority = 0;
strncpy(chan->context, context, sizeof(chan->context));
strncpy(chan->context, context, sizeof(chan->context)-1);
res = 0;
break;
} else if (res == '*') {

View File

@ -19,6 +19,7 @@
#include <asterisk/config.h>
#include <asterisk/say.h>
#include <asterisk/module.h>
#include <asterisk/adsi.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
@ -50,14 +51,27 @@
static char *tdesc = "Comedian Mail (Voicemail System)";
static char *adapp = "CoMa";
static char *adsec = "_AST";
static char *addesc = "Comedian Mail";
static int adver = 1;
static char *synopsis_vm =
"Leave a voicemail message";
static char *descrip_vm =
" VoiceMail([s]extension): Leaves voicemail for a given extension (must be\n"
"configured in voicemail.conf). If the extension is preceeded by an 's' then\n"
"instructions for leaving the message will be skipped. Returns -1 on error\n"
"or mailbox not found, or if the user hangs up. Otherwise, it returns 0. \n";
" VoiceMail([s|u|b]extension): Leaves voicemail for a given extension (must\n"
"be configured in voicemail.conf). If the extension is preceeded by an 's'"
"then instructions for leaving the message will be skipped. If the extension\n"
"is preceeded by 'u' then the \"unavailable\" message will be played (that is, \n"
"/var/lib/asterisk/sounds/vm/<exten>/unavail) if it exists. If the extension\n"
"is preceeded by a 'b' then the the busy message will be played (that is,\n"
"busy instead of unavail). At most one of 's', 'u', or 'b' may be specified.\n"
"Returns -1 on error or mailbox not found, or if the user hangs up. \n"
"Otherwise, it returns 0. \n";
static char *synopsis_vmain =
"Enter voicemail system";
@ -123,7 +137,7 @@ static int sendmail(char *srcemail, char *email, char *name, int msgnum, char *m
p = popen(SENDMAIL, "w");
if (p) {
if (strchr(srcemail, '@'))
strncpy(who, srcemail, sizeof(who));
strncpy(who, srcemail, sizeof(who)-1);
else {
gethostname(host, sizeof(host));
snprintf(who, sizeof(who), "%s@%s", srcemail, host);
@ -159,7 +173,29 @@ static int get_date(char *s, int len)
return strftime(s, len, "%a %b %e %r %Z %Y", tm);
}
static int leave_voicemail(struct ast_channel *chan, char *ext, int silent)
static int invent_message(struct ast_channel *chan, char *ext, int busy)
{
int res;
res = ast_streamfile(chan, "vm-theperson", chan->language);
if (res)
return -1;
res = ast_waitstream(chan, "#");
if (res)
return res;
res = ast_say_digit_str(chan, ext, "#", chan->language);
if (res)
return res;
if (busy)
res = ast_streamfile(chan, "vm-isonphone", chan->language);
else
res = ast_streamfile(chan, "vm-isunavail", chan->language);
if (res)
return -1;
res = ast_waitstream(chan, "#");
return res;
}
static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int busy, int unavail)
{
struct ast_config *cfg;
char *copy, *name, *passwd, *email, *fmt, *fmts;
@ -175,6 +211,7 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent)
char date[256];
char dir[256];
char fn[256];
char prefile[256]="";
char *astemail;
cfg = ast_load(VOICEMAIL_CONFIG);
@ -185,6 +222,11 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent)
if (!(astemail = ast_variable_retrieve(cfg, "general", "serveremail")))
astemail = ASTERISK_USERNAME;
if ((copy = ast_variable_retrieve(cfg, NULL, ext))) {
/* Setup pre-file if appropriate */
if (busy)
snprintf(prefile, sizeof(prefile), "vm/%s/busy", ext);
else if (unavail)
snprintf(prefile, sizeof(prefile), "vm/%s/unavail", ext);
/* Make sure they have an entry in the config */
copy = strdup(copy);
passwd = strtok(copy, ",");
@ -197,6 +239,27 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent)
make_dir(dir, sizeof(dir), ext, "INBOX");
if (mkdir(dir, 0700) && (errno != EEXIST))
ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
/* Play the beginning intro if desired */
if (strlen(prefile)) {
if (ast_fileexists(prefile, NULL, NULL) < 0) {
if (ast_streamfile(chan, prefile, chan->language) > -1)
silent = ast_waitstream(chan, "#");
} else {
ast_log(LOG_DEBUG, "%s doesn't exist, doing what we can\n", prefile);
silent = invent_message(chan, ext, busy);
}
if (silent < 0) {
ast_log(LOG_DEBUG, "Hang up during prefile playback\n");
free(copy);
return -1;
}
}
/* If they hit "#" we should still play the beep sound */
if (silent == '#') {
if (!ast_streamfile(chan, "beep", chan->language) < 0)
silent = 1;
ast_waitstream(chan, "");
}
/* Stream an info message */
if (silent || !ast_streamfile(chan, INTRO, chan->language)) {
/* Wait for the message to finish */
@ -405,7 +468,7 @@ static int play_and_wait(struct ast_channel *chan, char *fn)
static int say_and_wait(struct ast_channel *chan, int num)
{
int d;
d = ast_say_number(chan, num, chan->language);
d = ast_say_number(chan, num, AST_DIGIT_ANY, chan->language);
return d;
}
@ -476,6 +539,449 @@ static int save_to_folder(char *dir, int msg, char *username, int box)
return 0;
}
static int adsi_logo(unsigned char *buf)
{
int bytes = 0;
bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002 LSS, Inc.", "");
return bytes;
}
static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
{
char buf[256];
int bytes=0;
int x;
char num[5];
*useadsi = 0;
bytes += adsi_data_mode(buf + bytes);
adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
bytes = 0;
bytes += adsi_logo(buf);
bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
#ifdef DISPLAY
bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
#endif
bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
bytes += adsi_data_mode(buf + bytes);
adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
if (adsi_begin_download(chan, addesc, adapp, adsec, adver)) {
bytes = 0;
bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
bytes += adsi_voice_mode(buf + bytes, 0);
adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
return 0;
}
#ifdef DISPLAY
/* Add a dot */
bytes = 0;
bytes += adsi_logo(buf);
bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
#endif
bytes = 0;
bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "4", 1);
bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
#ifdef DISPLAY
/* Add another dot */
bytes = 0;
bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
#endif
bytes = 0;
/* These buttons we load but don't use yet */
bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
#ifdef DISPLAY
/* Add another dot */
bytes = 0;
bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
#endif
bytes = 0;
for (x=0;x<5;x++) {
snprintf(num, sizeof(num), "%d", x);
bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(x), mbox(x), num, 1);
}
bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
#ifdef DISPLAY
/* Add another dot */
bytes = 0;
bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
#endif
if (adsi_end_download(chan)) {
bytes = 0;
bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
bytes += adsi_voice_mode(buf + bytes, 0);
adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
return 0;
}
bytes = 0;
bytes += adsi_download_disconnect(buf + bytes);
adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
ast_log(LOG_DEBUG, "Done downloading scripts...\n");
#ifdef DISPLAY
/* Add last dot */
bytes = 0;
bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
#endif
ast_log(LOG_DEBUG, "Restarting session...\n");
bytes = 0;
/* Load the session now */
if (adsi_load_session(chan, adapp, adver, 1) == 1) {
*useadsi = 1;
bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
} else
bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
return 0;
}
static void adsi_begin(struct ast_channel *chan, int *useadsi)
{
int x;
x = adsi_load_session(chan, adapp, adver, 1);
if (x < 0)
return;
if (!x) {
if (adsi_load_vmail(chan, useadsi)) {
ast_log(LOG_WARNING, "Unable to upload voicemail scripts\n");
return;
}
} else
*useadsi = 1;
}
static void adsi_login(struct ast_channel *chan)
{
char buf[256];
int bytes=0;
unsigned char keys[6];
int x;
if (!adsi_available(chan))
return;
for (x=0;x<6;x++)
keys[x] = 0;
/* Set one key for next */
keys[3] = ADSI_KEY_APPS + 3;
bytes += adsi_logo(buf + bytes);
bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
bytes += adsi_set_keys(buf + bytes, keys);
bytes += adsi_voice_mode(buf + bytes, 0);
adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
}
static void adsi_password(struct ast_channel *chan)
{
char buf[256];
int bytes=0;
unsigned char keys[6];
int x;
if (!adsi_available(chan))
return;
for (x=0;x<6;x++)
keys[x] = 0;
/* Set one key for next */
keys[3] = ADSI_KEY_APPS + 3;
bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
bytes += adsi_set_keys(buf + bytes, keys);
adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
}
static void adsi_folders(struct ast_channel *chan, int start, char *label)
{
char buf[256];
int bytes=0;
unsigned char keys[6];
int x,y;
if (!adsi_available(chan))
return;
for (x=0;x<5;x++) {
y = ADSI_KEY_APPS + 12 + start + x;
if (y > ADSI_KEY_APPS + 12 + 4)
y = 0;
keys[x] = ADSI_KEY_SKT | y;
}
keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
bytes += adsi_set_keys(buf + bytes, keys);
adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
}
static void adsi_message(struct ast_channel *chan, char *folder, int msg, int last, int deleted, char *fn)
{
int bytes=0;
char buf[256], buf1[256], buf2[256];
char fn2[256];
char cid[256]="";
char *val;
char *name, *num;
char datetime[21]="";
FILE *f;
unsigned char keys[6];
int x;
if (!adsi_available(chan))
return;
/* Retrieve important info */
snprintf(fn2, sizeof(fn2), "%s.txt", fn);
f = fopen(fn2, "r");
if (f) {
while(!feof(f)) {
fgets(buf, sizeof(buf), f);
if (!feof(f)) {
strtok(buf, "=");
val = strtok(NULL, "=");
if (val && strlen(val)) {
if (!strcmp(buf, "callerid"))
strncpy(cid, val, sizeof(cid) - 1);
if (!strcmp(buf, "origdate"))
strncpy(datetime, val, sizeof(datetime) - 1);
}
}
}
fclose(f);
}
/* New meaning for keys */
for (x=0;x<5;x++)
keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
if (!msg) {
/* No prev key, provide "Folder" instead */
keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
}
if (msg >= last) {
/* If last message ... */
if (msg) {
/* but not only message, provide "Folder" instead */
keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
} else {
/* Otherwise if only message, leave blank */
keys[3] = 1;
}
}
if (strlen(cid)) {
ast_callerid_parse(cid, &name, &num);
if (!name)
name = num;
} else
name = "Unknown Caller";
/* If deleted, show "undeleted" */
if (deleted)
keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
/* Except "Exit" */
keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
snprintf(buf1, sizeof(buf1), "%s%s", folder,
strcasecmp(folder, "INBOX") ? " Messages" : "");
snprintf(buf2, sizeof(buf2), "Message %d of %d", msg + 1, last + 1);
bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
bytes += adsi_set_keys(buf + bytes, keys);
adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
}
static void adsi_delete(struct ast_channel *chan, int msg, int last, int deleted)
{
int bytes=0;
char buf[256];
unsigned char keys[6];
int x;
if (!adsi_available(chan))
return;
/* New meaning for keys */
for (x=0;x<5;x++)
keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
if (!msg) {
/* No prev key, provide "Folder" instead */
keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
}
if (msg >= last) {
/* If last message ... */
if (msg) {
/* but not only message, provide "Folder" instead */
keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
} else {
/* Otherwise if only message, leave blank */
keys[3] = 1;
}
}
/* If deleted, show "undeleted" */
if (deleted)
keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
/* Except "Exit" */
keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
bytes += adsi_set_keys(buf + bytes, keys);
adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
}
static void adsi_status(struct ast_channel *chan, int new, int old, int lastmsg)
{
char buf[256], buf1[256], buf2[256];
int bytes=0;
unsigned char keys[6];
int x;
char *newm = (new == 1) ? "message" : "messages";
char *oldm = (old == 1) ? "message" : "messages";
if (!adsi_available(chan))
return;
if (new) {
snprintf(buf1, sizeof(buf1), "You have %d new", new);
if (old) {
strcat(buf1, " and");
snprintf(buf2, sizeof(buf2), "%d old %s.", old, oldm);
} else {
snprintf(buf2, sizeof(buf2), "%s.", newm);
}
} else if (old) {
snprintf(buf1, sizeof(buf1), "You have %d old", old);
snprintf(buf2, sizeof(buf2), "%s.", oldm);
} else {
strcpy(buf1, "You have no messages.");
strcpy(buf2, " ");
}
bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
for (x=0;x<6;x++)
keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
/* Don't let them listen if there are none */
if (lastmsg < 0)
keys[0] = 1;
bytes += adsi_set_keys(buf + bytes, keys);
adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
}
static void adsi_status2(struct ast_channel *chan, char *folder, int messages)
{
char buf[256], buf1[256], buf2[256];
int bytes=0;
unsigned char keys[6];
int x;
char *mess = (messages == 1) ? "message" : "messages";
if (!adsi_available(chan))
return;
/* Original command keys */
for (x=0;x<6;x++)
keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
if (messages < 1)
keys[0] = 0;
snprintf(buf1, sizeof(buf1), "%s%s has", folder,
strcasecmp(folder, "INBOX") ? " folder" : "");
if (messages)
snprintf(buf2, sizeof(buf2), "%d %s.", messages, mess);
else
strcpy(buf2, "no messages.");
bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
bytes += adsi_set_keys(buf + bytes, keys);
adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
}
static void adsi_clear(struct ast_channel *chan)
{
char buf[256];
int bytes=0;
if (!adsi_available(chan))
return;
bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
}
static void adsi_goodbye(struct ast_channel *chan)
{
char buf[256];
int bytes=0;
if (!adsi_available(chan))
return;
bytes += adsi_logo(buf + bytes);
bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
}
static int get_folder(struct ast_channel *chan, int start)
{
int x;
@ -485,7 +991,7 @@ static int get_folder(struct ast_channel *chan, int start)
if (d)
return d;
for (x = start; x< 5; x++) {
if ((d = ast_say_number(chan, x, chan->language)))
if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language)))
return d;
d = play_and_wait(chan, "vm-for");
if (d)
@ -539,13 +1045,15 @@ static int get_folder(struct ast_channel *chan, int start)
#define PLAYMSG(a) do { \
starting = 0; \
make_file(fn, sizeof(fn), curdir, a); \
adsi_message(chan, curbox, a, lastmsg, deleted[a], fn); \
if (!a) \
WAITFILE2("vm-first"); \
else if (a == lastmsg) \
WAITFILE2("vm-last"); \
WAITFILE2("vm-message"); \
if (a && (a != lastmsg)) { \
d = ast_say_number(chan, a + 1, chan->language); \
d = ast_say_number(chan, a + 1, AST_DIGIT_ANY, chan->language); \
if (d < 0) goto out; \
if (d) goto cmd; \
} \
@ -593,6 +1101,7 @@ static int get_folder(struct ast_channel *chan, int start)
snprintf(vmbox, sizeof(vmbox), "vm-%s", curbox); \
} while (0)
static int vm_execmain(struct ast_channel *chan, void *data)
{
/* XXX This is, admittedly, some pretty horrendus code. For some
@ -621,6 +1130,7 @@ static int vm_execmain(struct ast_channel *chan, void *data)
int lastmsg = 0;
int starting = 1;
int box;
int useadsi = 0;
struct ast_config *cfg;
LOCAL_USER_ADD(u);
@ -631,6 +1141,11 @@ static int vm_execmain(struct ast_channel *chan, void *data)
}
if (chan->state != AST_STATE_UP)
ast_answer(chan);
/* If ADSI is supported, setup login screen */
adsi_begin(chan, &useadsi);
if (useadsi)
adsi_login(chan);
if (ast_streamfile(chan, "vm-login", chan->language)) {
ast_log(LOG_WARNING, "Couldn't stream login file\n");
goto out;
@ -650,6 +1165,8 @@ static int vm_execmain(struct ast_channel *chan, void *data)
res = 0;
goto out;
}
if (useadsi)
adsi_password(chan);
if (ast_streamfile(chan, "vm-password", chan->language)) {
ast_log(LOG_WARNING, "Unable to stream password file\n");
goto out;
@ -670,10 +1187,14 @@ static int vm_execmain(struct ast_channel *chan, void *data)
} else if (option_verbose > 2)
ast_verbose( VERBOSE_PREFIX_3 "No such user '%s' in config file\n", username);
if (!valid) {
if (useadsi)
adsi_login(chan);
if (ast_streamfile(chan, "vm-incorrect", chan->language))
break;
#if 0
if (ast_waitstream(chan, ""))
break;
#endif
}
} while (!valid);
@ -684,17 +1205,29 @@ static int vm_execmain(struct ast_channel *chan, void *data)
OPEN_MAILBOX(0);
newmessages = lastmsg + 1;
/* Select proper mailbox FIRST!! */
if (!newmessages && oldmessages) {
/* If we only have old messages start here */
OPEN_MAILBOX(1);
}
if (useadsi)
adsi_status(chan, newmessages, oldmessages, lastmsg);
WAITCMD(play_and_wait(chan, "vm-youhave"));
if (newmessages) {
WAITCMD(say_and_wait(chan, newmessages));
WAITCMD(play_and_wait(chan, "vm-INBOX"));
if (newmessages == 1)
WAITCMD(play_and_wait(chan, "vm-message"));
else
WAITCMD(play_and_wait(chan, "vm-messages"));
if (oldmessages)
WAITCMD(play_and_wait(chan, "vm-and"));
else {
if (newmessages == 1)
WAITCMD(play_and_wait(chan, "vm-message"));
else
WAITCMD(play_and_wait(chan, "vm-messages"));
}
}
if (oldmessages) {
WAITCMD(say_and_wait(chan, oldmessages));
@ -708,10 +1241,6 @@ static int vm_execmain(struct ast_channel *chan, void *data)
WAITCMD(play_and_wait(chan, "vm-no"));
WAITCMD(play_and_wait(chan, "vm-messages"));
}
if (!newmessages && oldmessages) {
/* If we only have old messages start here */
OPEN_MAILBOX(1);
}
repeats = 0;
starting = 1;
instructions:
@ -750,6 +1279,8 @@ instructions:
cmd:
switch(d) {
case '2':
if (useadsi)
adsi_folders(chan, 0, "Change to folder...");
box = play_and_wait(chan, "vm-changeto");
if (box < 0)
goto out;
@ -763,6 +1294,8 @@ cmd:
box = box - '0';
CLOSE_MAILBOX;
OPEN_MAILBOX(box);
if (useadsi)
adsi_status2(chan, curbox, lastmsg + 1);
WAITCMD(play_and_wait(chan, vmbox));
WAITCMD(play_and_wait(chan, "vm-messages"));
starting = 1;
@ -799,12 +1332,16 @@ cmd:
}
case '7':
deleted[curmsg] = !deleted[curmsg];
if (useadsi)
adsi_delete(chan, curmsg, lastmsg, deleted[curmsg]);
if (deleted[curmsg])
WAITCMD(play_and_wait(chan, "vm-deleted"));
else
WAITCMD(play_and_wait(chan, "vm-undeleted"));
goto instructions;
case '9':
if (useadsi)
adsi_folders(chan, 1, "Save to folder...");
box = play_and_wait(chan, "vm-savefolder");
if (box < 0)
goto out;
@ -816,10 +1353,14 @@ cmd:
goto instructions;
}
box = box - '0';
ast_log(LOG_DEBUG, "Save to folder: %s (%d)\n", mbox(box), box);
if (option_debug)
ast_log(LOG_DEBUG, "Save to folder: %s (%d)\n", mbox(box), box);
if (save_to_folder(curdir, curmsg, username, box))
goto out;
deleted[curmsg]=1;
make_file(fn, sizeof(fn), curdir, curmsg);
if (useadsi)
adsi_message(chan, curbox, curmsg, lastmsg, deleted[curmsg], fn);
WAITCMD(play_and_wait(chan, "vm-message"));
WAITCMD(say_and_wait(chan, curmsg + 1) );
WAITCMD(play_and_wait(chan, "vm-savedto"));
@ -836,24 +1377,32 @@ cmd:
}
goto instructions;
case '#':
ast_stopstream(chan);
adsi_goodbye(chan);
play_and_wait(chan, "vm-goodbye");
goto out;
res = 0;
goto out2;
default:
goto instructions;
}
}
out:
adsi_goodbye(chan);
out2:
CLOSE_MAILBOX;
ast_stopstream(chan);
if (cfg)
ast_destroy(cfg);
if (useadsi)
adsi_unload_session(chan);
adsi_channel_init(chan);
LOCAL_USER_REMOVE(u);
return res;
}
static int vm_exec(struct ast_channel *chan, void *data)
{
int res=0, silent=0;
int res=0, silent=0, busy=0, unavail=0;
struct localuser *u;
char *ext = (char *)data;
@ -865,10 +1414,16 @@ static int vm_exec(struct ast_channel *chan, void *data)
if (*ext == 's') {
silent++;
ext++;
} else if (*ext == 'b') {
busy++;
ext++;
} else if (*ext == 'u') {
unavail++;
ext++;
}
if (chan->state != AST_STATE_UP)
ast_answer(chan);
res = leave_voicemail(chan, ext, silent);
res = leave_voicemail(chan, ext, silent, busy, unavail);
LOCAL_USER_REMOVE(u);
return res;
}

View File

@ -37,6 +37,9 @@ writeprotect=no
exten => _91NXXNXXXXXX,1,StripMSD,1
exten => _1NXXNXXXXXX,2,Dial,IAX/iaxtel.com/BYEXTENSION@iaxtel
[provider]
;switch => IAX/user:[key]@myserver/mycontext
; Local stuff
[local]
; Special extension for local phone numbers, long distance, etc, going
@ -52,10 +55,11 @@ exten => _1NXXNXXXXXX,2,Dial,IAX/iaxtel.com/BYEXTENSION@iaxtel
; so that dialtone remains even after dialing a 9.
;
ignorepat => 9
;exten => _9NXXXXXX,1,Dial,AdtranVoFR/BYEXTENSION
;exten => _91NXXNXXXXXX,1,Dial,AdtranVoFR/BYEXTENSION
;exten => _9911,1,Dial,AdtranVoFR/BYEXTENSION
;exten => _9NXXXXXX,1,Dial,IAX/user:[key]@myserver/BYEXTENSION
;exten => _91NXXNXXXXXX,1,Dial,IAX/user:[key]@myserver/BYEXTENSION
;exten => _9911,1,Dial,IAX/user:[key]@myserver/BYEXTENSION
include => default
include => provider
include => iaxtel
;
; You can use an alternative switch type as well, to resolve
@ -65,7 +69,7 @@ include => iaxtel
; switch => IAX/user:password@bigserver/local
[default]
[demo]
;
; We start with what to do when a call first comes in.
;
@ -89,11 +93,10 @@ exten => 3,2,Goto,s|5 ; Start with the congratulations
exten => 1234,1,Playback,transfer|skip ; "Please hold while..."
; (but skip if channel is not up)
exten => 1234,2,Dial,Console/dsp|10 ; Ring the console, 10 secs max
exten => 1234,3,Playback,vm/1234/unavail ; "I'm not here right now"
exten => 1234,4,Voicemail,1234 ; Send to voicemail...
exten => 1234,3,Voicemail,u1234 ; Send to voicemail...
exten => 1234,5,Goto,s|6 ; Start over
exten => 1234,103,Playback,vm/1234/busy ; (2 + 101) "I'm on the phone"
exten => 1234,104,Goto,4 ; Go to voicemail, etc.
exten => 1234,103,Voicemail,b1234 ; (2 + 101) "I'm on the phone"
exten => 1234,104,Goto,5 ; Go to voicemail, etc.
exten => 1235,1,Goto,1234|3 ; Right to voicemail
@ -140,8 +143,15 @@ exten => 8500,2,Goto,s|6
;exten => 1265,1,Dial,Phone/phone0|15
;exten => 1265,2,Goto,s|5
[default]
;
; By default we include the demo. In a production system, you
; probably don't want to have the demo there.
;
include => demo
; This is a more complicated sample extension configuration, similar to
; what we use at LSS.
; what we used to use at LSS.
;[default]
;exten => s,1,Wait,0
@ -171,17 +181,14 @@ exten => 8500,2,Goto,s|6
; Step 2: Dial the numbers where Ben is likely to be. Try for no more
; than 15 seconds.
;exten => 4300,2,Dial,AdtranVoFR/4300|15
; Step 3: If there is no answer, play back a message stating that Ben is
; unavailable. Alternatively, we could have rung an operator first.
;exten => 4300,3,Playback,vm/4300/unavail
; Step 4: Send them to voicemail.
;exten => 4300,4,Voicemail,4300
; Step 5: If they return from voicemail, go back to the top
;exten => 4300,5,Goto,s|4
; Step 3: Send them to voicemail, preceeded by their unavailable message.
;exten => 4300,3,Voicemail,u4300
; Step 4: If they return from voicemail, go back to the top
;exten => 4300,4,Goto,s|4
; Step 103: If the Dialing is busy, it will try here first. We'll play a
; special "I'm busy" message...
;exten => 4300,103,Playback,vm/4300/busy
; Step 104: And then continue as if it had been busy in the first place.
; special "I'm busy" message and send them to voicemail
;exten => 4300,103,Voicemail,b4300
; Step 104: And then continue from whereever the other would
;exten => 4300,104,Goto,4
; Exten. 4301: Provide a short-circuit so we can transfer striaght to
; voicemail.

View File

@ -24,14 +24,18 @@ extern "C" {
#endif
/* Convenient for waiting */
//! Convenient for waiting
#define AST_DIGIT_ANY "0123456789#*"
/* Defined by individual formats. First item MUST be a
pointer for use by the stream manager */
struct ast_filestream;
/* Register a new file format capability */
//! Registers a new file format
/*! Register a new file format capability
* Adds a format to asterisk's format abilities. Fill in the fields, and it will work. For examples, look at some of the various format code.
* returns 0 on success, -1 on failure
*/
int ast_format_register(char *name, char *exts, int format,
struct ast_filestream * (*open)(int fd),
struct ast_filestream * (*rewrite)(int fd, char *comment),
@ -41,40 +45,111 @@ int ast_format_register(char *name, char *exts, int format,
void (*close)(struct ast_filestream *),
char * (*getcomment)(struct ast_filestream *));
//! Unregisters a file format
/*!
* \param name the name of the format you wish to unregister
* Unregisters a format based on the name of the format.
* Returns 0 on success, -1 on failure to unregister
*/
int ast_format_unregister(char *name);
/* Start streaming a file, in the preferred language if possible */
//! Streams a file
/*!
* \param c channel to stream the file to
* \param filename the name of the file you wish to stream, minus the extension
* \param preflang the preferred language you wish to have the file streamed to you in
* Prepares a channel for the streaming of a file. To start the stream, afterward do a ast_waitstream() on the channel
* Also, it will stop any existing streams on the channel.
* Returns 0 on success, or -1 on failure.
*/
int ast_streamfile(struct ast_channel *c, char *filename, char *preflang);
/* Stop playback of a stream */
//! Stops a stream
/*!
* \param c The channel you wish to stop playback on
* Stop playback of a stream
* Returns 0 regardless
*/
int ast_stopstream(struct ast_channel *c);
/* See if a given file exists in a given format. If fmt is NULL, any format is accepted.*/
/* Returns -1 if file does not exist */
//! Checks for the existence of a given file
/*!
* \param filename name of the file you wish to check, minus the extension
* \param fmt the format you wish to check (the extension)
* \param preflang (the preferred language you wisht to find the file in)
* See if a given file exists in a given format. If fmt is NULL, any format is accepted.
* Returns -1 if file does not exist, non-zero positive otherwise.
*/
int ast_fileexists(char *filename, char *fmt, char *preflang);
/* Rename a given file in a given format, or if fmt is NULL, then do so for all */
//! Renames a file
/*!
* \param oldname the name of the file you wish to act upon (minus the extension)
* \param newname the name you wish to rename the file to (minus the extension)
* \param fmt the format of the file
* Rename a given file in a given format, or if fmt is NULL, then do so for all
* Returns -1 on failure
*/
int ast_filerename(char *oldname, char *newname, char *fmt);
/* Delete a given file in a given format, or if fmt is NULL, then do so for all */
//! Deletes a file
/*!
* \param filename name of the file you wish to delete (minus the extension)
* \param format of the file
* Delete a given file in a given format, or if fmt is NULL, then do so for all
*/
int ast_filedelete(char *filename, char *fmt);
/* Copy a given file in a given format, or if fmt is NULL, then do so for all */
//! Copies a file
/*!
* \param oldname name of the file you wish to copy (minus extension)
* \param newname name you wish the file to be copied to (minus extension)
* \param fmt the format of the file
* Copy a given file in a given format, or if fmt is NULL, then do so for all
*/
int ast_filecopy(char *oldname, char *newname, char *fmt);
/* Wait for a stream to stop or for any one of a given digit to arrive, Returns
0 if the stream finishes, the character if it was interrupted, and -1 on error */
//! Waits for a stream to stop or digit to be pressed
/*!
* \param c channel to waitstram on
* \param breakon string of DTMF digits to break upon
* Begins playback of a stream...
* Wait for a stream to stop or for any one of a given digit to arrive, Returns 0
* if the stream finishes, the character if it was interrupted, and -1 on error
*/
char ast_waitstream(struct ast_channel *c, char *breakon);
/* Create an outgoing file stream. oflags are flags for the open() command, and
if check is non-zero, then it will not write a file if there are any files that
start with that name and have an extension */
//! Starts writing a file
/*!
* \param filename the name of the file to write to
* \param type format of file you wish to write out to
* \param comment comment to go with
* \param oflags output file flags
* \param check (unimplemented, hence negligible)
* \param mode Open mode
* Create an outgoing file stream. oflags are flags for the open() command, and
* if check is non-zero, then it will not write a file if there are any files that
* start with that name and have an extension
* Please note, this is a blocking function. Program execution will not return until ast_waitstream completes it's execution.
* Returns a struct ast_filestream on success, NULL on failure
*/
struct ast_filestream *ast_writefile(char *filename, char *type, char *comment, int oflags, int check, mode_t mode);
/* Send a frame to a filestream -- note: does NOT free the frame, call ast_frfree manually */
//! Writes a frame to a stream
/*!
* \param fs filestream to write to
* \param f frame to write to the filestream
* Send a frame to a filestream -- note: does NOT free the frame, call ast_frfree manually
* Returns 0 on success, -1 on failure.
*/
int ast_writestream(struct ast_filestream *fs, struct ast_frame *f);
/* Close a playback or recording stream */
//! Closes a stream
/*!
* \param f filestream to close
* Close a playback or recording stream
* Returns 0 on success, -1 on failure
*/
int ast_closestream(struct ast_filestream *f);
#define AST_RESERVED_POINTERS 4

View File

@ -21,9 +21,38 @@
extern "C" {
#endif
int ast_say_number(struct ast_channel *chan, int num, char *lang);
int ast_say_digits(struct ast_channel *chan, int num, char *lang);
int ast_say_digit_str(struct ast_channel *chan, char *num, char *lang);
//! says a number
/*!
* \param chan channel to say them number on
* \param num number to say on the channel
* \param ints which dtmf to interrupt on
* \param lang language to speak the number
* Vocally says a number on a given channel
* Returns 0 on success, DTMF digit on interrupt, -1 on failure
*/
int ast_say_number(struct ast_channel *chan, int num, char *ints, char *lang);
//! says digits
/*!
* \param chan channel to act upon
* \param num number to speak
* \param ints which dtmf to interrupt on
* \param lang language to speak
* Vocally says digits of a given number
* Returns 0 on success, dtmf if interrupted, -1 on failure
*/
int ast_say_digits(struct ast_channel *chan, int num, char *ints, char *lang);
//! says digits of a string
/*!
* \param chan channel to act upon
* \param num string to speak
* \param ints which dtmf to interrupt on
* \param lang language to speak in
* Vocally says the digits of a given string
* Returns 0 on success, dtmf if interrupted, -1 on failure
*/
int ast_say_digit_str(struct ast_channel *chan, char *num, char *ints, char *lang);
#if defined(__cplusplus) || defined(c_plusplus)
}

498
res/res_parking.c Executable file
View File

@ -0,0 +1,498 @@
/*
* Asterisk -- A telephony toolkit for Linux.
*
* Routines implementing call parking
*
* Copyright (C) 1999, Mark Spencer
*
* Mark Spencer <markster@linux-support.net>
*
* This program is free software, distributed under the terms of
* the GNU General Public License
*/
#include <asterisk/file.h>
#include <asterisk/logger.h>
#include <asterisk/channel.h>
#include <asterisk/pbx.h>
#include <asterisk/options.h>
#include <asterisk/module.h>
#include <asterisk/translate.h>
#include <asterisk/say.h>
#include <asterisk/channel_pvt.h>
#include <asterisk/parking.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <netinet/in.h>
#include <pthread.h>
static char *parkedcall = "ParkedCall";
/* No more than 45 seconds parked before you do something with them */
static int parkingtime = 45000;
/* Context for which parking is made accessible */
static char parking_con[AST_MAX_EXTENSION] = "parkedcalls";
/* Extension you type to park the call */
static char parking_ext[AST_MAX_EXTENSION] = "700";
/* First available extension for parking */
static int parking_start = 701;
/* Last available extension for parking */
static int parking_stop = 750;
/* Registrar for operations */
static char *registrar = "res_parking";
static char *synopsis = "Answer a parked call";
static char *descrip = "ParkedCall(exten):"
"Used to connect to a parked call. This Application is always\n"
"registered internally and does not need to be explicitly added\n"
"into the dialplan, although you should include the 'parkedcalls'\n"
"context.\n";
struct parkeduser {
struct ast_channel *chan;
struct timeval start;
int parkingnum;
/* Where to go if our parking time expires */
char context[AST_MAX_EXTENSION];
char exten[AST_MAX_EXTENSION];
int priority;
struct parkeduser *next;
};
static struct parkeduser *parkinglot;
static pthread_mutex_t parking_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_t parking_thread;
STANDARD_LOCAL_USER;
LOCAL_USER_DECL;
char *ast_parking_ext(void)
{
return parking_ext;
}
int ast_park_call(struct ast_channel *chan, struct ast_channel *peer)
{
/* We put the user in the parking list, then wake up the parking thread to be sure it looks
after these channels too */
struct parkeduser *pu, *cur;
int x;
pu = malloc(sizeof(struct parkeduser));
if (pu) {
ast_pthread_mutex_lock(&parking_lock);
for (x=parking_start;x<=parking_stop;x++) {
cur = parkinglot;
while(cur) {
if (cur->parkingnum == x)
break;
cur = cur->next;
}
if (!cur)
break;
}
if (x <= parking_stop) {
pu->chan = chan;
gettimeofday(&pu->start, NULL);
pu->parkingnum = x;
/* Remember what had been dialed, so that if the parking
expires, we try to come back to the same place */
strncpy(pu->context, chan->context, sizeof(pu->context)-1);
strncpy(pu->exten, chan->exten, sizeof(pu->exten)-1);
pu->priority = chan->priority;
pu->next = parkinglot;
parkinglot = pu;
ast_pthread_mutex_unlock(&parking_lock);
/* Wake up the (presumably select()ing) thread */
pthread_kill(parking_thread, SIGURG);
if (option_verbose > 1)
ast_verbose(VERBOSE_PREFIX_2 "Parked %s on %d\n", pu->chan->name, pu->parkingnum);
ast_say_digits(peer, pu->parkingnum, "", peer->language);
return 0;
} else {
ast_log(LOG_WARNING, "No more parking spaces\n");
free(pu);
ast_pthread_mutex_unlock(&parking_lock);
return -1;
}
} else {
ast_log(LOG_WARNING, "Out of memory\n");
return -1;
}
return 0;
}
int ast_masq_park_call(struct ast_channel *rchan, struct ast_channel *peer)
{
struct ast_channel *chan;
struct ast_frame *f;
/* Make a new, fake channel that we'll use to masquerade in the real one */
chan = ast_channel_alloc();
if (chan) {
/* Let us keep track of the channel name */
snprintf(chan->name, sizeof (chan->name), "Parked/%s",rchan->name);
/* Make formats okay */
chan->readformat = rchan->readformat;
chan->writeformat = rchan->writeformat;
ast_channel_masquerade(chan, rchan);
/* Setup the extensions and such */
strncpy(chan->context, rchan->context, sizeof(chan->context) - 1);
strncpy(chan->exten, rchan->exten, sizeof(chan->exten) - 1);
chan->priority = rchan->priority;
/* Make the masq execute */
f = ast_read(chan);
if (f)
ast_frfree(f);
ast_park_call(chan, peer);
} else {
ast_log(LOG_WARNING, "Unable to create parked channel\n");
return -1;
}
return 0;
}
int ast_bridge_call(struct ast_channel *chan, struct ast_channel *peer, int allowredirect)
{
/* Copy voice back and forth between the two channels. Give the peer
the ability to transfer calls with '#<extension' syntax. */
int len;
struct ast_frame *f;
struct ast_channel *who;
char newext[256], *ptr;
int res;
struct ast_option_header *aoh;
/* Answer if need be */
if (chan->state != AST_STATE_UP) {
if (ast_answer(chan))
return -1;
}
peer->appl = "Bridged Call";
peer->data = chan->name;
for (;;) {
res = ast_channel_bridge(chan, peer, allowredirect ? AST_BRIDGE_DTMF_CHANNEL_1 : 0, &f, &who);
if (res < 0) {
ast_log(LOG_WARNING, "Bridge failed on channels %s and %s\n", chan->name, peer->name);
return -1;
}
if (!f || ((f->frametype == AST_FRAME_CONTROL) && ((f->subclass == AST_CONTROL_HANGUP) || (f->subclass == AST_CONTROL_BUSY) ||
(f->subclass == AST_CONTROL_CONGESTION)))) {
res = -1;
break;
}
if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_RINGING)) {
if (who == chan)
ast_indicate(peer, AST_CONTROL_RINGING);
else
ast_indicate(chan, AST_CONTROL_RINGING);
}
if ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_OPTION)) {
aoh = f->data;
/* Forward option Requests */
if (aoh && (aoh->flag == AST_OPTION_FLAG_REQUEST)) {
if (who == chan)
ast_channel_setoption(peer, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
else
ast_channel_setoption(chan, ntohs(aoh->option), aoh->data, f->datalen - sizeof(struct ast_option_header), 0);
}
}
if ((f->frametype == AST_FRAME_DTMF) && (who == peer) && allowredirect &&
(f->subclass == '#')) {
memset(newext, 0, sizeof(newext));
ptr = newext;
/* Transfer */
if ((res=ast_streamfile(peer, "pbx-transfer", chan->language)))
break;
if ((res=ast_waitstream(peer, AST_DIGIT_ANY)) < 0)
break;
ast_stopstream(peer);
if (res > 0) {
/* If they've typed a digit already, handle it */
newext[0] = res;
ptr++;
len --;
}
res = 0;
while(strlen(newext) < sizeof(newext - 1)) {
res = ast_waitfordigit(peer, 3000);
if (res < 1)
break;
*(ptr++) = res;
if (!ast_canmatch_extension(peer, peer->context, newext, 1, peer->callerid) ||
ast_exists_extension(peer, peer->context, newext, 1, peer->callerid)) {
res = 0;
break;
}
}
if (res)
break;
if (!strcmp(newext, ast_parking_ext())) {
if (!ast_park_call(chan, peer)) {
/* We return non-zero, but tell the PBX not to hang the channel when
the thread dies -- We have to be careful now though. We are responsible for
hanging up the channel, else it will never be hung up! */
res=AST_PBX_KEEPALIVE;
break;
} else {
ast_log(LOG_WARNING, "Unable to park call %s\n", chan->name);
}
/* XXX Maybe we should have another message here instead of invalid extension XXX */
} else if (ast_exists_extension(chan, peer->context, newext, 1, peer->callerid)) {
/* Set the channel's new extension, since it exists, using peer context */
strncpy(chan->exten, newext, sizeof(chan->exten)-1);
strncpy(chan->context, peer->context, sizeof(chan->context)-1);
chan->priority = 0;
ast_frfree(f);
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Transferring %s to '%s' (context %s) priority 1\n", chan->name, chan->exten, chan->context);
res=0;
break;
} else {
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Unable to find extension '%s' in context %s\n", newext, peer->context);
}
res = ast_streamfile(peer, "pbx-invalid", chan->language);
if (res)
break;
res = ast_waitstream(peer, AST_DIGIT_ANY);
ast_stopstream(peer);
res = 0;
} else {
if (f && (f->frametype == AST_FRAME_DTMF)) {
if (who == peer)
ast_write(chan, f);
else
ast_write(peer, f);
}
#if 1
ast_log(LOG_DEBUG, "Read from %s (%d,%d)\n", who->name, f->frametype, f->subclass);
#endif
}
if (f)
ast_frfree(f);
}
return res;
}
static void *do_parking_thread(void *ignore)
{
int ms, tms, max;
struct parkeduser *pu, *pl, *pt = NULL;
struct timeval tv;
struct ast_frame *f;
int x;
fd_set rfds, efds;
fd_set nrfds, nefds;
FD_ZERO(&rfds);
FD_ZERO(&efds);
for (;;) {
ms = -1;
max = -1;
ast_pthread_mutex_lock(&parking_lock);
pl = NULL;
pu = parkinglot;
gettimeofday(&tv, NULL);
FD_ZERO(&nrfds);
FD_ZERO(&nefds);
while(pu) {
tms = (tv.tv_sec - pu->start.tv_sec) * 1000 + (tv.tv_usec - pu->start.tv_usec) / 1000;
if (tms > parkingtime) {
/* They've been waiting too long, send them back to where they came. Theoretically they
should have their original extensions and such, but we copy to be on the safe side */
strncpy(pu->chan->exten, pu->exten, sizeof(pu->chan->exten)-1);
strncpy(pu->chan->context, pu->context, sizeof(pu->chan->context)-1);
pu->chan->priority = pu->priority;
/* Start up the PBX, or hang them up */
if (ast_pbx_start(pu->chan)) {
ast_log(LOG_WARNING, "Unable to restart the PBX for user on '%s', hanging them up...\n", pu->chan->name);
ast_hangup(pu->chan);
}
/* And take them out of the parking lot */
if (pl)
pl->next = pu->next;
else
parkinglot = pu->next;
pt = pu;
pu = pu->next;
free(pt);
} else {
for (x=0;x<AST_MAX_FDS;x++) {
if ((pu->chan->fds[x] > -1) && (FD_ISSET(pu->chan->fds[x], &rfds) || FD_ISSET(pu->chan->fds[x], &efds))) {
if (FD_ISSET(pu->chan->fds[x], &efds))
pu->chan->exception = 1;
pu->chan->fdno = x;
/* See if they need servicing */
f = ast_read(pu->chan);
if (!f || ((f->frametype == AST_FRAME_CONTROL) && (f->subclass == AST_CONTROL_HANGUP))) {
/* There's a problem, hang them up*/
if (option_verbose > 1)
ast_verbose(VERBOSE_PREFIX_2 "%s got tired of being parked\n", pu->chan->name);
ast_hangup(pu->chan);
/* And take them out of the parking lot */
if (pl)
pl->next = pu->next;
else
parkinglot = pu->next;
pt = pu;
pu = pu->next;
free(pt);
break;
} else {
/* XXX Maybe we could do something with packets, like dial "0" for operator or something XXX */
ast_frfree(f);
goto std; /* XXX Ick: jumping into an else statement??? XXX */
}
}
}
if (x >= AST_MAX_FDS) {
std: for (x=0;x<AST_MAX_FDS;x++) {
/* Keep this one for next one */
if (pu->chan->fds[x] > -1) {
FD_SET(pu->chan->fds[x], &nrfds);
FD_SET(pu->chan->fds[x], &nefds);
if (pu->chan->fds[x] > max)
max = pu->chan->fds[x];
}
}
/* Keep track of our longest wait */
if ((tms < ms) || (ms < 0))
ms = tms;
pl = pu;
pu = pu->next;
}
}
}
ast_pthread_mutex_unlock(&parking_lock);
rfds = nrfds;
efds = nefds;
tv.tv_sec = ms / 1000;
tv.tv_usec = (ms % 1000) * 1000;
/* Wait for something to happen */
select(max + 1, &rfds, NULL, &efds, (ms > -1) ? &tv : NULL);
pthread_testcancel();
}
return NULL; /* Never reached */
}
static int park_exec(struct ast_channel *chan, void *data)
{
int res=0;
struct localuser *u;
struct ast_channel *peer=NULL;
struct parkeduser *pu, *pl=NULL;
int park;
if (!data) {
ast_log(LOG_WARNING, "Park requires an argument (extension number)\n");
return -1;
}
LOCAL_USER_ADD(u);
park = atoi((char *)data);
ast_pthread_mutex_lock(&parking_lock);
pu = parkinglot;
while(pu) {
if (pu->parkingnum == park) {
if (pl)
pl->next = pu->next;
else
parkinglot = pu->next;
break;
}
pu = pu->next;
}
ast_pthread_mutex_unlock(&parking_lock);
if (pu) {
peer = pu->chan;
free(pu);
}
if (peer) {
res = ast_channel_make_compatible(chan, peer);
if (res < 0) {
ast_log(LOG_WARNING, "Could not make channels %s and %s compatible for bridge\n", chan->name, peer->name);
ast_hangup(peer);
return -1;
}
/* This runs sorta backwards, since we give the incoming channel control, as if it
were the person called. */
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Channel %s connected to parked call %d\n", chan->name, park);
res = ast_bridge_call(peer, chan, 1);
/* Simulate the PBX hanging up */
if (res != AST_PBX_KEEPALIVE)
ast_hangup(peer);
return -1;
} else {
/* XXX Play a message XXX */
if (option_verbose > 2)
ast_verbose(VERBOSE_PREFIX_3 "Channel %s tried to talk to non-existant parked call %d\n", chan->name, park);
res = -1;
}
LOCAL_USER_REMOVE(u);
return res;
}
int load_module(void)
{
int res;
int x;
struct ast_context *con;
char exten[AST_MAX_EXTENSION];
con = ast_context_find(parking_con);
if (!con) {
con = ast_context_create(parking_con, registrar);
if (!con) {
ast_log(LOG_ERROR, "Parking context '%s' does not exist and unable to create\n", parking_con);
return -1;
}
}
for(x=parking_start; x<=parking_stop;x++) {
snprintf(exten, sizeof(exten), "%d", x);
ast_add_extension2(con, 1, exten, 1, NULL, parkedcall, strdup(exten), free, registrar);
}
pthread_create(&parking_thread, NULL, do_parking_thread, NULL);
res = ast_register_application(parkedcall, park_exec, synopsis, descrip);
return res;
}
int unload_module(void)
{
STANDARD_HANGUP_LOCALUSERS;
return ast_unregister_application(parkedcall);
}
char *description(void)
{
return "Call Parking Resource";
}
int usecount(void)
{
/* Never allow parking to be unloaded because it will
unresolve needed symbols in the dialer */
#if 0
int res;
STANDARD_USECOUNT(res);
return res;
#else
return 1;
#endif
}
char *key()
{
return ASTERISK_GPL_KEY;
}

22
say.c
View File

@ -17,7 +17,7 @@
#include <asterisk/say.h>
#include <stdio.h>
int ast_say_digit_str(struct ast_channel *chan, char *fn2, char *lang)
int ast_say_digit_str(struct ast_channel *chan, char *fn2, char *ints, char *lang)
{
char fn[256] = "";
int num = 0;
@ -26,26 +26,26 @@ int ast_say_digit_str(struct ast_channel *chan, char *fn2, char *lang)
snprintf(fn, sizeof(fn), "digits/%c", fn2[num]);
res = ast_streamfile(chan, fn, lang);
if (!res)
res = ast_waitstream(chan, AST_DIGIT_ANY);
res = ast_waitstream(chan, ints);
ast_stopstream(chan);
num++;
}
return res;
}
int ast_say_digits(struct ast_channel *chan, int num, char *lang)
int ast_say_digits(struct ast_channel *chan, int num, char *ints, char *lang)
{
char fn2[256];
snprintf(fn2, sizeof(fn2), "%d", num);
return ast_say_digit_str(chan, fn2, lang);
return ast_say_digit_str(chan, fn2, ints, lang);
}
int ast_say_number(struct ast_channel *chan, int num, char *language)
int ast_say_number(struct ast_channel *chan, int num, char *ints, char *language)
{
int res = 0;
int playh = 0;
char fn[256] = "";
if (!num)
return ast_say_digits(chan, 0,language);
return ast_say_digits(chan, 0,ints, language);
if (0) {
/* XXX Only works for english XXX */
} else {
@ -70,12 +70,16 @@ int ast_say_number(struct ast_channel *chan, int num, char *language)
num -= ((num / 100) * 100);
} else {
if (num < 1000000) {
ast_say_number(chan, num / 1000, language);
res = ast_say_number(chan, num / 1000, ints, language);
if (res)
return res;
num = num % 1000;
snprintf(fn, sizeof(fn), "digits/thousand");
} else {
if (num < 1000000000) {
ast_say_number(chan, num / 1000000, language);
res = ast_say_number(chan, num / 1000000, ints, language);
if (res)
return res;
num = num % 1000000;
snprintf(fn, sizeof(fn), "digits/million");
} else {
@ -88,7 +92,7 @@ int ast_say_number(struct ast_channel *chan, int num, char *language)
if (!res) {
res = ast_streamfile(chan, fn, language);
if (!res)
res = ast_waitstream(chan, AST_DIGIT_ANY);
res = ast_waitstream(chan, ints);
ast_stopstream(chan);
}