2 * Asterisk -- An open source telephony toolkit.
4 * Copyright (C) 1999 - 2005, Digium, Inc.
6 * Mark Spencer <markster@digium.com>
8 * See http://www.asterisk.org for more information about
9 * the Asterisk project. Please do not directly contact
10 * any of the maintainers of this project for assistance;
11 * the project provides a web site, mailing lists and IRC
12 * channels for your use.
14 * This program is free software, distributed under the terms of
15 * the GNU General Public License Version 2. See the LICENSE file
16 * at the top of the source tree.
21 * \brief Comedian Mail - Voicemail System
25 * \ingroup applications
29 * 12-16-2004 : Support for Greek added by InAccess Networks (work funded by HOL, www.hol.gr)
30 * George Konstantoulakis <gkon@inaccessnetworks.com>
32 * 05-10-2005 : Support for Swedish and Norwegian added by Daniel Nylander, http://www.danielnylander.se/
34 * 05-11-2005 : An option for maximum number of messsages per mailbox added by GDS Partners (www.gdspartners.com)
35 * 07-11-2005 : An issue with voicemail synchronization has been fixed by GDS Partners (www.gdspartners.com)
36 * Stojan Sljivic <stojan.sljivic@gdspartners.com>
48 #include <sys/types.h>
55 ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
57 #include "asterisk/lock.h"
58 #include "asterisk/file.h"
59 #include "asterisk/logger.h"
60 #include "asterisk/channel.h"
61 #include "asterisk/pbx.h"
62 #include "asterisk/options.h"
63 #include "asterisk/config.h"
64 #include "asterisk/say.h"
65 #include "asterisk/module.h"
66 #include "asterisk/adsi.h"
67 #include "asterisk/app.h"
68 #include "asterisk/manager.h"
69 #include "asterisk/dsp.h"
70 #include "asterisk/localtime.h"
71 #include "asterisk/cli.h"
72 #include "asterisk/utils.h"
73 #ifdef USE_ODBC_STORAGE
74 #include "asterisk/res_odbc.h"
77 #define COMMAND_TIMEOUT 5000
79 #define VOICEMAIL_CONFIG "voicemail.conf"
80 #define ASTERISK_USERNAME "asterisk"
82 /* Default mail command to mail voicemail. Change it with the
83 mailcmd= command in voicemail.conf */
84 #define SENDMAIL "/usr/sbin/sendmail -t"
86 #define INTRO "vm-intro"
89 #define MAXMSGLIMIT 9999
91 #define BASEMAXINLINE 256
92 #define BASELINELEN 72
93 #define BASEMAXINLINE 256
96 #define MAX_DATETIME_FORMAT 512
97 #define MAX_NUM_CID_CONTEXTS 10
99 #define VM_REVIEW (1 << 0)
100 #define VM_OPERATOR (1 << 1)
101 #define VM_SAYCID (1 << 2)
102 #define VM_SVMAIL (1 << 3)
103 #define VM_ENVELOPE (1 << 4)
104 #define VM_SAYDURATION (1 << 5)
105 #define VM_SKIPAFTERCMD (1 << 6)
106 #define VM_FORCENAME (1 << 7) /*!< Have new users record their name */
107 #define VM_FORCEGREET (1 << 8) /*!< Have new users record their greetings */
108 #define VM_PBXSKIP (1 << 9)
109 #define VM_DIRECFORWARD (1 << 10) /*!< directory_forward */
110 #define VM_ATTACH (1 << 11)
111 #define VM_DELETE (1 << 12)
112 #define VM_ALLOCED (1 << 13)
113 #define VM_SEARCH (1 << 14)
115 #define ERROR_LOCK_PATH -100
118 OPT_SILENT = (1 << 0),
119 OPT_BUSY_GREETING = (1 << 1),
120 OPT_UNAVAIL_GREETING = (1 << 2),
121 OPT_RECORDGAIN = (1 << 3),
122 OPT_PREPEND_MAILBOX = (1 << 4),
123 OPT_PRIORITY_JUMP = (1 << 5),
127 OPT_ARG_RECORDGAIN = 0,
128 OPT_ARG_ARRAY_SIZE = 1,
131 AST_APP_OPTIONS(vm_app_options, {
132 AST_APP_OPTION('s', OPT_SILENT),
133 AST_APP_OPTION('b', OPT_BUSY_GREETING),
134 AST_APP_OPTION('u', OPT_UNAVAIL_GREETING),
135 AST_APP_OPTION_ARG('g', OPT_RECORDGAIN, OPT_ARG_RECORDGAIN),
136 AST_APP_OPTION('p', OPT_PREPEND_MAILBOX),
137 AST_APP_OPTION('j', OPT_PRIORITY_JUMP),
140 static int load_config(void);
142 /*! \page vmlang Voicemail Language Syntaxes Supported
144 \par Syntaxes supported, not really language codes.
151 \arg \b pt - Portuguese
153 \arg \b no - Norwegian
156 German requires the following additional soundfile:
157 \arg \b 1F einE (feminine)
159 Spanish requires the following additional soundfile:
160 \arg \b 1M un (masculine)
162 Dutch, Portuguese & Spanish require the following additional soundfiles:
163 \arg \b vm-INBOXs singular of 'new'
164 \arg \b vm-Olds singular of 'old/heard/read'
167 \arg \b vm-INBOX nieuwe (nl)
168 \arg \b vm-Old oude (nl)
171 \arg \b vm-nytt singular of 'new'
172 \arg \b vm-nya plural of 'new'
173 \arg \b vm-gammalt singular of 'old'
174 \arg \b vm-gamla plural of 'old'
175 \arg \b digits/ett 'one', not always same as 'digits/1'
178 \arg \b vm-ny singular of 'new'
179 \arg \b vm-nye plural of 'new'
180 \arg \b vm-gammel singular of 'old'
181 \arg \b vm-gamle plural of 'old'
189 Italian requires the following additional soundfile:
193 \arg \b vm-nuovi new plural
194 \arg \b vm-vecchio old
195 \arg \b vm-vecchi old plural
197 \note Don't use vm-INBOX or vm-Old, because they are the name of the INBOX and Old folders,
198 spelled among others when you have to change folder. For the above reasons, vm-INBOX
199 and vm-Old are spelled plural, to make them sound more as folder name than an adjective.
208 unsigned char iobuf[BASEMAXINLINE];
211 /*! Structure for linked list of users */
213 char context[AST_MAX_CONTEXT]; /*!< Voicemail context */
214 char mailbox[AST_MAX_EXTENSION];/*!< Mailbox id, unique within vm context */
215 char password[80]; /*!< Secret pin code, numbers only */
216 char fullname[80]; /*!< Full name, for directory app */
217 char email[80]; /*!< E-mail address */
218 char pager[80]; /*!< E-mail address to pager (no attachment) */
219 char serveremail[80]; /*!< From: Mail address */
220 char mailcmd[160]; /*!< Configurable mail command */
221 char language[MAX_LANGUAGE]; /*!< Config: Language setting */
222 char zonetag[80]; /*!< Time zone */
225 char uniqueid[20]; /*!< Unique integer identifier */
227 unsigned int flags; /*!< VM_ flags */
229 int maxmsg; /*!< Maximum number of msgs per folder for this mailbox */
230 struct ast_vm_user *next;
236 char msg_format[512];
237 struct vm_zone *next;
256 static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg,
257 int option, signed char record_gain);
258 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
259 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime,
260 char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir,
261 signed char record_gain);
262 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain);
263 static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
265 static void apply_options(struct ast_vm_user *vmu, const char *options);
267 #ifdef USE_ODBC_STORAGE
268 static char odbc_database[80];
269 static char odbc_table[80];
270 #define RETRIEVE(a,b) retrieve_file(a,b)
271 #define DISPOSE(a,b) remove_file(a,b)
272 #define STORE(a,b,c,d) store_file(a,b,c,d)
273 #define EXISTS(a,b,c,d) (message_exists(a,b))
274 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(a,b,c,d,e,f))
275 #define COPY(a,b,c,d,e,f,g,h) (copy_file(a,b,c,d,e,f))
276 #define DELETE(a,b,c) (delete_file(a,b))
278 #define RETRIEVE(a,b)
280 #define STORE(a,b,c,d)
281 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
282 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
283 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
284 #define DELETE(a,b,c) (vm_delete(c))
287 static char VM_SPOOL_DIR[AST_CONFIG_MAX_PATH];
289 static char ext_pass_cmd[128];
291 static char *tdesc = "Comedian Mail (Voicemail System)";
293 static char *addesc = "Comedian Mail";
295 static char *synopsis_vm =
296 "Leave a Voicemail message";
298 static char *descrip_vm =
299 " VoiceMail(mailbox[@context][&mailbox[@context]][...][|options]): This\n"
300 "application allows the calling party to leave a message for the specified\n"
301 "list of mailboxes. When multiple mailboxes are specified, the greeting will\n"
302 "be taken from the first mailbox specified. Dialplan execution will stop if the\n"
303 "specified mailbox does not exist.\n"
304 " The Voicemail application will exit if any of the following DTMF digits are\n"
306 " 0 - Jump to the 'o' extension in the current dialplan context.\n"
307 " * - Jump to the 'a' extension in the current dialplan context.\n"
308 " This application will set the following channel variable upon completion:\n"
309 " VMSTATUS - This indicates the status of the execution of the VoiceMail\n"
310 " application. The possible values are:\n"
311 " SUCCESS | USEREXIT | FAILED\n\n"
313 " b - Play the 'busy' greeting to the calling party.\n"
314 " g(#) - Use the specified amount of gain when recording the voicemail\n"
315 " message. The units are whole-number decibels (dB).\n"
316 " s - Skip the playback of instructions for leaving a message to the\n"
318 " u - Play the 'unavailble greeting.\n"
319 " j - Jump to priority n+101 if the mailbox is not found or some other\n"
322 static char *synopsis_vmain =
323 "Check Voicemail messages";
325 static char *descrip_vmain =
326 " VoiceMailMain([mailbox][@context][|options]): This application allows the\n"
327 "calling party to check voicemail messages. A specific mailbox, and optional\n"
328 "corresponding context, may be specified. If a mailbox is not provided, the\n"
329 "calling party will be prompted to enter one. If a context is not specified,\n"
330 "the 'default' context will be used.\n\n"
332 " p - Consider the mailbox parameter as a prefix to the mailbox that\n"
333 " is entered by the caller.\n"
334 " g(#) - Use the specified amount of gain when recording a voicemail\n"
335 " message. The units are whole-number decibels (dB).\n"
336 " s - Skip checking the passcode for the mailbox.\n";
338 static char *synopsis_vm_box_exists =
339 "Check to see if Voicemail mailbox exists";
341 static char *descrip_vm_box_exists =
342 " MailboxExists(mailbox[@context][|options]): Check to see if the specified\n"
343 "mailbox exists. If no voicemail context is specified, the 'default' context\n"
345 " This application will set the following channel variable upon completion:\n"
346 " VMBOXEXISTSSTATUS - This will contain the status of the execution of the\n"
347 " MailboxExists application. Possible values include:\n"
348 " SUCCESS | FAILED\n\n"
350 " j - Jump to priority n+101 if the mailbox is found.\n";
352 static char *synopsis_vmauthenticate =
353 "Authenticate with Voicemail passwords";
355 static char *descrip_vmauthenticate =
356 " VMAuthenticate([mailbox][@context][|options]): This application behaves the\n"
357 "same way as the Authenticate application, but the passwords are taken from\n"
359 " If the mailbox is specified, only that mailbox's password will be considered\n"
360 "valid. If the mailbox is not specified, the channel variable AUTH_MAILBOX will\n"
361 "be set with the authenticated mailbox.\n\n"
363 " s - Skip playing the initial prompts.\n";
365 /* Leave a message */
366 static char *app = "VoiceMail";
368 /* Check mail, control, etc */
369 static char *app2 = "VoiceMailMain";
371 static char *app3 = "MailboxExists";
372 static char *app4 = "VMAuthenticate";
374 AST_MUTEX_DEFINE_STATIC(vmlock);
375 struct ast_vm_user *users;
376 struct ast_vm_user *usersl;
377 struct vm_zone *zones = NULL;
378 struct vm_zone *zonesl = NULL;
379 static int maxsilence;
381 static int silencethreshold = 128;
382 static char serveremail[80];
383 static char mailcmd[160]; /* Configurable mail cmd */
384 static char externnotify[160];
386 static char vmfmts[80];
387 static int vmminmessage;
388 static int vmmaxmessage;
391 static int maxlogins;
393 static struct ast_flags globalflags = {0};
395 static int saydurationminfo;
397 static char dialcontext[AST_MAX_CONTEXT];
398 static char callcontext[AST_MAX_CONTEXT];
399 static char exitcontext[AST_MAX_CONTEXT];
401 static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
404 static char *emailbody = NULL;
405 static char *emailsubject = NULL;
406 static char *pagerbody = NULL;
407 static char *pagersubject = NULL;
408 static char fromstring[100];
409 static char pagerfromstring[100];
410 static char emailtitle[100];
411 static char charset[32] = "ISO-8859-1";
413 static unsigned char adsifdn[4] = "\x00\x00\x00\x0F";
414 static unsigned char adsisec[4] = "\x9B\xDB\xF7\xAC";
415 static int adsiver = 1;
416 static char emaildateformat[32] = "%A, %B %d, %Y at %r";
422 static void populate_defaults(struct ast_vm_user *vmu)
424 ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
425 if (saydurationminfo)
426 vmu->saydurationm = saydurationminfo;
428 ast_copy_string(vmu->callback, callcontext, sizeof(vmu->callback));
430 ast_copy_string(vmu->dialout, dialcontext, sizeof(vmu->dialout));
432 ast_copy_string(vmu->exit, exitcontext, sizeof(vmu->exit));
434 vmu->maxmsg = maxmsg;
437 static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
440 if (!strcasecmp(var, "attach")) {
441 ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
442 } else if (!strcasecmp(var, "serveremail")) {
443 ast_copy_string(vmu->serveremail, value, sizeof(vmu->serveremail));
444 } else if (!strcasecmp(var, "language")) {
445 ast_copy_string(vmu->language, value, sizeof(vmu->language));
446 } else if (!strcasecmp(var, "tz")) {
447 ast_copy_string(vmu->zonetag, value, sizeof(vmu->zonetag));
448 } else if (!strcasecmp(var, "delete")) {
449 ast_set2_flag(vmu, ast_true(value), VM_DELETE);
450 } else if (!strcasecmp(var, "saycid")){
451 ast_set2_flag(vmu, ast_true(value), VM_SAYCID);
452 } else if (!strcasecmp(var,"sendvoicemail")){
453 ast_set2_flag(vmu, ast_true(value), VM_SVMAIL);
454 } else if (!strcasecmp(var, "review")){
455 ast_set2_flag(vmu, ast_true(value), VM_REVIEW);
456 } else if (!strcasecmp(var, "operator")){
457 ast_set2_flag(vmu, ast_true(value), VM_OPERATOR);
458 } else if (!strcasecmp(var, "envelope")){
459 ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE);
460 } else if (!strcasecmp(var, "sayduration")){
461 ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION);
462 } else if (!strcasecmp(var, "saydurationm")){
463 if (sscanf(value, "%d", &x) == 1) {
464 vmu->saydurationm = x;
466 ast_log(LOG_WARNING, "Invalid min duration for say duration\n");
468 } else if (!strcasecmp(var, "forcename")){
469 ast_set2_flag(vmu, ast_true(value), VM_FORCENAME);
470 } else if (!strcasecmp(var, "forcegreetings")){
471 ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET);
472 } else if (!strcasecmp(var, "callback")) {
473 ast_copy_string(vmu->callback, value, sizeof(vmu->callback));
474 } else if (!strcasecmp(var, "dialout")) {
475 ast_copy_string(vmu->dialout, value, sizeof(vmu->dialout));
476 } else if (!strcasecmp(var, "exitcontext")) {
477 ast_copy_string(vmu->exit, value, sizeof(vmu->exit));
478 } else if (!strcasecmp(var, "maxmsg")) {
479 vmu->maxmsg = atoi(value);
480 if (vmu->maxmsg <= 0) {
481 ast_log(LOG_WARNING, "Invalid number of messages per folder maxmsg=%s. Using default value %i\n", value, MAXMSG);
482 vmu->maxmsg = MAXMSG;
483 } else if (vmu->maxmsg > MAXMSGLIMIT) {
484 ast_log(LOG_WARNING, "Maximum number of messages per folder is %i. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
485 vmu->maxmsg = MAXMSGLIMIT;
487 } else if (!strcasecmp(var, "options")) {
488 apply_options(vmu, value);
492 static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
495 if (!ast_strlen_zero(vmu->uniqueid)) {
496 res = ast_update_realtime("voicemail", "uniqueid", vmu->uniqueid, "password", password, NULL);
498 ast_copy_string(vmu->password, password, sizeof(vmu->password));
508 static void apply_options(struct ast_vm_user *vmu, const char *options)
509 { /* Destructively Parse options and apply */
513 stringp = ast_strdupa(options);
514 while ((s = strsep(&stringp, "|"))) {
516 if ((var = strsep(&value, "=")) && value) {
517 apply_option(vmu, var, value);
522 static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
524 struct ast_variable *var, *tmp;
525 struct ast_vm_user *retval;
530 retval=malloc(sizeof(struct ast_vm_user));
533 memset(retval, 0, sizeof(struct ast_vm_user));
535 ast_set_flag(retval, VM_ALLOCED);
537 ast_copy_string(retval->mailbox, mailbox, sizeof(retval->mailbox));
538 populate_defaults(retval);
539 if (ast_test_flag((&globalflags), VM_SEARCH))
540 var = ast_load_realtime("voicemail", "mailbox", mailbox, NULL);
542 var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", retval->context, NULL);
546 printf("%s => %s\n", tmp->name, tmp->value);
547 if (!strcasecmp(tmp->name, "password")) {
548 ast_copy_string(retval->password, tmp->value, sizeof(retval->password));
549 } else if (!strcasecmp(tmp->name, "uniqueid")) {
550 ast_copy_string(retval->uniqueid, tmp->value, sizeof(retval->uniqueid));
551 } else if (!strcasecmp(tmp->name, "pager")) {
552 ast_copy_string(retval->pager, tmp->value, sizeof(retval->pager));
553 } else if (!strcasecmp(tmp->name, "email")) {
554 ast_copy_string(retval->email, tmp->value, sizeof(retval->email));
555 } else if (!strcasecmp(tmp->name, "fullname")) {
556 ast_copy_string(retval->fullname, tmp->value, sizeof(retval->fullname));
557 } else if (!strcasecmp(tmp->name, "context")) {
558 ast_copy_string(retval->context, tmp->value, sizeof(retval->context));
560 apply_option(retval, tmp->name, tmp->value);
572 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
574 /* This function could be made to generate one from a database, too */
575 struct ast_vm_user *vmu=NULL, *cur;
576 ast_mutex_lock(&vmlock);
579 if (!context && !ast_test_flag((&globalflags), VM_SEARCH))
583 if (ast_test_flag((&globalflags), VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
585 if ((!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
593 /* Make a copy, so that on a reload, we have no race */
594 vmu = malloc(sizeof(struct ast_vm_user));
596 memcpy(vmu, cur, sizeof(struct ast_vm_user));
597 ast_set2_flag(vmu, !ivm, VM_ALLOCED);
601 vmu = find_user_realtime(ivm, context, mailbox);
602 ast_mutex_unlock(&vmlock);
606 static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
608 /* This function could be made to generate one from a database, too */
609 struct ast_vm_user *cur;
611 ast_mutex_lock(&vmlock);
614 if ((!context || !strcasecmp(context, cur->context)) &&
615 (!strcasecmp(mailbox, cur->mailbox)))
620 ast_copy_string(cur->password, newpass, sizeof(cur->password));
623 ast_mutex_unlock(&vmlock);
627 static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
629 /* There's probably a better way of doing this. */
630 /* That's why I've put the password change in a separate function. */
631 /* This could also be done with a database function */
638 char currcontext[256] ="";
639 char tmpin[AST_CONFIG_MAX_PATH];
640 char tmpout[AST_CONFIG_MAX_PATH];
643 if (!change_password_realtime(vmu, newpassword))
646 snprintf(tmpin, sizeof(tmpin), "%s/voicemail.conf", ast_config_AST_CONFIG_DIR);
647 snprintf(tmpout, sizeof(tmpout), "%s/voicemail.conf.new", ast_config_AST_CONFIG_DIR);
648 configin = fopen(tmpin,"r");
650 configout = fopen(tmpout,"w+");
653 if (!configin || !configout) {
657 ast_log(LOG_WARNING, "Warning: Unable to open '%s' for reading: %s\n", tmpin, strerror(errno));
661 ast_log(LOG_WARNING, "Warning: Unable to open '%s' for writing: %s\n", tmpout, strerror(errno));
665 while (!feof(configin)) {
666 char *user = NULL, *pass = NULL, *rest = NULL, *comment = NULL, *tmpctx = NULL, *tmpctxend = NULL;
668 /* Read in the line */
669 fgets(inbuf, sizeof(inbuf), configin);
672 if (ast_strlen_zero(inbuf)) {
673 fprintf(configout, "\n");
677 /* Make a backup of it */
678 ast_copy_string(orig, inbuf, sizeof(orig));
681 Read the file line by line, split each line into a comment and command section
682 only parse the command portion of the line
684 if (inbuf[strlen(inbuf) - 1] == '\n')
685 inbuf[strlen(inbuf) - 1] = '\0';
687 if ((comment = strchr(inbuf, ';')))
688 *comment++ = '\0'; /* Now inbuf is terminated just before the comment */
690 if (ast_strlen_zero(inbuf)) {
691 fprintf(configout, "%s", orig);
695 /* Check for a context, first '[' to first ']' */
696 if ((tmpctx = strchr(inbuf, '['))) {
697 tmpctxend = strchr(tmpctx, ']');
700 ast_copy_string(currcontext, tmpctx + 1, tmpctxend - tmpctx);
701 fprintf(configout, "%s", orig);
706 /* This isn't a context line, check for MBX => PSWD... */
708 if ((pass = strchr(user, '='))) {
709 /* We have a line in the form of aaaaa=aaaaaa */
712 user = ast_strip(user);
717 pass = ast_skip_blanks(pass);
720 Since no whitespace allowed in fields, or more correctly white space
721 inside the fields is there for a purpose, we can just terminate pass
722 at the comma or EOL whichever comes first.
724 if ((rest = strchr(pass, ',')))
730 /* Compare user, pass AND context */
731 if (!ast_strlen_zero(user) && !strcmp(user, vmu->mailbox) &&
732 !ast_strlen_zero(pass) && !strcmp(pass, vmu->password) &&
733 !strcasecmp(currcontext, vmu->context)) {
734 /* This is the line */
736 fprintf(configout, "%s => %s,%s", user, newpassword, rest);
738 fprintf(configout, "%s => %s", user, newpassword);
740 /* If there was a comment on the line print it out */
742 fprintf(configout, ";%s\n", comment);
744 fprintf(configout, "\n");
747 /* Put it back like it was */
748 fprintf(configout, "%s", orig);
754 stat(tmpin, &statbuf);
755 chmod(tmpout, statbuf.st_mode);
756 chown(tmpout, statbuf.st_uid, statbuf.st_gid);
758 rename(tmpout, tmpin);
759 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
760 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
763 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
766 snprintf(buf,255,"%s %s %s %s",ext_pass_cmd,vmu->context,vmu->mailbox,newpassword);
767 if (!ast_safe_system(buf))
768 ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
771 static int make_dir(char *dest, int len, char *context, char *ext, char *mailbox)
773 return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, mailbox);
776 static int make_file(char *dest, int len, char *dir, int num)
778 return snprintf(dest, len, "%s/msg%04d", dir, num);
781 /* only return failure if ast_lock_path returns 'timeout',
782 not if the path does not exist or any other reason
784 static int vm_lock_path(const char *path)
786 switch (ast_lock_path(path)) {
787 case AST_LOCK_TIMEOUT:
795 #ifdef USE_ODBC_STORAGE
796 static int retrieve_file(char *dir, int msgnum)
803 SQLSMALLINT colcount=0;
810 SQLSMALLINT datatype;
811 SQLSMALLINT decimaldigits;
812 SQLSMALLINT nullable;
821 obj = fetch_odbc_obj(odbc_database, 0);
823 ast_copy_string(fmt, vmfmts, sizeof(fmt));
824 c = strchr(fmt, '|');
827 if (!strcasecmp(fmt, "wav49"))
829 snprintf(msgnums, sizeof(msgnums),"%d", msgnum);
831 make_file(fn, sizeof(fn), dir, msgnum);
833 ast_copy_string(fn, dir, sizeof(fn));
834 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
835 f = fopen(full_fn, "w+");
836 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
837 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
838 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
839 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
842 snprintf(sql, sizeof(sql), "SELECT * FROM %s WHERE dir=? AND msgnum=?",odbc_table);
843 res = SQLPrepare(stmt, sql, SQL_NTS);
844 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
845 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
846 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
849 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(dir), 0, (void *)dir, 0, NULL);
850 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(msgnums), 0, (void *)msgnums, 0, NULL);
851 res = odbc_smart_execute(obj, stmt);
852 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
853 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
854 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
857 res = SQLFetch(stmt);
858 if (res == SQL_NO_DATA) {
859 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
862 else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
863 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
864 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
867 fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC);
869 ast_log(LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
870 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
873 res = SQLNumResultCols(stmt, &colcount);
874 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
875 ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
876 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
880 fprintf(f, "[message]\n");
881 for (x=0;x<colcount;x++) {
883 collen = sizeof(coltitle);
884 res = SQLDescribeCol(stmt, x + 1, coltitle, sizeof(coltitle), &collen,
885 &datatype, &colsize, &decimaldigits, &nullable);
886 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
887 ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
888 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
891 if (!strcasecmp(coltitle, "recording")) {
892 res = SQLGetData(stmt, x + 1, SQL_BINARY, NULL, 0, &colsize);
894 fd = open(full_fn, O_RDWR | O_TRUNC | O_CREAT, 0770);
897 lseek(fd, fdlen - 1, SEEK_SET);
898 if (write(fd, tmp, 1) != 1) {
903 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
906 memset(fdm, 0, fdlen);
907 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, fdlen, &colsize);
908 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
909 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
910 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
915 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
916 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
917 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
918 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
921 if (strcasecmp(coltitle, "msgnum") && strcasecmp(coltitle, "dir") && f)
922 fprintf(f, "%s=%s\n", coltitle, rowdata);
925 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
927 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
938 static int remove_file(char *dir, int msgnum)
945 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
946 make_file(fn, sizeof(fn), dir, msgnum);
948 ast_copy_string(fn, dir, sizeof(fn));
949 ast_filedelete(fn, NULL);
950 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
955 static int last_message_index(struct ast_vm_user *vmu, char *dir)
964 obj = fetch_odbc_obj(odbc_database, 0);
966 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
967 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
968 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
971 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=?",odbc_table);
972 res = SQLPrepare(stmt, sql, SQL_NTS);
973 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
974 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
975 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
978 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(dir), 0, (void *)dir, 0, NULL);
979 res = odbc_smart_execute(obj, stmt);
980 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
981 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
982 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
985 res = SQLFetch(stmt);
986 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
987 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
988 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
991 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
992 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
993 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
994 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
997 if (sscanf(rowdata, "%d", &x) != 1)
998 ast_log(LOG_WARNING, "Failed to read message count!\n");
999 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1001 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
1006 static int message_exists(char *dir, int msgnum)
1016 obj = fetch_odbc_obj(odbc_database, 0);
1018 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
1019 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
1020 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1021 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
1024 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?",odbc_table);
1025 res = SQLPrepare(stmt, sql, SQL_NTS);
1026 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1027 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
1028 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1031 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(dir), 0, (void *)dir, 0, NULL);
1032 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(msgnums), 0, (void *)msgnums, 0, NULL);
1033 res = odbc_smart_execute(obj, stmt);
1034 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1035 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
1036 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1039 res = SQLFetch(stmt);
1040 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1041 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
1042 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1045 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
1046 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1047 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
1048 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1051 if (sscanf(rowdata, "%d", &x) != 1)
1052 ast_log(LOG_WARNING, "Failed to read message count!\n");
1053 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1055 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
1060 static int count_messages(struct ast_vm_user *vmu, char *dir)
1062 return last_message_index(vmu, dir) + 1;
1065 static void delete_file(char *sdir, int smsg)
1073 obj = fetch_odbc_obj(odbc_database, 0);
1075 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
1076 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
1077 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1078 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
1081 snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE dir=? AND msgnum=?",odbc_table);
1082 res = SQLPrepare(stmt, sql, SQL_NTS);
1083 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1084 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
1085 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1088 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(sdir), 0, (void *)sdir, 0, NULL);
1089 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(msgnums), 0, (void *)msgnums, 0, NULL);
1090 res = odbc_smart_execute(obj, stmt);
1091 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1092 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
1093 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1096 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1098 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
1103 static void copy_file(char *sdir, int smsg, char *ddir, int dmsg, char *dmailboxuser, char *dmailboxcontext)
1112 delete_file(ddir, dmsg);
1113 obj = fetch_odbc_obj(odbc_database, 0);
1115 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
1116 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
1117 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
1118 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1119 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
1122 #ifdef EXTENDED_ODBC_STORAGE
1123 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir, msgnum, context, macrocontext, callerid, origtime, duration, recording, mailboxuser, mailboxcontext) SELECT ?,?,context,macrocontext,callerid,origtime,duration,recording,?,? FROM %s WHERE dir=? AND msgnum=?",odbc_table,odbc_table);
1125 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir, msgnum, context, macrocontext, callerid, origtime, duration, recording) SELECT ?,?,context,macrocontext,callerid,origtime,duration,recording FROM %s WHERE dir=? AND msgnum=?",odbc_table,odbc_table);
1127 res = SQLPrepare(stmt, sql, SQL_NTS);
1128 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1129 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
1130 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1133 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(ddir), 0, (void *)ddir, 0, NULL);
1134 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(msgnumd), 0, (void *)msgnumd, 0, NULL);
1135 #ifdef EXTENDED_ODBC_STORAGE
1136 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(dmailboxuser), 0, (void *)dmailboxuser, 0, NULL);
1137 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(dmailboxcontext), 0, (void *)dmailboxcontext, 0, NULL);
1138 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(sdir), 0, (void *)sdir, 0, NULL);
1139 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(msgnums), 0, (void *)msgnums, 0, NULL);
1141 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(sdir), 0, (void *)sdir, 0, NULL);
1142 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(msgnums), 0, (void *)msgnums, 0, NULL);
1144 res = odbc_smart_execute(obj, stmt);
1145 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1146 ast_log(LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
1147 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1150 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1152 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
1157 static int store_file(char *dir, char *mailboxuser, char *mailboxcontext, int msgnum)
1172 char *context="", *macrocontext="", *callerid="", *origtime="", *duration="";
1173 char *category = "";
1174 struct ast_config *cfg=NULL;
1177 delete_file(dir, msgnum);
1178 obj = fetch_odbc_obj(odbc_database, 0);
1180 ast_copy_string(fmt, vmfmts, sizeof(fmt));
1181 c = strchr(fmt, '|');
1184 if (!strcasecmp(fmt, "wav49"))
1186 snprintf(msgnums, sizeof(msgnums),"%d", msgnum);
1188 make_file(fn, sizeof(fn), dir, msgnum);
1190 ast_copy_string(fn, dir, sizeof(fn));
1191 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
1192 cfg = ast_config_load(full_fn);
1193 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
1194 fd = open(full_fn, O_RDWR);
1196 ast_log(LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno));
1200 context = ast_variable_retrieve(cfg, "message", "context");
1201 if (!context) context = "";
1202 macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext");
1203 if (!macrocontext) macrocontext = "";
1204 callerid = ast_variable_retrieve(cfg, "message", "callerid");
1205 if (!callerid) callerid = "";
1206 origtime = ast_variable_retrieve(cfg, "message", "origtime");
1207 if (!origtime) origtime = "";
1208 duration = ast_variable_retrieve(cfg, "message", "duration");
1209 if (!duration) duration = "";
1210 category = ast_variable_retrieve(cfg, "message", "category");
1211 if (!category) category = "";
1213 fdlen = lseek(fd, 0, SEEK_END);
1214 lseek(fd, 0, SEEK_SET);
1215 printf("Length is %d\n", fdlen);
1216 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED,fd, 0);
1218 ast_log(LOG_WARNING, "Memory map failed!\n");
1221 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
1222 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1223 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
1226 if (!ast_strlen_zero(category))
1227 #ifdef EXTENDED_ODBC_STORAGE
1228 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,category) VALUES (?,?,?,?,?,?,?,?,?,?,?)",odbc_table);
1230 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,category) VALUES (?,?,?,?,?,?,?,?,?)",odbc_table);
1233 #ifdef EXTENDED_ODBC_STORAGE
1234 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext) VALUES (?,?,?,?,?,?,?,?,?,?)",odbc_table);
1236 snprintf(sql, sizeof(sql), "INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration) VALUES (?,?,?,?,?,?,?,?)",odbc_table);
1238 res = SQLPrepare(stmt, sql, SQL_NTS);
1239 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1240 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
1241 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1244 len = fdlen; /* SQL_LEN_DATA_AT_EXEC(fdlen); */
1245 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(dir), 0, (void *)dir, 0, NULL);
1246 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(msgnums), 0, (void *)msgnums, 0, NULL);
1247 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_BINARY, fdlen, 0, (void *)fdm, fdlen, &len);
1248 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(context), 0, (void *)context, 0, NULL);
1249 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(macrocontext), 0, (void *)macrocontext, 0, NULL);
1250 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(callerid), 0, (void *)callerid, 0, NULL);
1251 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(origtime), 0, (void *)origtime, 0, NULL);
1252 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(duration), 0, (void *)duration, 0, NULL);
1253 #ifdef EXTENDED_ODBC_STORAGE
1254 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(mailboxuser), 0, (void *)mailboxuser, 0, NULL);
1255 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(mailboxcontext), 0, (void *)mailboxcontext, 0, NULL);
1256 if (!ast_strlen_zero(category))
1257 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(category), 0, (void *)category, 0, NULL);
1259 if (!ast_strlen_zero(category))
1260 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(category), 0, (void *)category, 0, NULL);
1262 res = odbc_smart_execute(obj, stmt);
1263 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1264 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
1265 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1268 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1270 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
1273 ast_config_destroy(cfg);
1281 static void rename_file(char *sdir, int smsg, char *mailboxuser, char *mailboxcontext, char *ddir, int dmsg)
1290 delete_file(ddir, dmsg);
1291 obj = fetch_odbc_obj(odbc_database, 0);
1293 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
1294 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
1295 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
1296 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1297 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
1300 #ifdef EXTENDED_ODBC_STORAGE
1301 snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?",odbc_table);
1303 snprintf(sql, sizeof(sql), "UPDATE %s SET dir=?, msgnum=? WHERE dir=? AND msgnum=?",odbc_table);
1305 res = SQLPrepare(stmt, sql, SQL_NTS);
1306 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1307 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
1308 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1311 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(ddir), 0, (void *)ddir, 0, NULL);
1312 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(msgnumd), 0, (void *)msgnumd, 0, NULL);
1313 #ifdef EXTENDED_ODBC_STORAGE
1314 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(mailboxuser), 0, (void *)mailboxuser, 0, NULL);
1315 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(mailboxcontext), 0, (void *)mailboxcontext, 0, NULL);
1316 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(sdir), 0, (void *)sdir, 0, NULL);
1317 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(msgnums), 0, (void *)msgnums, 0, NULL);
1319 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(sdir), 0, (void *)sdir, 0, NULL);
1320 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(msgnums), 0, (void *)msgnums, 0, NULL);
1322 res = odbc_smart_execute(obj, stmt);
1323 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1324 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
1325 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1328 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1330 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
1337 static int count_messages(struct ast_vm_user *vmu, char *dir)
1339 /* Find all .txt files - even if they are not in sequence from 0000 */
1343 struct dirent *vment = NULL;
1345 if (vm_lock_path(dir))
1346 return ERROR_LOCK_PATH;
1348 if ((vmdir = opendir(dir))) {
1349 while ((vment = readdir(vmdir))) {
1350 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7, ".txt", 4))
1355 ast_unlock_path(dir);
1360 static void rename_file(char *sfn, char *dfn)
1364 ast_filerename(sfn,dfn,NULL);
1365 snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
1366 snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
1370 static int copy(char *infile, char *outfile)
1378 #ifdef HARDLINK_WHEN_POSSIBLE
1379 /* Hard link if possible; saves disk space & is faster */
1380 if (link(infile, outfile)) {
1382 if ((ifd = open(infile, O_RDONLY)) < 0) {
1383 ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
1386 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) {
1387 ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
1392 len = read(ifd, buf, sizeof(buf));
1394 ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
1400 res = write(ofd, buf, len);
1401 if (errno == ENOMEM || errno == ENOSPC || res != len) {
1402 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
1412 #ifdef HARDLINK_WHEN_POSSIBLE
1414 /* Hard link succeeded */
1420 static void copy_file(char *frompath, char *topath)
1422 char frompath2[256],topath2[256];
1423 ast_filecopy(frompath, topath, NULL);
1424 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
1425 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
1426 copy(frompath2, topath2);
1430 * A negative return value indicates an error.
1432 static int last_message_index(struct ast_vm_user *vmu, char *dir)
1437 if (vm_lock_path(dir))
1438 return ERROR_LOCK_PATH;
1440 for (x = 0; x < vmu->maxmsg; x++) {
1441 make_file(fn, sizeof(fn), dir, x);
1442 if (ast_fileexists(fn, NULL, NULL) < 1)
1445 ast_unlock_path(dir);
1450 static int vm_delete(char *file)
1455 txtsize = (strlen(file) + 5)*sizeof(char);
1456 txt = (char *)alloca(txtsize);
1457 /* Sprintf here would safe because we alloca'd exactly the right length,
1458 * but trying to eliminate all sprintf's anyhow
1460 snprintf(txt, txtsize, "%s.txt", file);
1462 return ast_filedelete(file, NULL);
1468 inbuf(struct baseio *bio, FILE *fi)
1475 if ((l = fread(bio->iobuf,1,BASEMAXINLINE,fi)) <= 0) {
1490 inchar(struct baseio *bio, FILE *fi)
1492 if (bio->iocp>=bio->iolen) {
1493 if (!inbuf(bio, fi))
1497 return bio->iobuf[bio->iocp++];
1501 ochar(struct baseio *bio, int c, FILE *so)
1503 if (bio->linelength>=BASELINELEN) {
1504 if (fputs(eol,so)==EOF)
1510 if (putc(((unsigned char)c),so)==EOF)
1518 static int base_encode(char *filename, FILE *so)
1520 unsigned char dtable[BASEMAXINLINE];
1525 memset(&bio, 0, sizeof(bio));
1526 bio.iocp = BASEMAXINLINE;
1528 if (!(fi = fopen(filename, "rb"))) {
1529 ast_log(LOG_WARNING, "Failed to open log file: %s: %s\n", filename, strerror(errno));
1533 for (i= 0;i<9;i++) {
1536 dtable[26+i]= 'a'+i;
1537 dtable[26+i+9]= 'j'+i;
1539 for (i= 0;i<8;i++) {
1540 dtable[i+18]= 'S'+i;
1541 dtable[26+i+18]= 's'+i;
1543 for (i= 0;i<10;i++) {
1544 dtable[52+i]= '0'+i;
1550 unsigned char igroup[3],ogroup[4];
1553 igroup[0]= igroup[1]= igroup[2]= 0;
1555 for (n= 0;n<3;n++) {
1556 if ((c = inchar(&bio, fi)) == EOF) {
1561 igroup[n]= (unsigned char)c;
1565 ogroup[0]= dtable[igroup[0]>>2];
1566 ogroup[1]= dtable[((igroup[0]&3)<<4)|(igroup[1]>>4)];
1567 ogroup[2]= dtable[((igroup[1]&0xF)<<2)|(igroup[2]>>6)];
1568 ogroup[3]= dtable[igroup[2]&0x3F];
1578 ochar(&bio, ogroup[i], so);
1582 if (fputs(eol,so)==EOF)
1590 static void prep_email_sub_vars(struct ast_channel *ast, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, char *cidnum, char *cidname, char *dur, char *date, char *passdata, size_t passdatasize)
1593 /* Prepare variables for substition in email body and subject */
1594 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
1595 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
1596 snprintf(passdata, passdatasize, "%d", msgnum);
1597 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", passdata);
1598 pbx_builtin_setvar_helper(ast, "VM_CONTEXT", context);
1599 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
1600 pbx_builtin_setvar_helper(ast, "VM_CALLERID", ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, "Unknown Caller"));
1601 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (cidname ? cidname : "an unknown caller"));
1602 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (cidnum ? cidnum : "an unknown caller"));
1603 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
1606 static int sendmail(char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, char *cidnum, char *cidname, char *attach, char *format, int duration, int attach_user_voicemail)
1611 char host[MAXHOSTNAMELEN] = "";
1616 char tmp[80] = "/tmp/astmail-XXXXXX";
1620 struct vm_zone *the_zone = NULL;
1621 if (vmu && ast_strlen_zero(vmu->email)) {
1622 ast_log(LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
1625 if (!strcmp(format, "wav49"))
1627 ast_log(LOG_DEBUG, "Attaching file '%s', format '%s', uservm is '%d', global is %d\n", attach, format, attach_user_voicemail, ast_test_flag((&globalflags), VM_ATTACH));
1628 /* Make a temporary file instead of piping directly to sendmail, in case the mail
1632 p = fdopen(pfd, "w");
1639 gethostname(host, sizeof(host)-1);
1640 if (strchr(srcemail, '@'))
1641 ast_copy_string(who, srcemail, sizeof(who));
1643 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
1645 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
1648 /* Does this user have a timezone specified? */
1649 if (!ast_strlen_zero(vmu->zonetag)) {
1650 /* Find the zone in the list */
1654 if (!strcmp(z->name, vmu->zonetag)) {
1663 ast_localtime(&t,&tm,the_zone->timezone);
1665 ast_localtime(&t,&tm,NULL);
1666 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", &tm);
1667 fprintf(p, "Date: %s\n", date);
1669 /* Set date format for voicemail mail */
1670 strftime(date, sizeof(date), emaildateformat, &tm);
1673 struct ast_channel *ast = ast_channel_alloc(0);
1676 int vmlen = strlen(fromstring)*3 + 200;
1677 if ((passdata = alloca(vmlen))) {
1678 memset(passdata, 0, vmlen);
1679 prep_email_sub_vars(ast,vmu,msgnum + 1,context,mailbox,cidnum, cidname,dur,date,passdata, vmlen);
1680 pbx_substitute_variables_helper(ast,fromstring,passdata,vmlen);
1681 fprintf(p, "From: %s <%s>\n",passdata,who);
1682 } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
1683 ast_channel_free(ast);
1684 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
1686 fprintf(p, "From: Asterisk PBX <%s>\n", who);
1687 fprintf(p, "To: %s <%s>\n", vmu->fullname, vmu->email);
1690 struct ast_channel *ast = ast_channel_alloc(0);
1693 int vmlen = strlen(emailsubject)*3 + 200;
1694 if ((passdata = alloca(vmlen))) {
1695 memset(passdata, 0, vmlen);
1696 prep_email_sub_vars(ast,vmu,msgnum + 1,context,mailbox,cidnum, cidname,dur,date,passdata, vmlen);
1697 pbx_substitute_variables_helper(ast,emailsubject,passdata,vmlen);
1698 fprintf(p, "Subject: %s\n",passdata);
1699 } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
1700 ast_channel_free(ast);
1701 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
1704 fprintf(p, emailtitle, msgnum + 1, mailbox) ;
1706 } else if (ast_test_flag((&globalflags), VM_PBXSKIP))
1707 fprintf(p, "Subject: New message %d in mailbox %s\n", msgnum + 1, mailbox);
1709 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s\n", msgnum + 1, mailbox);
1710 fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>\n", msgnum, (unsigned int)rand(), mailbox, getpid(), host);
1711 fprintf(p, "MIME-Version: 1.0\n");
1712 if (attach_user_voicemail) {
1713 /* Something unique. */
1714 snprintf(bound, sizeof(bound), "voicemail_%d%s%d%d", msgnum, mailbox, getpid(), (unsigned int)rand());
1716 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"\n\n\n", bound);
1718 fprintf(p, "--%s\n", bound);
1720 fprintf(p, "Content-Type: text/plain; charset=%s\nContent-Transfer-Encoding: 8bit\n\n", charset);
1722 struct ast_channel *ast = ast_channel_alloc(0);
1725 int vmlen = strlen(emailbody)*3 + 200;
1726 if ((passdata = alloca(vmlen))) {
1727 memset(passdata, 0, vmlen);
1728 prep_email_sub_vars(ast,vmu,msgnum + 1,context,mailbox,cidnum, cidname,dur,date,passdata, vmlen);
1729 pbx_substitute_variables_helper(ast,emailbody,passdata,vmlen);
1730 fprintf(p, "%s\n",passdata);
1731 } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
1732 ast_channel_free(ast);
1733 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
1735 fprintf(p, "Dear %s:\n\n\tJust wanted to let you know you were just left a %s long message (number %d)\n"
1737 "in mailbox %s from %s, on %s so you might\n"
1738 "want to check it when you get a chance. Thanks!\n\n\t\t\t\t--Asterisk\n\n", vmu->fullname,
1739 dur, msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
1741 if (attach_user_voicemail) {
1742 /* Eww. We want formats to tell us their own MIME type */
1743 char *ctype = "audio/x-";
1744 if (!strcasecmp(format, "ogg"))
1745 ctype = "application/";
1747 fprintf(p, "--%s\n", bound);
1748 fprintf(p, "Content-Type: %s%s; name=\"msg%04d.%s\"\n", ctype, format, msgnum, format);
1749 fprintf(p, "Content-Transfer-Encoding: base64\n");
1750 fprintf(p, "Content-Description: Voicemail sound attachment.\n");
1751 fprintf(p, "Content-Disposition: attachment; filename=\"msg%04d.%s\"\n\n", msgnum, format);
1753 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
1754 base_encode(fname, p);
1755 fprintf(p, "\n\n--%s--\n.\n", bound);
1758 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
1759 ast_safe_system(tmp2);
1760 ast_log(LOG_DEBUG, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
1762 ast_log(LOG_WARNING, "Unable to launch '%s'\n", mailcmd);
1768 static int sendpage(char *srcemail, char *pager, int msgnum, char *context, char *mailbox, char *cidnum, char *cidname, int duration, struct ast_vm_user *vmu)
1773 char host[MAXHOSTNAMELEN]="";
1776 char tmp[80] = "/tmp/astmail-XXXXXX";
1780 struct vm_zone *the_zone = NULL;
1784 p = fdopen(pfd, "w");
1792 gethostname(host, sizeof(host)-1);
1793 if (strchr(srcemail, '@'))
1794 ast_copy_string(who, srcemail, sizeof(who));
1796 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
1798 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
1801 /* Does this user have a timezone specified? */
1802 if (!ast_strlen_zero(vmu->zonetag)) {
1803 /* Find the zone in the list */
1807 if (!strcmp(z->name, vmu->zonetag)) {
1816 ast_localtime(&t,&tm,the_zone->timezone);
1818 ast_localtime(&t,&tm,NULL);
1820 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", &tm);
1821 fprintf(p, "Date: %s\n", date);
1823 if (*pagerfromstring) {
1824 struct ast_channel *ast = ast_channel_alloc(0);
1827 int vmlen = strlen(fromstring)*3 + 200;
1828 if ((passdata = alloca(vmlen))) {
1829 memset(passdata, 0, vmlen);
1830 prep_email_sub_vars(ast,vmu,msgnum + 1,context,mailbox,cidnum, cidname,dur,date,passdata, vmlen);
1831 pbx_substitute_variables_helper(ast,pagerfromstring,passdata,vmlen);
1832 fprintf(p, "From: %s <%s>\n",passdata,who);
1834 ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
1835 ast_channel_free(ast);
1836 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
1838 fprintf(p, "From: Asterisk PBX <%s>\n", who);
1839 fprintf(p, "To: %s\n", pager);
1841 struct ast_channel *ast = ast_channel_alloc(0);
1844 int vmlen = strlen(pagersubject)*3 + 200;
1845 if ((passdata = alloca(vmlen))) {
1846 memset(passdata, 0, vmlen);
1847 prep_email_sub_vars(ast,vmu,msgnum + 1,context,mailbox,cidnum, cidname,dur,date,passdata, vmlen);
1848 pbx_substitute_variables_helper(ast,pagersubject,passdata,vmlen);
1849 fprintf(p, "Subject: %s\n\n",passdata);
1850 } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
1851 ast_channel_free(ast);
1852 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
1854 fprintf(p, "Subject: New VM\n\n");
1855 strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm);
1857 struct ast_channel *ast = ast_channel_alloc(0);
1860 int vmlen = strlen(pagerbody)*3 + 200;
1861 if ((passdata = alloca(vmlen))) {
1862 memset(passdata, 0, vmlen);
1863 prep_email_sub_vars(ast,vmu,msgnum + 1,context,mailbox,cidnum, cidname,dur,date,passdata, vmlen);
1864 pbx_substitute_variables_helper(ast,pagerbody,passdata,vmlen);
1865 fprintf(p, "%s\n",passdata);
1866 } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
1867 ast_channel_free(ast);
1868 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
1870 fprintf(p, "New %s long msg in box %s\n"
1871 "from %s, on %s", dur, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
1874 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
1875 ast_safe_system(tmp2);
1876 ast_log(LOG_DEBUG, "Sent page to %s with command '%s'\n", pager, mailcmd);
1878 ast_log(LOG_WARNING, "Unable to launch '%s'\n", mailcmd);
1884 static int get_date(char *s, int len)
1889 localtime_r(&t,&tm);
1890 return strftime(s, len, "%a %b %e %r %Z %Y", &tm);
1893 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
1897 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
1899 if (ast_fileexists(fn, NULL, NULL) > 0) {
1900 res = ast_streamfile(chan, fn, chan->language);
1905 res = ast_waitstream(chan, ecodes);
1911 /* Dispose just in case */
1913 res = ast_streamfile(chan, "vm-theperson", chan->language);
1916 res = ast_waitstream(chan, ecodes);
1919 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
1924 res = ast_streamfile(chan, "vm-isonphone", chan->language);
1926 res = ast_streamfile(chan, "vm-isunavail", chan->language);
1929 res = ast_waitstream(chan, ecodes);
1933 static void free_user(struct ast_vm_user *vmu)
1935 if (ast_test_flag(vmu, VM_ALLOCED))
1939 static void free_zone(struct vm_zone *z)
1944 static char *mbox(int id)
1972 #ifdef USE_ODBC_STORAGE
1973 static int messagecount(const char *mailbox, int *newmsgs, int *oldmsgs)
1987 /* If no mailbox, return immediately */
1988 if (ast_strlen_zero(mailbox))
1991 ast_copy_string(tmp, mailbox, sizeof(tmp));
1993 context = strchr(tmp, '@');
1998 context = "default";
2001 obj = fetch_odbc_obj(odbc_database, 0);
2003 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
2004 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
2005 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
2008 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir like \"%%%s/%s/%s\"%c", odbc_table, context, tmp, "INBOX", '\0');
2009 res = SQLPrepare(stmt, sql, SQL_NTS);
2010 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
2011 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
2012 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
2015 res = odbc_smart_execute(obj, stmt);
2016 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
2017 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
2018 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
2021 res = SQLFetch(stmt);
2022 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
2023 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
2024 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
2027 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
2028 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
2029 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
2030 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
2033 *newmsgs = atoi(rowdata);
2034 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
2036 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
2037 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
2038 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
2041 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir like \"%%%s/%s/%s\"%c", odbc_table, context, tmp, "Old", '\0');
2042 res = SQLPrepare(stmt, sql, SQL_NTS);
2043 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
2044 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
2045 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
2048 res = odbc_smart_execute(obj, stmt);
2049 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
2050 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
2051 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
2054 res = SQLFetch(stmt);
2055 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
2056 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
2057 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
2060 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
2061 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
2062 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
2063 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
2066 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
2067 *oldmsgs = atoi(rowdata);
2070 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
2076 static int has_voicemail(const char *mailbox, const char *folder)
2087 /* If no mailbox, return immediately */
2088 if (ast_strlen_zero(mailbox))
2091 ast_copy_string(tmp, mailbox, sizeof(tmp));
2093 context = strchr(tmp, '@');
2098 context = "default";
2101 obj = fetch_odbc_obj(odbc_database, 0);
2103 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
2104 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
2105 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
2108 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM %s WHERE dir like \"%%%s/%s/%s\"%c", odbc_table, context, tmp, "INBOX", '\0');
2109 res = SQLPrepare(stmt, sql, SQL_NTS);
2110 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
2111 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
2112 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
2115 res = odbc_smart_execute(obj, stmt);
2116 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
2117 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
2118 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
2121 res = SQLFetch(stmt);
2122 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
2123 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
2124 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
2127 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
2128 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
2129 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
2130 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
2133 nummsgs = atoi(rowdata);
2134 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
2136 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
2147 static int has_voicemail(const char *mailbox, const char *folder)
2158 /* If no mailbox, return immediately */
2159 if (ast_strlen_zero(mailbox))
2161 if (strchr(mailbox, ',')) {
2162 ast_copy_string(tmp, mailbox, sizeof(tmp));
2165 while((cur = strsep(&mb, ","))) {
2166 if (!ast_strlen_zero(cur)) {
2167 if (has_voicemail(cur, folder))
2173 ast_copy_string(tmp, mailbox, sizeof(tmp));
2174 context = strchr(tmp, '@');
2179 context = "default";
2180 snprintf(fn, sizeof(fn), "%s/%s/%s/%s", VM_SPOOL_DIR, context, tmp, folder);
2184 while ((de = readdir(dir))) {
2185 if (!strncasecmp(de->d_name, "msg", 3))
2195 static int messagecount(const char *mailbox, int *newmsgs, int *oldmsgs)
2208 /* If no mailbox, return immediately */
2209 if (ast_strlen_zero(mailbox))
2211 if (strchr(mailbox, ',')) {
2213 ast_copy_string(tmp, mailbox, sizeof(tmp));
2216 while((cur = strsep(&mb, ", "))) {
2217 if (!ast_strlen_zero(cur)) {
2218 if (messagecount(cur, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
2230 ast_copy_string(tmp, mailbox, sizeof(tmp));
2231 context = strchr(tmp, '@');
2236 context = "default";
2238 snprintf(fn, sizeof(fn), "%s/%s/%s/INBOX", VM_SPOOL_DIR, context, tmp);
2241 while ((de = readdir(dir))) {
2242 if ((strlen(de->d_name) > 3) && !strncasecmp(de->d_name, "msg", 3) &&
2243 !strcasecmp(de->d_name + strlen(de->d_name) - 3, "txt"))
2251 snprintf(fn, sizeof(fn), "%s/%s/%s/Old", VM_SPOOL_DIR, context, tmp);
2254 while ((de = readdir(dir))) {
2255 if ((strlen(de->d_name) > 3) && !strncasecmp(de->d_name, "msg", 3) &&
2256 !strcasecmp(de->d_name + strlen(de->d_name) - 3, "txt"))
2268 static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, int msgnum, long duration, char *fmt, char *cidnum, char *cidname);
2270 static int copy_message(struct ast_channel *chan, struct ast_vm_user *vmu, int imbox, int msgnum, long duration, struct ast_vm_user *recip, char *fmt)
2272 char fromdir[256], todir[256], frompath[256], topath[256];
2273 char *frombox = mbox(imbox);
2276 ast_log(LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
2278 make_dir(todir, sizeof(todir), recip->context, "", "");
2279 /* It's easier just to try to make it than to check for its existence */
2280 if (mkdir(todir, 0700) && (errno != EEXIST))
2281 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", todir, strerror(errno));
2282 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, "");
2283 /* It's easier just to try to make it than to check for its existence */
2284 if (mkdir(todir, 0700) && (errno != EEXIST))
2285 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", todir, strerror(errno));
2286 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX");
2287 if (mkdir(todir, 0700) && (errno != EEXIST))
2288 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", todir, strerror(errno));
2290 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
2291 make_file(frompath, sizeof(frompath), fromdir, msgnum);
2293 if (vm_lock_path(todir))
2294 return ERROR_LOCK_PATH;
2298 make_file(topath, sizeof(topath), todir, recipmsgnum);
2299 if (!EXISTS(todir, recipmsgnum, topath, chan->language))
2302 } while (recipmsgnum < recip->maxmsg);
2303 if (recipmsgnum < recip->maxmsg) {
2304 COPY(fromdir, msgnum, todir, recipmsgnum, recip->mailbox, recip->context, frompath, topath);
2306 ast_log(LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
2308 ast_unlock_path(todir);
2309 notify_new_message(chan, recip, recipmsgnum, duration, fmt, chan->cid.cid_num, chan->cid.cid_name);
2314 static void run_externnotify(char *context, char *extension)
2316 char arguments[255];
2317 char ext_context[256] = "";
2318 int newvoicemails = 0, oldvoicemails = 0;
2320 if (!ast_strlen_zero(context))
2321 snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context);
2323 ast_copy_string(ext_context, extension, sizeof(ext_context));
2325 if (!ast_strlen_zero(externnotify)) {
2326 if (messagecount(ext_context, &newvoicemails, &oldvoicemails)) {
2327 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
2329 snprintf(arguments, sizeof(arguments), "%s %s %s %d&", externnotify, context, extension, newvoicemails);
2330 ast_log(LOG_DEBUG, "Executing %s\n", arguments);
2331 ast_safe_system(arguments);
2336 struct leave_vm_options {
2338 signed char record_gain;
2341 static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
2354 char prefile[256]="";
2355 char tempfile[256]="";
2356 char ext_context[256] = "";
2359 char ecodes[16] = "#";
2360 char tmp[256] = "", *tmpptr;
2361 struct ast_vm_user *vmu;
2362 struct ast_vm_user svm;
2363 char *category = NULL;
2365 ast_copy_string(tmp, ext, sizeof(tmp));
2367 context = strchr(tmp, '@');
2371 tmpptr = strchr(context, '&');
2373 tmpptr = strchr(ext, '&');
2381 category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY");
2383 if (!(vmu = find_user(&svm, context, ext))) {
2384 ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
2385 if (ast_test_flag(options, OPT_PRIORITY_JUMP) || ast_opt_priority_jumping)
2386 ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101);
2387 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
2391 /* Setup pre-file if appropriate */
2392 if (strcmp(vmu->context, "default"))
2393 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
2395 ast_copy_string(ext_context, vmu->context, sizeof(ext_context));
2396 if (ast_test_flag(options, OPT_BUSY_GREETING))
2397 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
2398 else if (ast_test_flag(options, OPT_UNAVAIL_GREETING))
2399 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
2400 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
2401 RETRIEVE(tempfile, -1);
2402 if (ast_fileexists(tempfile, NULL, NULL) > 0)
2403 ast_copy_string(prefile, tempfile, sizeof(prefile));
2404 DISPOSE(tempfile, -1);
2405 make_dir(dir, sizeof(dir), vmu->context, "", "");
2406 /* It's easier just to try to make it than to check for its existence */
2407 if (mkdir(dir, 0700) && (errno != EEXIST))
2408 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
2409 make_dir(dir, sizeof(dir), vmu->context, ext, "");
2410 /* It's easier just to try to make it than to check for its existence */
2411 if (mkdir(dir, 0700) && (errno != EEXIST))
2412 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
2413 make_dir(dir, sizeof(dir), vmu->context, ext, "INBOX");
2414 if (mkdir(dir, 0700) && (errno != EEXIST))
2415 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
2417 /* Check current or macro-calling context for special extensions */
2418 if (!ast_strlen_zero(vmu->exit)) {
2419 if (ast_exists_extension(chan, vmu->exit, "o", 1, chan->cid.cid_num))
2420 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
2421 } else if (ast_exists_extension(chan, chan->context, "o", 1, chan->cid.cid_num))
2422 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
2423 else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "o", 1, chan->cid.cid_num)) {
2424 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
2428 if (!ast_strlen_zero(vmu->exit)) {
2429 if (ast_exists_extension(chan, vmu->exit, "a", 1, chan->cid.cid_num))
2430 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
2431 } else if (ast_exists_extension(chan, chan->context, "a", 1, chan->cid.cid_num))
2432 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
2433 else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "a", 1, chan->cid.cid_num)) {
2434 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
2438 /* Play the beginning intro if desired */
2439 if (!ast_strlen_zero(prefile)) {
2440 RETRIEVE(prefile, -1);
2441 if (ast_fileexists(prefile, NULL, NULL) > 0) {
2442 if (ast_streamfile(chan, prefile, chan->language) > -1)
2443 res = ast_waitstream(chan, ecodes);
2445 ast_log(LOG_DEBUG, "%s doesn't exist, doing what we can\n", prefile);
2446 res = invent_message(chan, vmu->context, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
2448 DISPOSE(prefile, -1);
2450 ast_log(LOG_DEBUG, "Hang up during prefile playback\n");
2452 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
2457 /* On a '#' we skip the instructions */
2458 ast_set_flag(options, OPT_SILENT);
2461 if (!res && !ast_test_flag(options, OPT_SILENT)) {
2462 res = ast_streamfile(chan, INTRO, chan->language);
2464 res = ast_waitstream(chan, ecodes);
2466 ast_set_flag(options, OPT_SILENT);
2471 ast_stopstream(chan);
2472 /* Check for a '*' here in case the caller wants to escape from voicemail to something
2473 other than the operator -- an automated attendant or mailbox login for example */
2475 chan->exten[0] = 'a';
2476 chan->exten[1] = '\0';
2477 if (!ast_strlen_zero(vmu->exit)) {
2478 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
2479 } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
2480 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
2484 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
2487 /* Check for a '0' here */
2490 if (ast_test_flag(vmu, VM_OPERATOR)) {
2491 chan->exten[0] = 'o';
2492 chan->exten[1] = '\0';
2493 if (!ast_strlen_zero(vmu->exit)) {
2494 ast_copy_string(chan->context, vmu->exit, sizeof(chan->context));
2495 } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
2496 ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context));
2498 ast_play_and_wait(chan, "transfer");
2501 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
2504 ast_play_and_wait(chan, "vm-sorry");
2505 pbx_builtin_setvar_helper(chan, "VMSTATUS", "USEREXIT");
2511 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
2514 /* The meat of recording the message... All the announcements and beeps have been played*/
2515 ast_copy_string(fmt, vmfmts, sizeof(fmt));
2516 if (!ast_strlen_zero(fmt)) {
2519 if (vm_lock_path(dir)) {
2521 return ERROR_LOCK_PATH;
2525 * This operation can be very expensive if done say over NFS or if the mailbox has 100+ messages
2526 * in the mailbox. So we should get this first so we don't cut off the first few seconds of the
2530 make_file(fn, sizeof(fn), dir, msgnum);
2531 if (!EXISTS(dir,msgnum,fn,chan->language))
2534 } while (msgnum < vmu->maxmsg);
2536 /* Now play the beep once we have the message number for our next message. */
2538 /* Unless we're *really* silent, try to send the beep */
2539 res = ast_streamfile(chan, "beep", chan->language);
2541 res = ast_waitstream(chan, "");
2543 if (msgnum < vmu->maxmsg) {
2544 /* assign a variable with the name of the voicemail file */
2545 pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn);
2547 /* Store information */
2548 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
2549 txt = fopen(txtfile, "w+");
2551 get_date(date, sizeof(date));
2554 "; Message Information file\n"
2573 ast_callerid_merge(callerid, sizeof(callerid), chan->cid.cid_name, chan->cid.cid_num, "Unknown"),
2574 date, (long)time(NULL),
2575 category ? category : "");
2577 ast_log(LOG_WARNING, "Error opening text file for output\n");
2578 res = play_record_review(chan, NULL, fn, vmmaxmessage, fmt, 1, vmu, &duration, dir, options->record_gain);
2587 fprintf(txt, "duration=%d\n", duration);
2591 if (duration < vmminmessage) {
2592 if (option_verbose > 2)
2593 ast_verbose( VERBOSE_PREFIX_3 "Recording was %d seconds long but needs to be at least %d - abandoning\n", duration, vmminmessage);
2594 DELETE(dir,msgnum,fn);
2595 /* XXX We should really give a prompt too short/option start again, with leave_vm_out called only after a timeout XXX */
2596 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
2599 /* Are there to be more recipients of this message? */
2601 struct ast_vm_user recipu, *recip;
2602 char *exten, *context;
2604 exten = strsep(&tmpptr, "&");
2605 context = strchr(exten, '@');
2610 if ((recip = find_user(&recipu, context, exten))) {
2611 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt);
2615 if (ast_fileexists(fn, NULL, NULL)) {
2616 notify_new_message(chan, vmu, msgnum, duration, fmt, chan->cid.cid_num, chan->cid.cid_name);
2617 STORE(dir, vmu->mailbox, vmu->context, msgnum);
2618 DISPOSE(dir, msgnum);
2620 pbx_builtin_setvar_helper(chan, "VMSTATUS", "SUCCESS");
2622 ast_unlock_path(dir);
2623 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
2625 res = ast_waitstream(chan, "");
2626 ast_log(LOG_WARNING, "No more messages possible\n");
2627 pbx_builtin_setvar_helper(chan, "VMSTATUS", "FAILED");
2630 ast_log(LOG_WARNING, "No format for saving voicemail?\n");
2637 static int resequence_mailbox(struct ast_vm_user *vmu, char *dir)
2639 /* we know max messages, so stop process when number is hit */
2645 if (vm_lock_path(dir))
2646 return ERROR_LOCK_PATH;
2648 for (x = 0, dest = 0; x < vmu->maxmsg; x++) {
2649 make_file(sfn, sizeof(sfn), dir, x);
2650 if (EXISTS(dir, x, sfn, NULL)) {
2653 make_file(dfn, sizeof(dfn), dir, dest);
2654 RENAME(dir, x, vmu->mailbox, vmu->context, dir, dest, sfn, dfn);
2660 ast_unlock_path(dir);
2666 static int say_and_wait(struct ast_channel *chan, int num, char *language)
2669 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, (char *) NULL);
2673 static int save_to_folder(struct ast_vm_user *vmu, char *dir, int msg, char *context, char *username, int box)
2678 char *dbox = mbox(box);
2680 make_file(sfn, sizeof(sfn), dir, msg);
2681 make_dir(ddir, sizeof(ddir), context, username, dbox);
2684 if (vm_lock_path(ddir))
2685 return ERROR_LOCK_PATH;
2687 for (x = 0; x < vmu->maxmsg; x++) {
2688 make_file(dfn, sizeof(dfn), ddir, x);
2689 if (!EXISTS(ddir, x, dfn, NULL))
2692 if (x >= vmu->maxmsg) {
2693 ast_unlock_path(ddir);
2696 if (strcmp(sfn, dfn)) {
2697 COPY(dir, msg, ddir, x, username, context, sfn, dfn);
2699 ast_unlock_path(ddir);
2704 static int adsi_logo(unsigned char *buf)
2707 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
2708 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002 LSS, Inc.", "");
2712 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
2714 unsigned char buf[256];
2720 bytes += adsi_data_mode(buf + bytes);
2721 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2724 bytes += adsi_logo(buf);
2725 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
2727 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
2729 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2730 bytes += adsi_data_mode(buf + bytes);
2731 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2733 if (adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
2735 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
2736 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
2737 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2738 bytes += adsi_voice_mode(buf + bytes, 0);
2739 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2746 bytes += adsi_logo(buf);
2747 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
2748 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
2749 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2750 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2753 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
2754 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
2755 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
2756 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
2757 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
2758 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
2759 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
2762 /* Add another dot */
2764 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
2765 bytes += adsi_voice_mode(buf + bytes, 0);
2767 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2768 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2772 /* These buttons we load but don't use yet */
2773 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
2774 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
2775 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
2776 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
2777 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
2778 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
2779 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
2782 /* Add another dot */
2784 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
2785 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2786 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2791 snprintf(num, sizeof(num), "%d", x);
2792 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(x), mbox(x), num, 1);
2794 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
2795 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
2798 /* Add another dot */
2800 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
2801 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2802 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2805 if (adsi_end_download(chan)) {
2807 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
2808 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
2809 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2810 bytes += adsi_voice_mode(buf + bytes, 0);
2811 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2815 bytes += adsi_download_disconnect(buf + bytes);
2816 bytes += adsi_voice_mode(buf + bytes, 0);
2817 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
2819 ast_log(LOG_DEBUG, "Done downloading scripts...\n");
2824 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
2825 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2827 ast_log(LOG_DEBUG, "Restarting session...\n");
2830 /* Load the session now */
2831 if (adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
2833 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
2835 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
2837 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2841 static void adsi_begin(struct ast_channel *chan, int *useadsi)
2844 if (!adsi_available(chan))
2846 x = adsi_load_session(chan, adsifdn, adsiver, 1);
2850 if (adsi_load_vmail(chan, useadsi)) {
2851 ast_log(LOG_WARNING, "Unable to upload voicemail scripts\n");
2858 static void adsi_login(struct ast_channel *chan)
2860 unsigned char buf[256];
2862 unsigned char keys[8];
2864 if (!adsi_available(chan))
2869 /* Set one key for next */
2870 keys[3] = ADSI_KEY_APPS + 3;
2872 bytes += adsi_logo(buf + bytes);
2873 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
2874 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
2875 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2876 bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
2877 bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
2878 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
2879 bytes += adsi_set_keys(buf + bytes, keys);
2880 bytes += adsi_voice_mode(buf + bytes, 0);
2881 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2884 static void adsi_password(struct ast_channel *chan)
2886 unsigned char buf[256];
2888 unsigned char keys[8];
2890 if (!adsi_available(chan))
2895 /* Set one key for next */
2896 keys[3] = ADSI_KEY_APPS + 3;
2898 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2899 bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
2900 bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
2901 bytes += adsi_set_keys(buf + bytes, keys);
2902 bytes += adsi_voice_mode(buf + bytes, 0);
2903 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2906 static void adsi_folders(struct ast_channel *chan, int start, char *label)
2908 unsigned char buf[256];
2910 unsigned char keys[8];
2913 if (!adsi_available(chan))
2917 y = ADSI_KEY_APPS + 12 + start + x;
2918 if (y > ADSI_KEY_APPS + 12 + 4)
2920 keys[x] = ADSI_KEY_SKT | y;
2922 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
2926 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
2927 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
2928 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2929 bytes += adsi_set_keys(buf + bytes, keys);
2930 bytes += adsi_voice_mode(buf + bytes, 0);
2932 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2935 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
2938 unsigned char buf[256];
2939 char buf1[256], buf2[256];
2945 char datetime[21]="";
2948 unsigned char keys[8];
2952 if (!adsi_available(chan))
2955 /* Retrieve important info */
2956 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
2957 f = fopen(fn2, "r");
2960 fgets((char *)buf, sizeof(buf), f);
2963 stringp = (char *)buf;
2964 strsep(&stringp, "=");
2965 val = strsep(&stringp, "=");
2966 if (!ast_strlen_zero(val)) {
2967 if (!strcmp((char *)buf, "callerid"))
2968 ast_copy_string(cid, val, sizeof(cid));
2969 if (!strcmp((char *)buf, "origdate"))
2970 ast_copy_string(datetime, val, sizeof(datetime));
2976 /* New meaning for keys */
2978 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
2983 /* No prev key, provide "Folder" instead */
2984 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
2986 if (vms->curmsg >= vms->lastmsg) {
2987 /* If last message ... */
2989 /* but not only message, provide "Folder" instead */
2990 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
2991 bytes += adsi_voice_mode(buf + bytes, 0);
2994 /* Otherwise if only message, leave blank */
2999 if (!ast_strlen_zero(cid)) {
3000 ast_callerid_parse(cid, &name, &num);
3004 name = "Unknown Caller";
3006 /* If deleted, show "undeleted" */
3008 if (vms->deleted[vms->curmsg])
3009 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
3012 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
3013 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
3014 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
3015 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
3017 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
3018 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
3019 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
3020 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
3021 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
3022 bytes += adsi_set_keys(buf + bytes, keys);
3023 bytes += adsi_voice_mode(buf + bytes, 0);
3025 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
3028 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
3031 unsigned char buf[256];
3032 unsigned char keys[8];
3036 if (!adsi_available(chan))
3039 /* New meaning for keys */
3041 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
3047 /* No prev key, provide "Folder" instead */
3048 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
3050 if (vms->curmsg >= vms->lastmsg) {
3051 /* If last message ... */
3053 /* but not only message, provide "Folder" instead */
3054 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
3056 /* Otherwise if only message, leave blank */
3061 /* If deleted, show "undeleted" */
3062 if (vms->deleted[vms->curmsg])
3063 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
3066 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
3067 bytes += adsi_set_keys(buf + bytes, keys);
3068 bytes += adsi_voice_mode(buf + bytes, 0);
3070 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
3073 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
3075 unsigned char buf[256] = "";
3076 char buf1[256] = "", buf2[256] = "";
3078 unsigned char keys[8];
3081 char *newm = (vms->newmessages == 1) ? "message" : "messages";
3082 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
3083 if (!adsi_available(chan))
3085 if (vms->newmessages) {
3086 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
3087 if (vms->oldmessages) {
3088 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
3089 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
3091 snprintf(buf2, sizeof(buf2), "%s.", newm);
3093 } else if (vms->oldmessages) {
3094 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
3095 snprintf(buf2, sizeof(buf2), "%s.", oldm);
3097 strcpy(buf1, "You have no messages.");
3101 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
3102 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
3103 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
3106 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
3110 /* Don't let them listen if there are none */
3111 if (vms->lastmsg < 0)
3113 bytes += adsi_set_keys(buf + bytes, keys);
3115 bytes += adsi_voice_mode(buf + bytes, 0);
3117 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
3120 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
3122 unsigned char buf[256] = "";
3123 char buf1[256] = "", buf2[256] = "";
3125 unsigned char keys[8];
3128 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
3130 if (!adsi_available(chan))
3133 /* Original command keys */
3135 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
3140 if ((vms->lastmsg + 1) < 1)
3143 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
3144 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
3146 if (vms->lastmsg + 1)
3147 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
3149 strcpy(buf2, "no messages.");
3150 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
3151 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
3152 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
3153 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
3154 bytes += adsi_set_keys(buf + bytes, keys);
3156 bytes += adsi_voice_mode(buf + bytes, 0);
3158 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
3163 static void adsi_clear(struct ast_channel *chan)
3167 if (!adsi_available(chan))
3169 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
3170 bytes += adsi_voice_mode(buf + bytes, 0);
3172 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
3176 static void adsi_goodbye(struct ast_channel *chan)
3178 unsigned char buf[256];
3181 if (!adsi_available(chan))
3183 bytes += adsi_logo(buf + bytes);
3184 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
3185 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
3186 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
3187 bytes += adsi_voice_mode(buf + bytes, 0);
3189 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
3192 /*--- get_folder: Folder menu ---*/
3193 /* Plays "press 1 for INBOX messages" etc
3194 Should possibly be internationalized
3196 static int get_folder(struct ast_channel *chan, int start)
3201 d = ast_play_and_wait(chan, "vm-press"); /* "Press" */
3204 for (x = start; x< 5; x++) { /* For all folders */
3205 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, (char *) NULL)))
3207 d = ast_play_and_wait(chan, "vm-for"); /* "for" */
3210 snprintf(fn, sizeof(fn), "vm-%s", mbox(x)); /* Folder name */
3211 d = vm_play_folder_name(chan, fn);
3214 d = ast_waitfordigit(chan, 500);
3218 d = ast_play_and_wait(chan, "vm-tocancel"); /* "or pound to cancel" */
3221 d = ast_waitfordigit(chan, 4000);
3225 static int get_folder2(struct ast_channel *chan, char *fn, int start)
3228 res = ast_play_and_wait(chan, fn); /* Folder name */
3229 while (((res < '0') || (res > '9')) &&
3230 (res != '#') && (res >= 0)) {
3231 res = get_folder(chan, 0);
3236 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vmfts,
3237 char *context, signed char record_gain)
3242 signed char zero_gain = 0;
3244 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
3249 /* prepend a message to the current message and return */
3252 snprintf(file, sizeof(file), "%s/msg%04d", curdir, curmsg);
3254 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &record_gain, sizeof(record_gain), 0);
3255 cmd = ast_play_and_prepend(chan, NULL, file, 0, vmfmts, &duration, 1, silencethreshold, maxsilence);
3257 ast_channel_setoption(chan, AST_OPTION_RXGAIN, &zero_gain, sizeof(zero_gain), 0);
3267 cmd = ast_play_and_wait(chan,"vm-forwardoptions");
3268 /* "Press 1 to prepend a message or 2 to forward the message without prepending" */
3270 cmd = ast_play_and_wait(chan,"vm-starmain");
3271 /* "press star to return to the main menu" */
3273 cmd = ast_waitfordigit(chan,6000);
3285 static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, int msgnum, long duration, char *fmt, char *cidnum, char *cidname)
3287 char todir[256], fn[256], ext_context[256], *stringp;
3288 int newmsgs = 0, oldmsgs = 0;
3290 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, "INBOX");
3291 make_file(fn, sizeof(fn), todir, msgnum);
3292 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
3294 /* Attach only the first format */
3295 fmt = ast_strdupa(fmt);
3298 strsep(&stringp, "|");
3300 if (!ast_strlen_zero(vmu->email)) {
3301 int attach_user_voicemail = ast_test_flag((&globalflags), VM_ATTACH);
3302 char *myserveremail = serveremail;
3303 attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
3304 if (!ast_strlen_zero(vmu->serveremail))
3305 myserveremail = vmu->serveremail;
3306 sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, cidnum, cidname, fn, fmt, duration, attach_user_voicemail);
3309 if (!ast_strlen_zero(vmu->pager)) {
3310 char *myserveremail = serveremail;
3311 if (!ast_strlen_zero(vmu->serveremail))
3312 myserveremail = vmu->serveremail;
3313 sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, cidnum, cidname, duration, vmu);
3316 ast_log(LOG_ERROR, "Out of memory\n");
3319 if (ast_test_flag(vmu, VM_DELETE)) {
3320 DELETE(todir, msgnum, fn);
3323 /* Leave voicemail for someone */
3324 if (ast_app_has_voicemail(ext_context, NULL)) {
3325 ast_app_messagecount(ext_context, &newmsgs, &oldmsgs);
3327 manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s@%s\r\nWaiting: %d\r\nNew: %d\r\nOld: %d\r\n", vmu->mailbox, vmu->context, ast_app_has_voicemail(ext_context, NULL), newmsgs, oldmsgs);
3328 run_externnotify(vmu->context, vmu->mailbox);
3332 static int forward_message(struct ast_channel *chan, char *context, char *dir, int curmsg, struct ast_vm_user *sender,
3333 char *fmt, int flag, signed char record_gain)
3335 char username[70]="";
3340 struct ast_config *mif;
3344 char ext_context[256]="";
3345 int res = 0, cmd = 0;
3346 struct ast_vm_user *receiver = NULL, *extensions = NULL, *vmtmp = NULL, *vmfree;
3349 int saved_messages = 0, found = 0;
3350 int valid_extensions = 0;
3352 while (!res && !valid_extensions) {
3353 int use_directory = 0;
3354 if(ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
3358 while((cmd >= 0) && !done ){
3375 /* Press 1 to enter an extension press 2 to use the directory */
3376 cmd = ast_play_and_wait(chan,"vm-forward");
3378 cmd = ast_waitfordigit(chan,3000);
3389 if( cmd<0 || cmd=='t' )
3393 if( use_directory ) {
3394 /* use app_directory */
3396 char old_context[sizeof(chan->context)];
3397 char old_exten[sizeof(chan->exten)];
3399 struct ast_app* app;
3402 app = pbx_findapp("Directory");
3404 /* make mackup copies */
3405 memcpy(old_context, chan->context, sizeof(chan->context));
3406 memcpy(old_exten, chan->exten, sizeof(chan->exten));
3407 old_priority = chan->priority;
3409 /* call the the Directory, changes the channel */
3410 res = pbx_exec(chan, app, ((context)?context:chan->context), 1);
3412 ast_copy_string(username, chan->exten, sizeof(username));
3414 /* restore the old context, exten, and priority */
3415 memcpy(chan->context, old_context, sizeof(chan->context));
3416 memcpy(chan->exten, old_exten, sizeof(chan->exten));
3417 chan->priority = old_priority;
3420 ast_log(LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n");
3421 ast_clear_flag((&globalflags), VM_DIRECFORWARD);
3424 /* Ask for an extension */
3425 res = ast_streamfile(chan, "vm-extension", chan->language); /* "extension" */
3428 if ((res = ast_readstring(chan, username, sizeof(username) - 1, 2000, 10000, "#") < 0))
3432 /* start all over if no username */
3433 if (ast_strlen_zero(username))
3436 s = strsep(&stringp, "*");
3437 /* start optimistic */
3438 valid_extensions = 1;
3440 /* find_user is going to malloc since we have a NULL as first argument */
3441 if ((receiver = find_user(NULL, context, s))) {
3443 vmtmp = extensions = receiver;
3445 vmtmp->next = receiver;
3450 valid_extensions = 0;
3453 s = strsep(&stringp, "*");
3455 /* break from the loop of reading the extensions */