Version 0.1.2 from FTP
git-svn-id: http://svn.digium.com/svn/asterisk/trunk@152 f38db490-d61c-443f-a65b-d21fe96a405b
This commit is contained in:
parent
2137f5008c
commit
999d3524e2
|
@ -11,7 +11,7 @@
|
|||
# the GNU General Public License
|
||||
#
|
||||
|
||||
APPS=app_dial.so app_playback.so app_voicemail.so app_directory.so app_intercom.so app_mp3.so
|
||||
APPS=app_dial.so app_playback.so app_voicemail.so app_directory.so app_intercom.so app_mp3.so app_system.so app_echo.so
|
||||
|
||||
CFLAGS+=
|
||||
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Echo application -- play back what you hear to evaluate latency
|
||||
*
|
||||
* 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/module.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
|
||||
static char *tdesc = "Simple Echo Application";
|
||||
|
||||
static char *app = "Echo";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int skel_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=-1;
|
||||
struct localuser *u;
|
||||
struct ast_frame *f;
|
||||
LOCAL_USER_ADD(u);
|
||||
/* Do our thing here */
|
||||
while((f = ast_read(chan))) {
|
||||
if (f->frametype == AST_FRAME_VOICE) {
|
||||
if (ast_write(chan, f))
|
||||
break;
|
||||
} else if (f->frametype == AST_FRAME_DTMF) {
|
||||
if (f->subclass == '#') {
|
||||
res = 0;
|
||||
break;
|
||||
} else
|
||||
if (ast_write(chan, f))
|
||||
break;
|
||||
}
|
||||
}
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, skel_exec);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
|
@ -15,6 +15,7 @@
|
|||
#include <asterisk/logger.h>
|
||||
#include <asterisk/channel.h>
|
||||
#include <asterisk/pbx.h>
|
||||
#include <asterisk/module.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
@ -22,63 +23,32 @@
|
|||
|
||||
#include <pthread.h>
|
||||
|
||||
static pthread_mutex_t skellock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
static int usecnt=0;
|
||||
|
||||
static char *tdesc = "Trivial skeleton Application";
|
||||
|
||||
static char *app = "skel";
|
||||
|
||||
struct skeluser {
|
||||
struct ast_channel *chan;
|
||||
struct skeluser *next;
|
||||
} *users = NULL;
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int skel_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
struct skeluser *u, *ul=NULL;
|
||||
struct localuser *u;
|
||||
if (!data) {
|
||||
ast_log(LOG_WARNING, "skel requires an argument (filename)\n");
|
||||
return -1;
|
||||
}
|
||||
if (!(u=malloc(sizeof(struct skeluser)))) {
|
||||
ast_log(LOG_WARNING, "Out of memory\n");
|
||||
return -1;
|
||||
}
|
||||
pthread_mutex_lock(&skellock);
|
||||
u->chan = chan;
|
||||
u->next = users;
|
||||
users = u;
|
||||
usecnt++;
|
||||
pthread_mutex_unlock(&skellock);
|
||||
LOCAL_USER_ADD(u);
|
||||
/* Do our thing here */
|
||||
pthread_mutex_lock(&skellock);
|
||||
u = users;
|
||||
while(u) {
|
||||
if (ul)
|
||||
ul->next = u->next;
|
||||
else
|
||||
users = u->next;
|
||||
u = u->next;
|
||||
}
|
||||
usecnt--;
|
||||
pthread_mutex_unlock(&skellock);
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
struct skeluser *u;
|
||||
pthread_mutex_lock(&skellock);
|
||||
u = users;
|
||||
while(u) {
|
||||
/* Hang up anybody who is using us */
|
||||
ast_softhangup(u->chan);
|
||||
u = u->next;
|
||||
}
|
||||
pthread_mutex_unlock(&skellock);
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
|
@ -95,8 +65,6 @@ char *description(void)
|
|||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
pthread_mutex_lock(&skellock);
|
||||
res = usecnt;
|
||||
pthread_mutex_unlock(&skellock);
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
/*
|
||||
* Asterisk -- A telephony toolkit for Linux.
|
||||
*
|
||||
* Execute arbitrary system commands
|
||||
*
|
||||
* 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/module.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <pthread.h>
|
||||
|
||||
|
||||
static char *tdesc = "Generic System() application";
|
||||
|
||||
static char *app = "System";
|
||||
|
||||
STANDARD_LOCAL_USER;
|
||||
|
||||
LOCAL_USER_DECL;
|
||||
|
||||
static int skel_exec(struct ast_channel *chan, void *data)
|
||||
{
|
||||
int res=0;
|
||||
struct localuser *u;
|
||||
if (!data) {
|
||||
ast_log(LOG_WARNING, "System requires an argument(command)\n");
|
||||
return -1;
|
||||
}
|
||||
LOCAL_USER_ADD(u);
|
||||
/* Do our thing here */
|
||||
res = system((char *)data);
|
||||
if (res < 0) {
|
||||
ast_log(LOG_WARNING, "Unable to execute '%s'\n", data);
|
||||
res = -1;
|
||||
} else if (res == 127) {
|
||||
ast_log(LOG_WARNING, "Unable to execute '%s'\n", data);
|
||||
res = -1;
|
||||
} else {
|
||||
if (res && ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101))
|
||||
chan->priority+=100;
|
||||
res = 0;
|
||||
}
|
||||
LOCAL_USER_REMOVE(u);
|
||||
return res;
|
||||
}
|
||||
|
||||
int unload_module(void)
|
||||
{
|
||||
STANDARD_HANGUP_LOCALUSERS;
|
||||
return ast_unregister_application(app);
|
||||
}
|
||||
|
||||
int load_module(void)
|
||||
{
|
||||
return ast_register_application(app, skel_exec);
|
||||
}
|
||||
|
||||
char *description(void)
|
||||
{
|
||||
return tdesc;
|
||||
}
|
||||
|
||||
int usecount(void)
|
||||
{
|
||||
int res;
|
||||
STANDARD_USECOUNT(res);
|
||||
return res;
|
||||
}
|
|
@ -141,7 +141,7 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent)
|
|||
struct ast_config *cfg;
|
||||
char *copy, *name, *passwd, *email, *dir, *fmt, *fmts, *fn=NULL;
|
||||
char comment[256];
|
||||
struct ast_filestream *writer, *others[MAX_OTHER_FORMATS];
|
||||
struct ast_filestream *writer=NULL, *others[MAX_OTHER_FORMATS];
|
||||
char *sfmt[MAX_OTHER_FORMATS];
|
||||
int res = -1, fmtcnt=0, x;
|
||||
int msgnum;
|
||||
|
@ -182,8 +182,12 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent)
|
|||
snprintf(comment, sizeof(comment), "Voicemail from %s to %s (%s) on %s\n",
|
||||
(chan->callerid ? chan->callerid : "Unknown"),
|
||||
name, ext, chan->name);
|
||||
if (ast_fileexists(fn, NULL) > 0) {
|
||||
msgnum++;
|
||||
continue;
|
||||
}
|
||||
writer = ast_writefile(fn, fmt, comment, O_EXCL, 1 /* check for other formats */, 0700);
|
||||
if (!writer && (errno != EEXIST))
|
||||
if (!writer)
|
||||
break;
|
||||
msgnum++;
|
||||
} while(!writer && (msgnum < MAXMSG));
|
||||
|
@ -221,9 +225,14 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent)
|
|||
if (f->frametype == AST_FRAME_VOICE) {
|
||||
/* Write the primary format */
|
||||
res = ast_writestream(writer, f);
|
||||
if (res) {
|
||||
ast_log(LOG_WARNING, "Error writing primary frame\n");
|
||||
break;
|
||||
}
|
||||
/* And each of the others */
|
||||
for (x=0;x<fmtcnt;x++)
|
||||
for (x=0;x<fmtcnt;x++) {
|
||||
res |= ast_writestream(others[x], f);
|
||||
}
|
||||
ast_frfree(f);
|
||||
/* Exit on any error */
|
||||
if (res) {
|
||||
|
@ -314,20 +323,30 @@ static int vm_execmain(struct ast_channel *chan, void *data)
|
|||
ast_log(LOG_WARNING, "No voicemail configuration\n");
|
||||
goto out;
|
||||
}
|
||||
if (ast_streamfile(chan, "vm-login"))
|
||||
if (ast_streamfile(chan, "vm-login")) {
|
||||
ast_log(LOG_WARNING, "Couldn't stream login file\n");
|
||||
goto out;
|
||||
}
|
||||
do {
|
||||
/* Prompt for, and read in the username */
|
||||
if (ast_readstring(chan, username, sizeof(username), 2000, 5000, "#"))
|
||||
if (ast_readstring(chan, username, sizeof(username), 2000, 5000, "#")) {
|
||||
ast_log(LOG_WARNING, "Couldn't read username\n");
|
||||
goto out;
|
||||
}
|
||||
if (!strlen(username)) {
|
||||
if (option_verbose > 2)
|
||||
ast_verbose(VERBOSE_PREFIX_3 "Username not entered\n");
|
||||
res = 0;
|
||||
goto out;
|
||||
}
|
||||
if (ast_streamfile(chan, "vm-password"))
|
||||
if (ast_streamfile(chan, "vm-password")) {
|
||||
ast_log(LOG_WARNING, "Unable to stream password file\n");
|
||||
goto out;
|
||||
if (ast_readstring(chan, password, sizeof(password), 2000, 5000, "#"))
|
||||
}
|
||||
if (ast_readstring(chan, password, sizeof(password), 2000, 5000, "#")) {
|
||||
ast_log(LOG_WARNING, "Unable to read password\n");
|
||||
goto out;
|
||||
}
|
||||
copy = ast_variable_retrieve(cfg, NULL, username);
|
||||
if (copy) {
|
||||
copy = strdup(copy);
|
||||
|
|
78
asterisk.c
78
asterisk.c
|
@ -28,7 +28,9 @@ int option_verbose=0;
|
|||
int option_debug=0;
|
||||
int option_nofork=0;
|
||||
int option_quiet=0;
|
||||
int option_console=0;
|
||||
int option_highpriority=0;
|
||||
int fully_booted = 0;
|
||||
|
||||
#define HIGH_PRIORITY 1
|
||||
#define HIGH_PRIORITY_SCHED SCHED_RR
|
||||
|
@ -39,6 +41,7 @@ static void urg_handler(int num)
|
|||
system call. We don't actually need to do anything though. */
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "Urgent handler\n");
|
||||
signal(num, urg_handler);
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -89,6 +92,7 @@ static void console_verboser(char *s, int pos, int replace, int complete)
|
|||
if (!pos)
|
||||
fprintf(stdout, "\r");
|
||||
fprintf(stdout, s + pos);
|
||||
fflush(stdout);
|
||||
if (complete)
|
||||
/* Wake up a select()ing console */
|
||||
pthread_kill(consolethread, SIGURG);
|
||||
|
@ -99,8 +103,19 @@ static void consolehandler(char *s)
|
|||
/* Called when readline data is available */
|
||||
if (s && strlen(s))
|
||||
add_history(s);
|
||||
if (s)
|
||||
/* Give the console access to the shell */
|
||||
if (s) {
|
||||
if (s[0] == '!') {
|
||||
if (s[1])
|
||||
system(s+1);
|
||||
else
|
||||
system(getenv("SHELL") ? getenv("SHELL") : "/bin/sh");
|
||||
} else
|
||||
ast_cli_command(STDOUT_FILENO, s);
|
||||
if (!strcasecmp(s, "help"))
|
||||
fprintf(stdout, " !<command> Executes a given shell command\n");
|
||||
} else
|
||||
fprintf(stdout, "\nUse \"quit\" to exit\n");
|
||||
}
|
||||
|
||||
static char quit_help[] =
|
||||
|
@ -138,17 +153,21 @@ int main(int argc, char *argv[])
|
|||
exit(1);
|
||||
}
|
||||
/* Check for options */
|
||||
while((c=getopt(argc, argv, "dvqp")) != EOF) {
|
||||
while((c=getopt(argc, argv, "dvqpc")) != EOF) {
|
||||
switch(c) {
|
||||
case 'd':
|
||||
option_debug++;
|
||||
option_nofork++;
|
||||
break;
|
||||
case 'c':
|
||||
option_console++;
|
||||
option_nofork++;
|
||||
case 'p':
|
||||
option_highpriority++;
|
||||
break;
|
||||
case 'v':
|
||||
option_verbose++;
|
||||
option_nofork++;
|
||||
break;
|
||||
case 'q':
|
||||
option_quiet++;
|
||||
|
@ -157,12 +176,15 @@ int main(int argc, char *argv[])
|
|||
exit(1);
|
||||
}
|
||||
}
|
||||
ast_register_verbose(console_verboser);
|
||||
/* Print a welcome message if desired */
|
||||
if (option_verbose) {
|
||||
if (option_verbose || option_console) {
|
||||
ast_verbose( "Asterisk, Copyright (C) 1999 Mark Spencer\n");
|
||||
ast_verbose( "Written by Mark Spencer <markster@linux-support.net>\n");
|
||||
ast_verbose( "=========================================================================\n");
|
||||
}
|
||||
if (option_console && !option_verbose)
|
||||
ast_verbose("[ Booting...");
|
||||
signal(SIGURG, urg_handler);
|
||||
signal(SIGINT, quit_handler);
|
||||
signal(SIGTERM, quit_handler);
|
||||
|
@ -177,28 +199,34 @@ int main(int argc, char *argv[])
|
|||
exit(1);
|
||||
/* We might have the option of showing a console, but for now just
|
||||
do nothing... */
|
||||
|
||||
/* Console stuff now... */
|
||||
/* Register our quit function */
|
||||
ast_cli_register(&quit);
|
||||
consolethread = pthread_self();
|
||||
ast_register_verbose(console_verboser);
|
||||
if (option_verbose)
|
||||
if (option_console && !option_verbose)
|
||||
ast_verbose(" ]\n");
|
||||
if (option_verbose || option_console)
|
||||
ast_verbose( "Asterisk Ready.\n");
|
||||
if (strlen(filename))
|
||||
read_history(filename);
|
||||
rl_callback_handler_install(ASTERISK_PROMPT, consolehandler);
|
||||
rl_completion_entry_function = (Function *)cli_generator;
|
||||
for(;;) {
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(STDIN_FILENO, &rfds);
|
||||
res = select(STDIN_FILENO + 1, &rfds, NULL, NULL, NULL);
|
||||
if (res > 0) {
|
||||
rl_callback_read_char();
|
||||
} else if (res < 1) {
|
||||
rl_forced_update_display();
|
||||
}
|
||||
|
||||
}
|
||||
fully_booted = 1;
|
||||
if (option_console) {
|
||||
/* Console stuff now... */
|
||||
/* Register our quit function */
|
||||
ast_cli_register(&quit);
|
||||
consolethread = pthread_self();
|
||||
if (strlen(filename))
|
||||
read_history(filename);
|
||||
rl_callback_handler_install(ASTERISK_PROMPT, consolehandler);
|
||||
rl_completion_entry_function = (Function *)cli_generator;
|
||||
for(;;) {
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(STDIN_FILENO, &rfds);
|
||||
res = select(STDIN_FILENO + 1, &rfds, NULL, NULL, NULL);
|
||||
if (res > 0) {
|
||||
rl_callback_read_char();
|
||||
} else if (res < 1) {
|
||||
rl_forced_update_display();
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
/* Do nothing */
|
||||
select(0,NULL,NULL,NULL,NULL);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
61
channel.c
61
channel.c
|
@ -18,6 +18,7 @@
|
|||
#include <sys/time.h>
|
||||
#include <signal.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <asterisk/sched.h>
|
||||
#include <asterisk/options.h>
|
||||
#include <asterisk/channel.h>
|
||||
|
@ -26,6 +27,27 @@
|
|||
#include <asterisk/file.h>
|
||||
#include <asterisk/translate.h>
|
||||
|
||||
|
||||
|
||||
#ifdef DEBUG_MUTEX
|
||||
/* Convenient mutex debugging functions */
|
||||
#define PTHREAD_MUTEX_LOCK(a) __PTHREAD_MUTEX_LOCK(__FUNCTION__, a)
|
||||
#define PTHREAD_MUTEX_UNLOCK(a) __PTHREAD_MUTEX_UNLOCK(__FUNCTION__, a)
|
||||
|
||||
static int __PTHREAD_MUTEX_LOCK(char *f, pthread_mutex_t *a) {
|
||||
ast_log(LOG_DEBUG, "Locking %p (%s)\n", a, f);
|
||||
return pthread_mutex_lock(a);
|
||||
}
|
||||
|
||||
static int __PTHREAD_MUTEX_UNLOCK(char *f, pthread_mutex_t *a) {
|
||||
ast_log(LOG_DEBUG, "Unlocking %p (%s)\n", a, f);
|
||||
return pthread_mutex_unlock(a);
|
||||
}
|
||||
#else
|
||||
#define PTHREAD_MUTEX_LOCK(a) pthread_mutex_lock(a)
|
||||
#define PTHREAD_MUTEX_UNLOCK(a) pthread_mutex_unlock(a)
|
||||
#endif
|
||||
|
||||
struct chanlist {
|
||||
char type[80];
|
||||
char description[80];
|
||||
|
@ -33,7 +55,6 @@ struct chanlist {
|
|||
struct ast_channel * (*requester)(char *type, int format, void *data);
|
||||
struct chanlist *next;
|
||||
} *backends = NULL;
|
||||
|
||||
struct ast_channel *channels = NULL;
|
||||
|
||||
/* Protect the channel list (highly unlikely that two things would change
|
||||
|
@ -45,7 +66,7 @@ int ast_channel_register(char *type, char *description, int capabilities,
|
|||
struct ast_channel *(*requester)(char *type, int format, void *data))
|
||||
{
|
||||
struct chanlist *chan, *last=NULL;
|
||||
if (pthread_mutex_lock(&chlock)) {
|
||||
if (PTHREAD_MUTEX_LOCK(&chlock)) {
|
||||
ast_log(LOG_WARNING, "Unable to lock channel list\n");
|
||||
return -1;
|
||||
}
|
||||
|
@ -53,7 +74,7 @@ int ast_channel_register(char *type, char *description, int capabilities,
|
|||
while(chan) {
|
||||
if (!strcasecmp(type, chan->type)) {
|
||||
ast_log(LOG_WARNING, "Already have a handler for type '%s'\n", type);
|
||||
pthread_mutex_unlock(&chlock);
|
||||
PTHREAD_MUTEX_UNLOCK(&chlock);
|
||||
return -1;
|
||||
}
|
||||
last = chan;
|
||||
|
@ -62,7 +83,7 @@ int ast_channel_register(char *type, char *description, int capabilities,
|
|||
chan = malloc(sizeof(struct chanlist));
|
||||
if (!chan) {
|
||||
ast_log(LOG_WARNING, "Out of memory\n");
|
||||
pthread_mutex_unlock(&chlock);
|
||||
PTHREAD_MUTEX_UNLOCK(&chlock);
|
||||
return -1;
|
||||
}
|
||||
strncpy(chan->type, type, sizeof(chan->type));
|
||||
|
@ -78,7 +99,7 @@ int ast_channel_register(char *type, char *description, int capabilities,
|
|||
ast_log(LOG_DEBUG, "Registered handler for '%s' (%s)\n", chan->type, chan->description);
|
||||
else if (option_verbose > 1)
|
||||
ast_verbose( VERBOSE_PREFIX_2 "Registered channel type '%s' (%s)\n", chan->type, chan->description);
|
||||
pthread_mutex_unlock(&chlock);
|
||||
PTHREAD_MUTEX_UNLOCK(&chlock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -86,7 +107,7 @@ struct ast_channel *ast_channel_alloc(void)
|
|||
{
|
||||
struct ast_channel *tmp;
|
||||
struct ast_channel_pvt *pvt;
|
||||
pthread_mutex_lock(&chlock);
|
||||
PTHREAD_MUTEX_LOCK(&chlock);
|
||||
tmp = malloc(sizeof(struct ast_channel));
|
||||
memset(tmp, 0, sizeof(struct ast_channel));
|
||||
if (tmp) {
|
||||
|
@ -121,17 +142,17 @@ struct ast_channel *ast_channel_alloc(void)
|
|||
}
|
||||
} else
|
||||
ast_log(LOG_WARNING, "Out of memory\n");
|
||||
pthread_mutex_unlock(&chlock);
|
||||
PTHREAD_MUTEX_UNLOCK(&chlock);
|
||||
return tmp;
|
||||
}
|
||||
|
||||
struct ast_channel *ast_channel_walk(struct ast_channel *prev)
|
||||
{
|
||||
struct ast_channel *l, *ret=NULL;
|
||||
pthread_mutex_lock(&chlock);
|
||||
PTHREAD_MUTEX_LOCK(&chlock);
|
||||
l = channels;
|
||||
if (!prev) {
|
||||
pthread_mutex_unlock(&chlock);
|
||||
PTHREAD_MUTEX_UNLOCK(&chlock);
|
||||
return l;
|
||||
}
|
||||
while(l) {
|
||||
|
@ -139,7 +160,7 @@ struct ast_channel *ast_channel_walk(struct ast_channel *prev)
|
|||
ret = l->next;
|
||||
l = l->next;
|
||||
}
|
||||
pthread_mutex_unlock(&chlock);
|
||||
PTHREAD_MUTEX_UNLOCK(&chlock);
|
||||
return ret;
|
||||
|
||||
}
|
||||
|
@ -147,7 +168,7 @@ struct ast_channel *ast_channel_walk(struct ast_channel *prev)
|
|||
void ast_channel_free(struct ast_channel *chan)
|
||||
{
|
||||
struct ast_channel *last=NULL, *cur;
|
||||
pthread_mutex_lock(&chlock);
|
||||
PTHREAD_MUTEX_LOCK(&chlock);
|
||||
cur = channels;
|
||||
while(cur) {
|
||||
if (cur == chan) {
|
||||
|
@ -174,7 +195,7 @@ void ast_channel_free(struct ast_channel *chan)
|
|||
free(chan->callerid);
|
||||
pthread_mutex_destroy(&chan->lock);
|
||||
free(chan);
|
||||
pthread_mutex_unlock(&chlock);
|
||||
PTHREAD_MUTEX_UNLOCK(&chlock);
|
||||
}
|
||||
|
||||
int ast_softhangup(struct ast_channel *chan)
|
||||
|
@ -220,7 +241,7 @@ void ast_channel_unregister(char *type)
|
|||
struct chanlist *chan, *last=NULL;
|
||||
if (option_debug)
|
||||
ast_log(LOG_DEBUG, "Unregistering channel type '%s'\n", type);
|
||||
if (pthread_mutex_lock(&chlock)) {
|
||||
if (PTHREAD_MUTEX_LOCK(&chlock)) {
|
||||
ast_log(LOG_WARNING, "Unable to lock channel list\n");
|
||||
return;
|
||||
}
|
||||
|
@ -232,13 +253,13 @@ void ast_channel_unregister(char *type)
|
|||
else
|
||||
backends = backends->next;
|
||||
free(chan);
|
||||
pthread_mutex_unlock(&chlock);
|
||||
PTHREAD_MUTEX_UNLOCK(&chlock);
|
||||
return;
|
||||
}
|
||||
last = chan;
|
||||
chan = chan->next;
|
||||
}
|
||||
pthread_mutex_unlock(&chlock);
|
||||
PTHREAD_MUTEX_UNLOCK(&chlock);
|
||||
}
|
||||
|
||||
int ast_answer(struct ast_channel *chan)
|
||||
|
@ -392,7 +413,7 @@ struct ast_channel *ast_request(char *type, int format, void *data)
|
|||
{
|
||||
struct chanlist *chan;
|
||||
struct ast_channel *c = NULL;
|
||||
if (pthread_mutex_lock(&chlock)) {
|
||||
if (PTHREAD_MUTEX_LOCK(&chlock)) {
|
||||
ast_log(LOG_WARNING, "Unable to lock channel list\n");
|
||||
return NULL;
|
||||
}
|
||||
|
@ -402,15 +423,16 @@ struct ast_channel *ast_request(char *type, int format, void *data)
|
|||
if (!(chan->capabilities & format)) {
|
||||
format = ast_translator_best_choice(format, chan->capabilities);
|
||||
}
|
||||
PTHREAD_MUTEX_UNLOCK(&chlock);
|
||||
if (chan->requester)
|
||||
c = chan->requester(type, format, data);
|
||||
pthread_mutex_unlock(&chlock);
|
||||
break;
|
||||
return c;
|
||||
}
|
||||
chan = chan->next;
|
||||
}
|
||||
if (!chan)
|
||||
ast_log(LOG_WARNING, "No channel type registered for '%s'\n", type);
|
||||
PTHREAD_MUTEX_UNLOCK(&chlock);
|
||||
return c;
|
||||
}
|
||||
|
||||
|
@ -433,9 +455,10 @@ int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int fti
|
|||
if (!len)
|
||||
return -1;
|
||||
do {
|
||||
if (c->streamid > -1) {
|
||||
if ((c->streamid > -1) || (c->trans && (c->trans->streamid > -1))) {
|
||||
d = ast_waitstream(c, AST_DIGIT_ANY);
|
||||
ast_stopstream(c);
|
||||
usleep(1000);
|
||||
if (!d)
|
||||
d = ast_waitfordigit(c, to);
|
||||
} else {
|
||||
|
|
|
@ -200,7 +200,7 @@ static int g723tolin_framein(struct ast_translator_pvt *pvt, struct ast_frame *f
|
|||
#ifdef ANNEX_B
|
||||
Decod(&tmp->dec, tmpdata, f->data, 0);
|
||||
for (x=0;x<Frame;x++)
|
||||
(tmp->buf + tmp->tail)[x] = tmpdata[x];
|
||||
(tmp->buf + tmp->tail)[x] = (short)tmpdata[x];
|
||||
#else
|
||||
Decod(&tmp->dec, tmp->buf + tmp->tail, f->data, 0);
|
||||
#endif
|
||||
|
|
|
@ -6,8 +6,10 @@
|
|||
[interfaces]
|
||||
;
|
||||
; Lines for which we are the user termination. They accept incoming
|
||||
; and outgoing calls.
|
||||
; and outgoing calls. We use the default context on the first 8 lines
|
||||
; used by internal phones.
|
||||
;
|
||||
context=default
|
||||
;user=voice00
|
||||
;user=voice01
|
||||
;user=voice02
|
||||
|
@ -16,15 +18,11 @@
|
|||
;user=voice05
|
||||
;user=voice06
|
||||
;user=voice07
|
||||
context=default
|
||||
user=voice13
|
||||
user=voice14
|
||||
user=voice15
|
||||
; Calls on 16 and 17 come from the outside world, so they get
|
||||
; a little bit special treatment
|
||||
context=remote
|
||||
user=voice16
|
||||
user=voice17
|
||||
;user=voice16
|
||||
;user=voice17
|
||||
;
|
||||
; Next we have lines which we only accept calls on, and typically
|
||||
; do not send outgoing calls on (i.e. these are where we are the
|
||||
|
|
|
@ -26,8 +26,8 @@ stripmsd=1
|
|||
;
|
||||
; Type of dialing
|
||||
;
|
||||
;dialtype=tone
|
||||
dialtype=pulse
|
||||
dialtype=tone
|
||||
;dialtype=pulse
|
||||
;
|
||||
; Mode selection. "Immediate" means that as soon as you dial, you're connected
|
||||
; and the line is considered up. "Ring" means we wait until the ring cadence
|
||||
|
@ -39,4 +39,4 @@ mode=immediate
|
|||
;
|
||||
; List all devices we can use.
|
||||
;
|
||||
device=/dev/ttyS3
|
||||
;device=/dev/ttyS3
|
||||
|
|
|
@ -3,12 +3,26 @@
|
|||
;
|
||||
; Module Loader configuration file
|
||||
;
|
||||
|
||||
[modules]
|
||||
autoload=yes
|
||||
;load=pbx_gtkconsole.so
|
||||
;
|
||||
; If you want, load the GTK console right away.
|
||||
; Don't load the KDE console since
|
||||
; it's not as sophisticated right now.
|
||||
;
|
||||
noload=pbx_gtkconsole.so
|
||||
;load=pbx_gtkconsole.so
|
||||
noload=pbx_kdeconsole.so
|
||||
;
|
||||
; Intercom application is obsoleted by
|
||||
; chan_oss. Don't load it.
|
||||
;
|
||||
noload=app_intercom.so
|
||||
;load=chan_vofr.so
|
||||
;load=chan_h323.so
|
||||
|
||||
;
|
||||
; Module names listed in "global" section will have symbols globally
|
||||
; exported to modules loaded after them.
|
||||
;
|
||||
[global]
|
||||
chan_modem.so=yes
|
||||
|
|
|
@ -2,13 +2,19 @@
|
|||
; Voicemail Configuration
|
||||
;
|
||||
[general]
|
||||
; Default format for writing Voicemail
|
||||
; format=g723sf|rawgsm|mp3|wav
|
||||
format=g723sf|wav49|wav
|
||||
; Default formats for writing Voicemail
|
||||
;format=g723sf|wav49|wav
|
||||
format=gsm|wav49|wav
|
||||
|
||||
;
|
||||
; Each mailbox is listed in the form <mailbox>=<password>,<name>,<email>
|
||||
; if the e-mail is specified, a message will be sent when a message is
|
||||
; received, to the given mailbox.
|
||||
;
|
||||
[default]
|
||||
4200=2345,Mark Spencer,markster@linux-support.net
|
||||
4300=2345,Ben Rigas,ben@american-computer.net
|
||||
4310=2345,Sales,sales@marko.net
|
||||
4069=2345,Matt Brooks,matt@marko.net
|
||||
4110=1379,Rob Flynn,rflynn@blueridge.net
|
||||
1234=4242,Example Mailbox,root@localhost
|
||||
;4200=9855,Mark Spencer,markster@linux-support.net
|
||||
;4300=3456,Ben Rigas,ben@american-computer.net
|
||||
;4310=5432,Sales,sales@marko.net
|
||||
;4069=6522,Matt Brooks,matt@marko.net
|
||||
;4110=3443,Rob Flynn,rflynn@blueridge.net
|
||||
|
|
|
@ -143,12 +143,14 @@ char ast_waitfordigit(struct ast_channel *c, int ms);
|
|||
for the first digit */
|
||||
int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int rtimeout, char *enders);
|
||||
#define CHECK_BLOCKING(c) { \
|
||||
if ((c)->blocking) \
|
||||
if ((c)->blocking) {\
|
||||
ast_log(LOG_WARNING, "Blocking '%s', already blocked by thread %ld in procedure %s\n", (c)->name, (c)->blocker, (c)->blockproc); \
|
||||
else { \
|
||||
/* *((int *)0)=0; */ \
|
||||
} else { \
|
||||
(c)->blocker = pthread_self(); \
|
||||
(c)->blockproc = __PRETTY_FUNCTION__; \
|
||||
c->blocking = -1; } }
|
||||
c->blocking = -1; \
|
||||
} }
|
||||
|
||||
#if defined(__cplusplus) || defined(c_plusplus)
|
||||
}
|
||||
|
|
40
loader.c
40
loader.c
|
@ -92,6 +92,22 @@ int ast_load_resource(char *resource_name)
|
|||
int errors=0;
|
||||
int res;
|
||||
struct module *m;
|
||||
int flags=0;
|
||||
char *val;
|
||||
int o;
|
||||
struct ast_config *cfg;
|
||||
/* Keep the module file parsing silent */
|
||||
o = option_verbose;
|
||||
option_verbose = 0;
|
||||
cfg = ast_load(AST_MODULE_CONFIG);
|
||||
option_verbose = o;
|
||||
if (cfg) {
|
||||
if ((val = ast_variable_retrieve(cfg, "global", resource_name))
|
||||
&& ast_true(val))
|
||||
flags |= RTLD_GLOBAL;
|
||||
ast_destroy(cfg);
|
||||
}
|
||||
|
||||
if (pthread_mutex_lock(&modlock))
|
||||
ast_log(LOG_WARNING, "Failed to lock\n");
|
||||
m = module_list;
|
||||
|
@ -115,7 +131,7 @@ int ast_load_resource(char *resource_name)
|
|||
} else {
|
||||
snprintf(fn, sizeof(fn), "%s/%s", AST_MODULE_DIR, resource_name);
|
||||
}
|
||||
m->lib = dlopen(fn, RTLD_NOW | RTLD_GLOBAL);
|
||||
m->lib = dlopen(fn, RTLD_NOW | flags);
|
||||
if (!m->lib) {
|
||||
ast_log(LOG_WARNING, "%s\n", dlerror());
|
||||
free(m);
|
||||
|
@ -149,16 +165,24 @@ int ast_load_resource(char *resource_name)
|
|||
pthread_mutex_unlock(&modlock);
|
||||
return -1;
|
||||
}
|
||||
if (option_verbose)
|
||||
ast_verbose( " => (%s)\n", m->description());
|
||||
pthread_mutex_unlock(&modlock);
|
||||
if ((res = m->load_module())) {
|
||||
ast_log(LOG_WARNING, "%s: load_module failed, returning %d\n", m->resource, fn, res);
|
||||
ast_unload_resource(resource_name, 0);
|
||||
return -1;
|
||||
if (!fully_booted) {
|
||||
if (option_verbose)
|
||||
ast_verbose( " => (%s)\n", m->description());
|
||||
if (option_console && !option_verbose)
|
||||
ast_verbose( ".");
|
||||
} else {
|
||||
if (option_verbose)
|
||||
ast_verbose(VERBOSE_PREFIX_1 "Loaded %s => (%s)\n", fn, m->description());
|
||||
}
|
||||
m->next = module_list;
|
||||
module_list = m;
|
||||
pthread_mutex_unlock(&modlock);
|
||||
if ((res = m->load_module())) {
|
||||
ast_log(LOG_WARNING, "%s: load_module failed, returning %d\n", m->resource, res);
|
||||
ast_unload_resource(resource_name, 0);
|
||||
return -1;
|
||||
}
|
||||
ast_update_use_count();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,12 +25,15 @@
|
|||
#include <asterisk/module.h>
|
||||
#include <asterisk/logger.h>
|
||||
#include <asterisk/options.h>
|
||||
#include <asterisk/cli.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/signal.h>
|
||||
|
||||
#include <gtk/gtk.h>
|
||||
#include <glib.h>
|
||||
|
@ -42,6 +45,9 @@ static pthread_mutex_t verb_lock = PTHREAD_MUTEX_INITIALIZER;
|
|||
static pthread_t console_thread;
|
||||
|
||||
static int inuse=0;
|
||||
static int clipipe[2];
|
||||
static int cleanupid = -1;
|
||||
|
||||
static char *dtext = "Asterisk PBX Console (GTK Version)";
|
||||
|
||||
static GtkWidget *window;
|
||||
|
@ -50,6 +56,9 @@ static GtkWidget *closew;
|
|||
static GtkWidget *verb;
|
||||
static GtkWidget *modules;
|
||||
static GtkWidget *statusbar;
|
||||
static GtkWidget *cli;
|
||||
|
||||
static struct timeval last;
|
||||
|
||||
static void update_statusbar(char *msg)
|
||||
{
|
||||
|
@ -65,26 +74,101 @@ int unload_module(void)
|
|||
gdk_threads_enter();
|
||||
gtk_widget_destroy(window);
|
||||
gdk_threads_leave();
|
||||
close(clipipe[0]);
|
||||
close(clipipe[1]);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cleanup(void *useless)
|
||||
{
|
||||
gdk_threads_enter();
|
||||
gtk_clist_thaw(GTK_CLIST(verb));
|
||||
gtk_widget_queue_resize(verb->parent);
|
||||
gtk_clist_moveto(GTK_CLIST(verb), GTK_CLIST(verb)->rows - 1, 0, 0, 0);
|
||||
cleanupid = -1;
|
||||
gdk_threads_leave();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void verboser(char *stuff, int opos, int replacelast, int complete)
|
||||
|
||||
static void __verboser(char *stuff, int opos, int replacelast, int complete)
|
||||
{
|
||||
char *s2[2];
|
||||
pthread_mutex_lock(&verb_lock);
|
||||
struct timeval tv;
|
||||
int ms;
|
||||
s2[0] = stuff;
|
||||
s2[1] = NULL;
|
||||
gdk_threads_enter();
|
||||
gtk_clist_freeze(GTK_CLIST(verb));
|
||||
if (replacelast)
|
||||
gtk_clist_remove(GTK_CLIST(verb), GTK_CLIST(verb)->rows - 1);
|
||||
gtk_clist_append(GTK_CLIST(verb), s2);
|
||||
gtk_clist_moveto(GTK_CLIST(verb), GTK_CLIST(verb)->rows - 1, 0, 0, 0);
|
||||
gdk_threads_leave();
|
||||
if (last.tv_sec || last.tv_usec) {
|
||||
gdk_threads_leave();
|
||||
gettimeofday(&tv, NULL);
|
||||
if (cleanupid > -1)
|
||||
gtk_timeout_remove(cleanupid);
|
||||
ms = (tv.tv_sec - last.tv_sec) * 1000 + (tv.tv_usec - last.tv_usec) / 1000;
|
||||
if (ms < 100) {
|
||||
/* We just got a message within 100ms, so just schedule an update
|
||||
in the near future */
|
||||
cleanupid = gtk_timeout_add(200, cleanup, NULL);
|
||||
} else {
|
||||
cleanup(&cleanupid);
|
||||
}
|
||||
last = tv;
|
||||
} else {
|
||||
gettimeofday(&last, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
static void verboser(char *stuff, int opos, int replacelast, int complete)
|
||||
{
|
||||
pthread_mutex_lock(&verb_lock);
|
||||
/* Lock appropriately if we're really being called in verbose mode */
|
||||
__verboser(stuff, opos, replacelast, complete);
|
||||
pthread_mutex_unlock(&verb_lock);
|
||||
}
|
||||
|
||||
static void cliinput(void *data, int source, GdkInputCondition ic)
|
||||
{
|
||||
static char buf[256];
|
||||
static int offset = 0;
|
||||
int res;
|
||||
char *c;
|
||||
char *l;
|
||||
char n;
|
||||
/* Read as much stuff is there */
|
||||
res = read(source, buf + offset, sizeof(buf) - 1 - offset);
|
||||
if (res > -1)
|
||||
buf[res + offset] = '\0';
|
||||
/* make sure we've null terminated whatever we have so far */
|
||||
c = buf;
|
||||
l = buf;
|
||||
while(*c) {
|
||||
if (*c == '\n') {
|
||||
/* Keep the trailing \n */
|
||||
c++;
|
||||
n = *c;
|
||||
*c = '\0';
|
||||
__verboser(l, 0, 0, 1);
|
||||
*(c - 1) = '\0';
|
||||
*c = n;
|
||||
l = c;
|
||||
} else
|
||||
c++;
|
||||
}
|
||||
if (strlen(l)) {
|
||||
/* We have some left over */
|
||||
memmove(buf, l, strlen(l) + 1);
|
||||
offset = strlen(buf);
|
||||
} else {
|
||||
offset = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void remove_module()
|
||||
{
|
||||
int res;
|
||||
|
@ -194,14 +278,12 @@ static int mod_update(void)
|
|||
if (GTK_CLIST(modules)->selection) {
|
||||
module= (char *)gtk_clist_get_row_data(GTK_CLIST(modules), (int) GTK_CLIST(modules)->selection->data);
|
||||
}
|
||||
gdk_threads_enter();
|
||||
gtk_clist_freeze(GTK_CLIST(modules));
|
||||
gtk_clist_clear(GTK_CLIST(modules));
|
||||
ast_update_module_list(add_mod);
|
||||
if (module)
|
||||
gtk_clist_select_row(GTK_CLIST(modules), gtk_clist_find_row_from_data(GTK_CLIST(modules), module), -1);
|
||||
gtk_clist_thaw(GTK_CLIST(modules));
|
||||
gdk_threads_leave();
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -220,8 +302,12 @@ static void exit_now(GtkWidget *widget, gpointer data)
|
|||
|
||||
static void exit_completely(GtkWidget *widget, gpointer data)
|
||||
{
|
||||
/* This is the wrong way to do this. We need an ast_clean_exit() routine */
|
||||
exit(0);
|
||||
#if 0
|
||||
/* Clever... */
|
||||
ast_cli_command(clipipe[1], "quit");
|
||||
#else
|
||||
kill(getpid(), SIGTERM);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void exit_nicely(GtkWidget *widget, gpointer data)
|
||||
|
@ -239,6 +325,17 @@ static void *consolethread(void *data)
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static int cli_activate()
|
||||
{
|
||||
char buf[256];
|
||||
strncpy(buf, gtk_entry_get_text(GTK_ENTRY(cli)), sizeof(buf));
|
||||
gtk_entry_set_text(GTK_ENTRY(cli), "");
|
||||
if (strlen(buf)) {
|
||||
ast_cli_command(clipipe[1], buf);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int show_console()
|
||||
{
|
||||
GtkWidget *hbox;
|
||||
|
@ -276,7 +373,7 @@ static int show_console()
|
|||
gtk_container_add(GTK_CONTAINER(sw), verb);
|
||||
gtk_widget_show(verb);
|
||||
gtk_widget_show(sw);
|
||||
gtk_widget_set_usize(verb, 600, 400);
|
||||
gtk_widget_set_usize(verb, 640, 400);
|
||||
gtk_notebook_append_page(GTK_NOTEBOOK(notebook), sw, gtk_label_new("Verbose Status"));
|
||||
|
||||
|
||||
|
@ -333,14 +430,21 @@ static int show_console()
|
|||
|
||||
hbox = gtk_vbox_new(FALSE, 0);
|
||||
gtk_widget_show(hbox);
|
||||
|
||||
/* Command line */
|
||||
cli = gtk_entry_new();
|
||||
gtk_widget_show(cli);
|
||||
|
||||
gtk_signal_connect(GTK_OBJECT(cli), "activate",
|
||||
GTK_SIGNAL_FUNC (cli_activate), NULL);
|
||||
|
||||
gtk_box_pack_start(GTK_BOX(hbox), notebook, TRUE, TRUE, 5);
|
||||
gtk_box_pack_start(GTK_BOX(hbox), wbox, FALSE, FALSE, 5);
|
||||
gtk_box_pack_start(GTK_BOX(hbox), cli, FALSE, FALSE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(hbox), statusbar, FALSE, FALSE, 0);
|
||||
|
||||
|
||||
gtk_container_add(GTK_CONTAINER(window), hbox);
|
||||
gtk_window_set_title(GTK_WINDOW(window), "Asterisk Console");
|
||||
gtk_widget_grab_focus(cli);
|
||||
pthread_create(&console_thread, NULL, consolethread, NULL);
|
||||
/* XXX Okay, seriously fix me! XXX */
|
||||
usleep(100000);
|
||||
|
@ -348,6 +452,7 @@ static int show_console()
|
|||
gtk_clist_freeze(GTK_CLIST(verb));
|
||||
ast_loader_register(mod_update);
|
||||
gtk_clist_thaw(GTK_CLIST(verb));
|
||||
gdk_input_add(clipipe[0], GDK_INPUT_READ, cliinput, NULL);
|
||||
mod_update();
|
||||
update_statusbar("Asterisk Console Ready");
|
||||
return 0;
|
||||
|
@ -356,6 +461,10 @@ static int show_console()
|
|||
|
||||
int load_module(void)
|
||||
{
|
||||
if (pipe(clipipe)) {
|
||||
ast_log(LOG_WARNING, "Unable to create CLI pipe\n");
|
||||
return -1;
|
||||
}
|
||||
g_thread_init(NULL);
|
||||
if (gtk_init_check(NULL, NULL)) {
|
||||
/* XXX Do we need to call this twice? XXX */
|
||||
|
|
14
say.c
14
say.c
|
@ -42,8 +42,13 @@ int ast_say_digits(struct ast_channel *chan, int num)
|
|||
int ast_say_number(struct ast_channel *chan, int num)
|
||||
{
|
||||
int res = 0;
|
||||
int playh = 0;
|
||||
char fn[256] = "";
|
||||
while(num && !res) {
|
||||
if (playh) {
|
||||
snprintf(fn, sizeof(fn), "digits/hundred");
|
||||
playh = 0;
|
||||
} else
|
||||
if (num < 20) {
|
||||
snprintf(fn, sizeof(fn), "digits/%d", num);
|
||||
num = 0;
|
||||
|
@ -52,8 +57,13 @@ int ast_say_number(struct ast_channel *chan, int num)
|
|||
snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
|
||||
num -= ((num / 10) * 10);
|
||||
} else {
|
||||
ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
|
||||
res = -1;
|
||||
if (num < 1000){
|
||||
snprintf(fn, sizeof(fn), "digits/%d", (num/100));
|
||||
playh++;
|
||||
} else {
|
||||
ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
|
||||
res = -1;
|
||||
}
|
||||
}
|
||||
if (!res) {
|
||||
res = ast_streamfile(chan, fn);
|
||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,5 @@
|
|||
Ó™ÕS^ÀͪUe ³M-WƒVÀ¹˜J’[¬¡jm¶éÓè‚#àÀÖ’CKœá8ë1·äÁ8Ô±jMo!¡ú¿iÒv›°sdH±ÛebÂ,<2C>]¤Ö…´Ûž%”^$)n8ÄÒkú¥k¤Å¨æòÓ¢ÈãGâµ ˜oŠ6åñ™Ú„–Ód4Ò5ª!kŠ¦Ûè‘ØdŒÃÈ“•;?Œä‹‰×*<2A>$&Ür[„Ò1á¤ë¶ƒ%™¶<03>D9^Ô:Ü‘"‘Ú€Æ]‹#ÙðV½Ò4Ð᳉"ó"qÉ/‹!a&<26>€‡â'MðÛÆÃZi”Ò3èis…¹ ²U<14>ãÕ!ŽÇ ",Þ<>öÙ}âµ<C3A2>‚W ÒqÑe{{Ç)Ž;o{åƒT²Âw¤4üE(s*(ÛMLþÓs“žyw<79>U¨¢rÑI¾-ÄâqPµQúmkMá¤N–ÁÔ/”:qÎ/'je*o³§×˜¤m2äÙ.'oo®+ÓçcÔmœ[xÛ°¶ä7@³ÙQÄêžS\kQ¸ÔjG=ÙPŠ”P¶ÕÔ,¬_pk¯¥Û磌k<C2AB>bñ<62>áCisÇf·ÙÓMTÒp6%Ó¬¬_pkPߎUÆÔÓÏVü5wk®Êãxd5n<35>…›1´›Óë“×:kp=ÚRÆ¡ÚíX+»è
|
||||
ÜJHÉ…„æäÌÿJÇbÓêyÞkî©—“¯h<€Ç9[…¸×~Èh$‰Ê؃솲9[Ôj‚jîÅhÊôfÊ…#›»ñ‹D„¥ÈÄi·¬…^
|
||||
r4ìÓjƒgq…¨9Rrþ4¼ˆÐœR„ˆ‰ÉW5AÙ“‰¯u0þÓ«d3©‹¨ò¿ŒÎÔ‰§Ä
|
||||
‰=p‰(ÄÜQ½X“((͞ѤÓç„ghçLK¬h“˧cÔ;"<22>'É0ÂS¡ )\ééTÓ(Œç``«9km&£vµÉfªYc<59>¢Ä«'±2žEÓ)u3 ÈC>Uͯ
réqR#¶BV¶Ü¯e¸M$îÒå„ê(´¤dÅr+cºÆ¶ã7À£ûe!¦ë¨ä5"•„‚ÒŸweà°ÄG.öSžÄFäÍÙ²£óZ±ÚÂb<C382>{‘[¹ŠÓW
|
||||
³b
•NÏd±Ôºî@ò·–Ä£º<C2A3>{¢"× ÓN"™³5,ªÔ³"«'‘°«µãFÛ<46>´ŸZˆ–—ÜâÓ]UÞY`!®ûQɱA<C2B1>«;v_AØܹÒ<C2B9>³ÁB¦…ÔjÒ^†áT¢ªŽs[¢<>Ûe¨Ó¦@ç±îV“Ö@¨Š,S¥Ò^S¥"à ¾õ²ÄÓ¦Áäm´ãØ€Ùœ‰["À€£+mGYÓ s™Zž€¥¬µÉnÖ å£rE3| ¸ÓqÄ¥Ç@öá®Á-ÒÝjœÚfÀ¼òØ´ÄàÏrMÌ¢Þ £T1†<31>‚À¯uš76Ô jaX” Çl’i,˜ ¶ÓLÕ“Õ@¤™<C2A4>Å‹!E"<22>"îÓßzÙQŒ ã6”·òªà·"ˆ´êÆ Ë!±¥SpÀÆòŠ8ÕÒÝZ\ÙX Æì®MZàºã‰\l §h*'‚@êÛ‘EÒ<C2AD>bÔ@8ì—[;ì`µKVÀbBÃó˜à_S}u
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,4 @@
|
|||
Õ‘-£R¢4t`Ö¡f¢¤¥<C2A4>* ¶«4;p¢Q²I^œÖ<C593>y`©»"ŸIVš˜<C5A1>
<0A>c,ÒÀâU\OÚ« ÁË¥Uòó×èxÝÙ|¢(V£™‘Œá™©sSŸ˜¢ÎÍ4¤Ö[xؑء†¥±FͺÂÙnD¨ÜÂ6ͦç(œâ›¢5fÈÕœ`˜Y»#ÊÕfh ßøänÍCçbÔ¢7fY$´§i7&Ô<>r¡rw%(ª‰ÖƒÈÄãm¸6X…T0&Ë›+7,¶±%Ô¦dè_Í4ä–ûÅ\lÿ¶6îy[uDny13#nJÆÕ&u8Šîà-`Â]wÐ;ðIÆ“wQ$‹ŽÚ+°°²¡Ôét¦øëRK„m8äw1”“q[ul&ä1…®u0ê,<2C>ÉLÓê|æ±ç/4¬›$èÐF̉IotÍŠ«iÆÚèï9%îãÔ*[ZrîÈÈ42',îÈ„³>™[}E¿å›Ó&v¦Õa8äÔhdò}äô+if‚}ÈFãyÕâvÈà,V{¥C„qªÅÔ¦cß1{é9$×A%Žè
|
||||
D)vw¬KD²'#wì¶í–Óæcë0qh†ªE)Ws<%m·bçG7-¸.“æË%ZmË·Òålç(æ©#hÇè†Çc¿ˆ´ìç`mÉ¿îÅŽeq¥iÒ%§™x¦9wÁ³î¢¨=K¤ñCx49-zåÉm¢G#Ò&¦Xá ä–¥Në{B€ËÆ4¥~û]ò&㢢(ÉvɧÒ'¥$é€Â-D<>°ÓÒat–ùKàI+5ê<>ªõvù¤ÓàL ÚPág›˜¤n°¡Lšój3ê<33>Rà)w¤¡èä•Ú×bš$¢’¡Û •1%<25>å摇¸‘h£Þ.ÈĦD¿d<C2BF>XœØ¥‘%"ê¤=³m²£GÚ
ÆËl¤8øµLÓ¹i(äÆÜØh‰]pj†Ý<15>Œ†ç;Š¾¥„¨Ø<C2A8>½¹<¡«fnÞãØdp<64>qŒ§kœ}9i´ÆÉS´¦ÀÃãÀøþdå½NhÂÕLrè<72>h8å›ûºdǶÁ@¸îƒ¯ËBmÆã}-H“’È$ÕžD÷(˜ªI<08>„ƒhÉò©¦Û<C2A6>h\M…7?…¨bì‘É=ÕE¾Ø‹G'oÊœ¨¨%’²Ä<12>“7øYÔ¦
|
||||
h"LÔÝU¾<55><C2BE>å²ún<Ñ‘C·MUm“J²ÁÔ“e´ÛqÙwÔnyIÜ…´° ]—d´ãIÛX¦¦ZäMÉP›¢É#³Ç¤Óžv¹
|
||||
›¶Ú<C2B6>Ç<10>dcšy¡"Äj¶[¡A$þxÒߥ¸œ¡Â.HË¡ÂZ›R?•Z£4<C2A3>’$‚§P‘J}QÔÝMù³Bò‘RÝ«ƒ‚ÜnYbRĉ%mÉ"¥¤jÁæ°fÓßfY¬¤Tq¦¤³"”e—-¶¤km8ܶâ6âmÂ2Ò$¥ì™·!Šæ¾é%laµÒݼÁ¡×ÊÉm¾‚!¤±ÇdÒŸfå Ç#·I½a×H²fÚ»a¹#jE̹AÅs²Q#Ò vd¢àÀÃR¶H’¹!‡NJíT<C3AD>"ß©—"¹A&Øn¨Ü
|
Binary file not shown.
|
@ -0,0 +1 @@
|
|||
Ô cœ‘‚À¦írXS° ¦ì)ÔœºàZ¬Ú<C2AC>_œÀÉ&j¦âÒzXÐh€r‰ÁEþ†€Ôô<C394>Væ’ Ùª–Y3” É#M8[Ôà‹ÙÖàÃQ¸ãÔ 'esYžà ËRFåtÀ
N$<24>Ò]zœÙÄ€+!e#4êàÊÔ¾¹cr€æã–4Ù’ÀÄâ<C384>ÂãÒÝj™RÀ¹‘8›®€34Q…„àoóÕW—ðÀ¿q%Ò<>dÜâb@©]n=€·ªÉ<C2AA>ðà6ß–hÁ¹ù¶ÑÒa‡]Ùua„“i˶ƒCJV8š‡c4Û“È%¹D&Y1£ÁÔhr§0ƒìÉlèÒª(ÐÙ>ƒM<C692>RvÄ܃Ìʼn¯Õkr_(<28>hÔf'vér&£}î7$ŽÁÚ’¬È˜¥8çÕª‚—p{ÍXÏMÈêy&š™ï†ŽÌá<18>†¯ñŽW¹m¶ÜÔè{XwL¤Û–pÞàéÎ(°gë-½DÒ'ul&ì›ÖÕh[_Ru(ˆ 1}éêô1P¼Ís+8ï¼"álR;gÖ$K_aç
j•´Üo͸ð<C2B8>X¥o+'¾Ñ*ÙÜC¶(çÕ_LòØÛj±‰äÛ'š·p!ËÚÈ#<23>wîŒì)—N¹gÒ'¥ÙRÚ‰]Ò)ØÛÚDÆìÜD£ÜCÖÕÊ[pîBu+ÛÒcdâèƒ[e
¨ÜÚ <09>IéãÊ¡E]¯!¤Ü¢7ô’ÅTÓb|!RîÁ#Y$óª@è#Gäì4}’–ÔŒÀþ]ÏYjÒžc-Q¡DŒRÌêÁ'#i©!n ¥Ý‘9˜r «jØÓ×"r<>qA;JÇéÉÖ¤ÜzãFZq )ˆÅ±M),ØëpLêØ„*’0ܤg9´íéfÆÝÛžw›ZÅ+¨ƒ©Ùêš)QHF*…º›¶¥<¾“»RÇEäv;\žÆG(}(ŒÙkiÉhÌ…ú<E280A6>:dÅæ-MªãÈÃI–Úü«dz£¶€*Ö_$2à˜ƒ2)Ûv€ãzÒ)¤¥ëˆ¹mŸ——ã<E28094>̽ýÖ^<öàƒdÌ©3uŠÊ°[M½´Ž„!<21>¡Y<59>F‹*íhÕ]E·è&¦Ò£g©Z’X<E28099>ì<04>š&Ê¥%8T-¤ÕÝE;î„•€£$¥ä:
iÁ}Vä<56>nnIš©ÃË-çTãÖ^<ûð¦z„u–”«å¸âŽË7«Go[®Ç#©ÄE"x8œÕM{©DGõŽ´•žBÏYl(R«EÈ둾¬¯ÇÇ#r63Ômþ˜¦„”Nµ¡R¢™£‹\°ã–å»ú<C2BB>°ÂˆLq¶ÐÒ'Ŭšªƒ RjˬÂan×[¦á»+u[îîs:¨8¥Ò#Žä¢§dɪ'$VBÚ±¶í¾!WXMÄ´¡MdÇZÒßn]baÃIjPƒ'/Ö¦å¯!Å,±<>ª¢ÜzéÒŸe]"«bQ)¨˜«A)«eÍfáORT˜«`³“UªÞÒt¥"ØÁK"Œ‘e¦A&ÍŽ¨ãä€Ù<E282AC>¹ÉXà€©‘ªóÑÝK%šÀ¥*–+Þ€Çd²ÌSTÀÆ)²"e¾À¶œnC+
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,4 @@
|
|||
ÓßiŐ† Ěé·Hśbŕ¶ŰvĂłĚ ÉӍʤnŔDáX˘oÓ]z"´ X$9»S˘ <[s(ÂęŔ©!vEUvŔ}’!Ójˇ¦@—’ČüR YWú+\€<ËÂp‚Ŕ3®<>ÚŇ]zYŔ —*Q·+ć€Ů,§KzŔÔQäh §v,ăÔß‚`Ůրɣ‰Ç$´€ÖԌȢfŔô«Ą–€ŕ¦ËŇ8ŞŐˇzYĐŔ§aŃÉ"r`ß›—Y¨ŔÄÜ”í$š€%ŠIŠÖé›ebćÁFŇQ"ŤńâÉ&·Ë¶_ËČͶAdRH1«M"šÓ1›ž:ZD<5A>@)5$ęCW[’ýľYĚG#mą/aÎÚ$dÔ•ÓđşÚ=]°9¨‘É$sÎ"ł÷+qĄYnqďC[v%ČÔŻĂŐ˝qϸ/ś9qQ8!ŤM ‚<C2A0>äâˇ0*qńVă¦8¨ÔńĂ™üoväĘÖ'mP7L))/oŤQ[ň*ťmí9'†¨ŮÔň»Ůűoş#V]Emm3<6D>¦%ŻŰĚĂÝĆ×>mÎÇ\8śÔółÖ:×ńĹm7ĎŮŽę”Ű"o©‚ŔÔ¦ŘŰQĆäĐHÜÔ±Ľ;oĚŽW*émÔęf1
|
||||
oĚMn·cÝé*4·ĺ/Ôq
|
||||
¤J)/qŹzr«#áđÇ#7#ß3Ľ*n=˘Ő2ł™»‚đ, ©ÜăpíĂÍĆés®XŁ˛N[u
hĆ"źŐ1´R:uŻ22†«Uu®™SŽtów,ÁaM#/í1Q]MGEŐ2›Úyď©Ę*ă’{‹yůr9|{#âŤČ˘}Î'^Ť›Őq”zľŃÖÚ'}1oErDě<44>O¶ˇŻůDĆŃI[l<10>Őm”y<>ĆL˘Öއ®Č4ÍUÂŇqdP¦ë‰ĐH˘ŤÇ„Ő<C590>ŢůزÉ#u&ĂŽ<C482>Á,ţ"‘N«ťQ†<14>ĐËőG#ŐŞ„"¸—0FÜc'$•
} µÇ#—o6ŕ‘·%›*Îu¬F“Őčt¸›«Čúm<0C>ÜĚń}*<2A>fźjş¤˛]| ŠtdhşĚÖ§[Ňąˇë3K©6…ćŚzg„ČKŁIxsĚęŚo‘…PŐfKŢů§ĚVčɦ¦}Nµ¬ ©5u8«H{Zj7ÔçBÚ+®ŞČŰlW°ÄŚ";5¦bŻÝ@äÄcmľ»Ô"RŁŞŁÚĚŤM˛<>ä}‹ŰěĘ<C49B>ęâÇ đaÖ%lZÔk!˘ÁX¬QzćŕÜĺw•w¸<77>,¬-Ő+đÁDś6ŰÖ"z"Tá\qŤ%"|ÁY5ŽË'˛ˇY'D›ŽTÂI±OŐ¤Z–ÂfÓq‡Ş<E280A1>á,ŰŮ®ČÁgbĄŰęÄA\rMS$Ô%QŮጡ—Cmȥ΀¨…˝ĚÎA[j<Ěî öŠm‘Ó!iŕŕ¤Ó1,™ę<E284A2>f]ŠY[ś Ő5Ž&Ô´ ˘Ó<CB98>ČŁÓj]Ůę ĘÖČóÚŕÖôŽYcŘŕčäŽW[Ž€»
|
||||
<EFBFBD>»cŇ]z<>âR Ř“’ÉT¸€É${VěÔŔ*«C̡`Ç
n'Ňťsbŕ·i˝ŕŔë#ŽG,”€lĺ•răÚ€¦ĄŤšă
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,5 @@
|
|||
ÔEP™ˆáZüSÉ]ŸÁX|ûÔÁ|<7C>’Lo39\AT-»VÒfr¡Y„¡Í;2|V¶N6ÓÊ€–fGH‘ðA(Ýi
|
||||
Ò§zÙ—!)a‚]mRàó+u£
|
||||
”Á"e$Kk”¡Eâ›eÒé‹•Q„<51>ŠJÙ¬p¡‡Q4›<34>ÀÃfÁ%ÐÁ\ÜVëÒhƒQ!dmrL¯láj[°Ûu–¡8S$Z<>XÁPl)ZûÒ£e¨cQe+Û·By%j¬Ê[#:Ýœ™kâÈŠqôÒ¤vlë¯%¤N1¢o&×|rÄ¢oC² OÖjÄ–l)ÑoÒç…-ªoÃ÷££KáÊ©ŽTœk-µ$vÖ$kÌ:\<5C>‡´Ó©lz°iMÑuNÅk-;wU²ãi¬ LŽ££iéÌœ•Y˜Ôh\êøijyCÔ&×ÏìkD¤¸Ùg,š•ñKK͉–ÂèK*Óèm£(g v•Ñ¦eNÑ$jµË
ƾÆâËMÔå—¶ÛÔhTâðË-4,R×z|«(ȃ®gLÌm4ãkHù5¿'#Ô¦Ri°Ê)ÒNÍkæEˆÀ§µÞ‡6MÆäÀ¤=b¿m|Õi¬¨»CHÄù1Œ¦Gñ'nÀ„§Ü©i¢Ê£½.ôkÕid©®ã!›œt±¯$» Ù¯%x¥
|
||||
”«xã&’%‹Ö€è°Ê㙌ÆtdâäËAÕ¤"Ö¤2!(ý™%ÓvÇkÓãsq¸ge.Uy´oɨ;mwîšfÌ8‚mI7£)&#•Ó%e*øv¬³-Ø9"vêG¡)/}Èê,Úä<C39A>’ÿ—äÓÓãL*x¦È㥀ö‚¨XàSfš„Æ3CWKiª‡Ðãr¶’Óßbqû‡Èæ‰XÃU(•Ž§Ú¦iÎÔŽ…Ï’.Ô<>Òb£¬êrD}*2©ŒCµH‰Ù,î"¹X•âîâ"‚…:õÓž«mšV»ã)GBR‚U]r¤ÄAú׊ñ".f**ØZƒiâÜ¢– û»©#éîÎJßë¬1$m¶Û„¥É7y¥CÚ”q&°e´<65>š|öêF١ꧧDm)¥z…òP<C3B2>(§ÕZ‚r-pÉÙ9+¿IÆÛ
Æî<C386>îãZƤ–ÈÙÍÄïÓ£m.q™l-Ñ<ä’å`j.ýÿP¤ˆV·[—FI“¶îÌÓ¤mjñhÊHãnDÄ—%!T¶êĘÅÅ$ÉÔ„—Ķ¬Òæ}æ°š†¦£m±š£#¯;&ŸgÊÛmsZ<73>$ù¬íÆÓÒæefø ¢*‚ÁœÃNüÅúËÝEˆx› ãÍä¨ÜÓ¤c©ù¤Ä:ì–¬¥Å)LòµmP¢â«ÑÁ¨Âš²èBÔ_™i¢Üâ Qr˜±C½kù¹S¼Â‘EoFêÀ‚Šf¦Á×<15>éSÒæ<C383>U´¦èã[4—ÉfÕ$Tü2˜Ä^¥KrF+Õ˜aìár„$ÁáB¡R¢¶õŠüŦ¤MÕmÚßê£h˜1DÑÖX’mazâ¥"mú©#·w†)Tæ1êƒâÜ„„ZÃ<5A>°Ò×”zeS¼"¶ÖXûšàM”{°äX5“Å€¥McˆÛAÔØš%[Z³„ŒÓŠ‚k%tlé®Ã5\z©°°ã'ýy(eÔ"¢a[¦¢Áj«T¡ù]N7車PêºidÔ‚KeŽ
|
||||
©Õ“YÜÁñ&¯^å’ú§¬6ÛjáÙLßf„ƒ×±6Û
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1 @@
|
|||
ÒdŠ”ÛÆÀëŸB6ëªàËq4TŽR –©
ˆ“ ¡ZÝwUMÒ¤ƒÙ¼ÁEü•k\`§ž†êçÂÁ9”’)ÔÌÁÄØi©%Ñ,Ö!#kCÛîIÇtÂ&YjÚÁ¨ÃØ…U*ä‚»;ÅÌ¡ÑiÍ¥ªÂ¨\©Íþž¢àät´ƒ%
sÀ®lâw‰é£&ÑéÃõ°}"ÔÊdšyb±ÿH^{C%$m¸þy§ºäŒz’Ó(„vøs*6ÜÞ„ËsÌ’Ûh»|s¬©7ÆÞql;l¢õÔ(Œ.¸áÌ•4Skr¬ÔÐa0oŒKÞV>ìoªh¦œ‡Ó«„v¹q®We˘oJtM‰¨<E280B0>Ý.]âñ«cmÌ[؆@ÊÓk¤®©ÛLDŒE¡îmÌI6vþöÛ.7í=Y#ÛŒú¥<C3BA> Óªœn¹Ü°’P4_o
Ü~³wvqŒÛ÷7áåt%…öÓé£îzsäÃI¼ÓåO·½V¶äw«nÙ<6E>$Ñë0FÔr8Ó+¬®iñƒ¼15}lËzyQ”<51>ÔÔrHØ<48>
¨k±†ÛÓ,”n±„«õLHHž…ß—½ÉUŒÍÈ,f[PÚɪin Ò줪r<C2AA>B··ìâKÉ¥•¡‘ ¯m¸×Tä©}K ‰Òp«n¢“&}ëª'5Ž§Ã襖§T=€ªÙæÉ4ÄqËýÒn²®ª•dŒé˺”èDÔvûW°¦F™<>È•E–*Ï©,Ònâê#•#G-¿3•%´åú†²“âéa„Š•;;¢¸<C2A2>ÒpÓi¬ŒÄ÷Zm—5“¥éæn¶š<C2B6>H0ÒJ(ì‘$PrŠ8<C5A0>Òj³àì<C3A0>æ4ä¾]®£¨‹–€[Ž‡Æä’Q\sc!bDÒ/kR*ˆ£é»F©Œ¡SS§…&ì‚&å(‘ð"»$·ÒåÒeœ<65>†áĤp,Œ¡ÀñI¬ä‚ÁYúêùsš!i“M6Ò%“X\ª¡”ÃFÒÍî¡M·4Þ|ÀïYñ'=à`’S°¦™Ò!¢™’ê<E28099>6ÞE·ZjÁWl½Ç5\áÇmÀ›RÁY)a5Òf¢•‘z¡N¦Ö%]j¡)_Õ™Ô®ÁE‘=ˆá+q.KÑb›Y³Aº£‘·Ý ¡5²UÆÜ<C386>`à ¦ÜÔ€Õ¬zØMÑâ’™Zƒas-Ë8ÛŽ<C39B>x]®fÛ|Á´#L¥ªÁI±Û,Ñ"’™š¤<C5A1>)4uØ,ÌÁ$ÜQ‰š Æår=òÐ<C3B2>i²È¹,Ѥ‚ØÒðá £…ÆdcA5/ZSÈ Êô’=[¦ái*±ÆìÑeŠ<65>Ûð!HڊǺàºYJVŽ §iæݬÁH¯Î«ZÑer‘"pÁ<ØŒÅK¸Á'ÉÃ#RÁLæ‰i5àÀùŸ±¬áÒ©r“ÜáYaJá`¡3c*‹ˆÁÞÝS/vdÁ$´É
'Ô*«YRÖ¡¥znKÄpÁ†"@<40>VâÓ°¶ÁpÁ±/Eó
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Reference in New Issue