2 * Asterisk -- A telephony toolkit for Linux.
6 * Copyright (C) 2003 - 2005, Digium Inc.
8 * Mark Spencer <markster@digium.com>
10 * This program is free software, distributed under the terms of
11 * the GNU General Public License
13 * 12-16 - 2005 : Support for Greek added by InAccess Networks (work funded by HOL, www.hol.gr)
14 * George Konstantoulakis <gkon@inaccessnetworks.com>
17 #include <asterisk/lock.h>
18 #include <asterisk/file.h>
19 #include <asterisk/logger.h>
20 #include <asterisk/channel.h>
21 #include <asterisk/channel_pvt.h>
22 #include <asterisk/pbx.h>
23 #include <asterisk/options.h>
24 #include <asterisk/config.h>
25 #include <asterisk/say.h>
26 #include <asterisk/module.h>
27 #include <asterisk/adsi.h>
28 #include <asterisk/app.h>
29 #include <asterisk/manager.h>
30 #include <asterisk/dsp.h>
31 #include <asterisk/localtime.h>
32 #include <asterisk/cli.h>
33 #include <asterisk/utils.h>
34 #ifdef USE_ODBC_STORAGE
35 #include <asterisk/res_odbc.h>
45 #include <sys/types.h>
50 #include "../asterisk.h"
51 #include "../astconf.h"
53 #define COMMAND_TIMEOUT 5000
55 #define VOICEMAIL_CONFIG "voicemail.conf"
56 #define ASTERISK_USERNAME "asterisk"
58 /* Default mail command to mail voicemail. Change it with the
59 mailcmd= command in voicemail.conf */
60 #define SENDMAIL "/usr/sbin/sendmail -t"
62 #define INTRO "vm-intro"
66 #define BASEMAXINLINE 256
67 #define BASELINELEN 72
68 #define BASEMAXINLINE 256
71 #define MAX_DATETIME_FORMAT 512
72 #define MAX_NUM_CID_CONTEXTS 10
74 #define VM_REVIEW (1 << 0)
75 #define VM_OPERATOR (1 << 1)
76 #define VM_SAYCID (1 << 2)
77 #define VM_SVMAIL (1 << 3)
78 #define VM_ENVELOPE (1 << 4)
79 #define VM_SAYDURATION (1 << 5)
80 #define VM_SKIPAFTERCMD (1 << 6)
81 #define VM_FORCENAME (1 << 7) /* Have new users record their name */
82 #define VM_FORCEGREET (1 << 8) /* Have new users record their greetings */
83 #define VM_PBXSKIP (1 << 9)
84 #define VM_DIRECFORWARD (1 << 10) /* directory_forward */
85 #define VM_ATTACH (1 << 11)
86 #define VM_DELETE (1 << 12)
87 #define VM_ALLOCED (1 << 13)
89 static int load_config(void);
91 /* Syntaxes supported, not really language codes.
101 German requires the following additional soundfile:
104 Spanish requires the following additional soundfile:
107 Dutch, Portuguese & Spanish require the following additional soundfiles:
108 vm-INBOXs singular of 'new'
109 vm-Olds singular of 'old/heard/read'
122 Italian requires the following additional soundfile:
129 Don't use vm-INBOX or vm-Old, because they are the name of the INBOX and Old folderS, spelled among others when you have to change folder.
130 For the above reasons, vm-INBOX and vm-Old are spelled plural, to make them sound more as folder name than an adjective.
139 unsigned char iobuf[BASEMAXINLINE];
142 /* Structure for linked list of users */
144 char context[80]; /* Voicemail context */
145 char mailbox[80]; /* Mailbox id, unique within vm context */
146 char password[80]; /* Secret pin code, numbers only */
147 char fullname[80]; /* Full name, for directory app */
148 char email[80]; /* E-mail address */
149 char pager[80]; /* E-mail address to pager (no attachment) */
150 char serveremail[80]; /* From: Mail address */
151 char mailcmd[160]; /* Configurable mail command */
152 char language[MAX_LANGUAGE]; /* Config: Language setting */
153 char zonetag[80]; /* Time zone */
156 char uniqueid[20]; /* Unique integer identifier */
158 unsigned int flags; /* VM_ flags */
160 struct ast_vm_user *next;
166 char msg_format[512];
167 struct vm_zone *next;
186 static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg, int option);
187 static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context);
188 static int play_record_review(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime, char *fmt, int outsidecaller, struct ast_vm_user *vmu, int *duration, const char *unlockdir);
189 static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc);
190 static int vm_play_folder_name(struct ast_channel *chan, char *mbox);
192 #ifdef USE_ODBC_STORAGE
193 static char odbc_database[80];
194 #define RETRIEVE(a,b) retrieve_file(a,b)
195 #define DISPOSE(a,b) remove_file(a,b)
196 #define STORE(a,b) store_file(a,b)
197 #define EXISTS(a,b,c,d) (message_exists(a,b))
198 #define RENAME(a,b,c,d,e,f) (rename_file(a,b,c,d))
199 #define COPY(a,b,c,d,e,f) (copy_file(a,b,c,d))
200 #define DELETE(a,b,c) (delete_file(a,b))
202 #define RETRIEVE(a,b)
205 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
206 #define RENAME(a,b,c,d,e,f) (rename_file(e,f));
207 #define COPY(a,b,c,d,e,f) (copy_file(e,f));
208 #define DELETE(a,b,c) (vm_delete(c))
211 static char VM_SPOOL_DIR[AST_CONFIG_MAX_PATH];
213 static char ext_pass_cmd[128];
215 static char *tdesc = "Comedian Mail (Voicemail System)";
217 static char *addesc = "Comedian Mail";
219 static char *synopsis_vm =
220 "Leave a voicemail message";
222 static char *descrip_vm =
223 " VoiceMail([s|u|b]extension[@context][&extension[@context]][...]): Leaves"
224 "voicemail for a given extension (must be configured in voicemail.conf).\n"
225 " If the extension is preceded by \n"
226 "* 's' then instructions for leaving the message will be skipped.\n"
227 "* 'u' then the \"unavailable\" message will be played.\n"
228 " (/var/lib/asterisk/sounds/vm/<exten>/unavail) if it exists.\n"
229 "* 'b' then the the busy message will be played (that is, busy instead of unavail).\n"
230 "If the caller presses '0' (zero) during the prompt, the call jumps to\n"
231 "extension 'o' in the current context.\n"
232 "If the caller presses '*' during the prompt, the call jumps to\n"
233 "extension 'a' in the current context.\n"
234 "If the requested mailbox does not exist, and there exists a priority\n"
235 "n + 101, then that priority will be taken next.\n"
236 "When multiple mailboxes are specified, the unavailable or busy message\n"
237 "will be taken from the first mailbox specified.\n"
238 "Returns -1 on error or mailbox not found, or if the user hangs up.\n"
239 "Otherwise, it returns 0.\n";
241 static char *synopsis_vmain =
242 "Enter voicemail system";
244 static char *descrip_vmain =
245 " VoiceMailMain([[s]mailbox][@context]): Enters the main voicemail system\n"
246 "for the checking of voicemail. The mailbox can be passed as the option,\n"
247 "which will stop the voicemail system from prompting the user for the mailbox.\n"
248 "If the mailbox is preceded by 's' then the password check will be skipped. If\n"
249 "the mailbox is preceded by 'p' then the supplied mailbox is prepended to the\n"
250 "user's entry and the resulting string is used as the mailbox number. This is\n"
251 "useful for virtual hosting of voicemail boxes. If a context is specified,\n"
252 "logins are considered in that voicemail context only.\n"
253 "Returns -1 if the user hangs up or 0 otherwise.\n";
255 static char *synopsis_vm_box_exists =
256 "Check if vmbox exists";
258 static char *descrip_vm_box_exists =
259 " MailboxExists(mailbox[@context]): Conditionally branches to priority n+101\n"
260 "if the specified voice mailbox exists.\n";
262 static char *synopsis_vmauthenticate =
263 "Authenticate off voicemail passwords";
265 static char *descrip_vmauthenticate =
266 " VMAuthenticate([mailbox][@context]): Behaves identically to the Authenticate\n"
267 "application, with the exception that the passwords are taken from\n"
269 " If the mailbox is specified, only that mailbox's password will be considered\n"
270 "valid. If the mailbox is not specified, the channel variable AUTH_MAILBOX will\n"
271 "be set with the authenticated mailbox.\n";
273 /* Leave a message */
274 static char *app = "VoiceMail";
276 /* Check mail, control, etc */
277 static char *app2 = "VoiceMailMain";
279 static char *app3 = "MailboxExists";
280 static char *app4 = "VMAuthenticate";
282 AST_MUTEX_DEFINE_STATIC(vmlock);
283 struct ast_vm_user *users;
284 struct ast_vm_user *usersl;
285 struct vm_zone *zones = NULL;
286 struct vm_zone *zonesl = NULL;
287 static int maxsilence;
288 static int silencethreshold = 128;
289 static char serveremail[80];
290 static char mailcmd[160]; /* Configurable mail cmd */
291 static char externnotify[160];
293 static char vmfmts[80];
294 static int vmminmessage;
295 static int vmmaxmessage;
298 static int maxlogins;
300 static struct ast_flags globalflags = {0};
302 static int saydurationminfo;
304 static char dialcontext[80];
305 static char callcontext[80];
306 static char exitcontext[80];
308 static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
311 static char *emailbody = NULL;
312 static char *emailsubject = NULL;
313 static char fromstring[100];
314 static char pagerfromstring[100];
315 static char emailtitle[100];
316 static char charset[32] = "ISO-8859-1";
318 static char adsifdn[4] = "\x00\x00\x00\x0F";
319 static char adsisec[4] = "\x9B\xDB\xF7\xAC";
320 static int adsiver = 1;
326 static void populate_defaults(struct ast_vm_user *vmu)
328 ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
329 if (saydurationminfo>0)
330 vmu->saydurationm = saydurationminfo;
332 strncpy(vmu->callback, callcontext, sizeof(vmu->callback) -1);
334 strncpy(vmu->dialout, dialcontext, sizeof(vmu->dialout) -1);
336 strncpy(vmu->exit, exitcontext, sizeof(vmu->exit) -1);
339 static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
342 if (!strcasecmp(var, "attach")) {
343 ast_set2_flag(vmu, ast_true(value), VM_ATTACH);
344 } else if (!strcasecmp(var, "serveremail")) {
345 strncpy(vmu->serveremail, value, sizeof(vmu->serveremail) - 1);
346 } else if (!strcasecmp(var, "language")) {
347 strncpy(vmu->language, value, sizeof(vmu->language) - 1);
348 } else if (!strcasecmp(var, "tz")) {
349 strncpy(vmu->zonetag, value, sizeof(vmu->zonetag) - 1);
350 } else if (!strcasecmp(var, "delete")) {
351 ast_set2_flag(vmu, ast_true(value), VM_DELETE);
352 } else if (!strcasecmp(var, "saycid")){
353 ast_set2_flag(vmu, ast_true(value), VM_SAYCID);
354 } else if (!strcasecmp(var,"sendvoicemail")){
355 ast_set2_flag(vmu, ast_true(value), VM_SVMAIL);
356 } else if (!strcasecmp(var, "review")){
357 ast_set2_flag(vmu, ast_true(value), VM_REVIEW);
358 } else if (!strcasecmp(var, "operator")){
359 ast_set2_flag(vmu, ast_true(value), VM_OPERATOR);
360 } else if (!strcasecmp(var, "envelope")){
361 ast_set2_flag(vmu, ast_true(value), VM_ENVELOPE);
362 } else if (!strcasecmp(var, "sayduration")){
363 ast_set2_flag(vmu, ast_true(value), VM_SAYDURATION);
364 } else if (!strcasecmp(var, "saydurationm")){
365 if (sscanf(value, "%d", &x) == 1) {
366 vmu->saydurationm = x;
368 ast_log(LOG_WARNING, "Invalid min duration for say duration\n");
370 } else if (!strcasecmp(var, "forcename")){
371 ast_set2_flag(vmu, ast_true(value), VM_FORCENAME);
372 } else if (!strcasecmp(var, "forcegreetings")){
373 ast_set2_flag(vmu, ast_true(value), VM_FORCEGREET);
374 } else if (!strcasecmp(var, "callback")) {
375 strncpy(vmu->callback, value, sizeof(vmu->callback) -1);
376 } else if (!strcasecmp(var, "dialout")) {
377 strncpy(vmu->dialout, value, sizeof(vmu->dialout) -1);
378 } else if (!strcasecmp(var, "exitcontext")) {
379 strncpy(vmu->exit, value, sizeof(vmu->exit) -1);
383 static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
386 if (!ast_strlen_zero(vmu->uniqueid)) {
387 res = ast_update_realtime("voicemail", "uniqueid", vmu->uniqueid, "password", password, NULL);
389 strncpy(vmu->password, password, sizeof(vmu->password) - 1);
395 static void apply_options(struct ast_vm_user *vmu, const char *options)
396 { /* Destructively Parse options and apply */
400 stringp = ast_strdupa(options);
401 while ((s = strsep(&stringp, "|"))) {
403 if ((var = strsep(&value, "=")) && value) {
404 apply_option(vmu, var, value);
409 static struct ast_vm_user *find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
411 struct ast_variable *var, *tmp;
412 struct ast_vm_user *retval;
417 retval=malloc(sizeof(struct ast_vm_user));
420 memset(retval, 0, sizeof(struct ast_vm_user));
422 ast_set_flag(retval, VM_ALLOCED);
424 strncpy(retval->mailbox, mailbox, sizeof(retval->mailbox) - 1);
426 strncpy(retval->context, context, sizeof(retval->context) - 1);
428 strncpy(retval->context, "default", sizeof(retval->context) - 1);
429 populate_defaults(retval);
430 var = ast_load_realtime("voicemail", "mailbox", mailbox, "context", retval->context, NULL);
434 printf("%s => %s\n", tmp->name, tmp->value);
435 if (!strcasecmp(tmp->name, "password")) {
436 strncpy(retval->password, tmp->value, sizeof(retval->password) - 1);
437 } else if (!strcasecmp(tmp->name, "uniqueid")) {
438 strncpy(retval->uniqueid, tmp->value, sizeof(retval->uniqueid) - 1);
439 } else if (!strcasecmp(tmp->name, "pager")) {
440 strncpy(retval->pager, tmp->value, sizeof(retval->pager) - 1);
441 } else if (!strcasecmp(tmp->name, "email")) {
442 strncpy(retval->email, tmp->value, sizeof(retval->email) - 1);
443 } else if (!strcasecmp(tmp->name, "fullname")) {
444 strncpy(retval->fullname, tmp->value, sizeof(retval->fullname) - 1);
446 apply_option(retval, tmp->name, tmp->value);
458 static struct ast_vm_user *find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
460 /* This function could be made to generate one from a database, too */
461 struct ast_vm_user *vmu=NULL, *cur;
462 ast_mutex_lock(&vmlock);
465 if ((!context || !strcasecmp(context, cur->context)) &&
466 (!strcasecmp(mailbox, cur->mailbox)))
474 /* Make a copy, so that on a reload, we have no race */
475 vmu = malloc(sizeof(struct ast_vm_user));
477 memcpy(vmu, cur, sizeof(struct ast_vm_user));
478 ast_set2_flag(vmu, !ivm, VM_ALLOCED);
482 vmu = find_user_realtime(ivm, context, mailbox);
483 ast_mutex_unlock(&vmlock);
487 static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
489 /* This function could be made to generate one from a database, too */
490 struct ast_vm_user *cur;
492 ast_mutex_lock(&vmlock);
495 if ((!context || !strcasecmp(context, cur->context)) &&
496 (!strcasecmp(mailbox, cur->mailbox)))
501 strncpy(cur->password, newpass, sizeof(cur->password) - 1);
504 ast_mutex_unlock(&vmlock);
508 static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
510 /* There's probably a better way of doing this. */
511 /* That's why I've put the password change in a separate function. */
512 /* This could also be done with a database function */
519 char currcontext[256] ="";
520 char tmpin[AST_CONFIG_MAX_PATH];
521 char tmpout[AST_CONFIG_MAX_PATH];
522 char *user, *pass, *rest, *trim, *tempcontext;
525 if (!change_password_realtime(vmu, newpassword))
529 snprintf(tmpin, sizeof(tmpin), "%s/voicemail.conf", ast_config_AST_CONFIG_DIR);
530 snprintf(tmpout, sizeof(tmpout), "%s/voicemail.conf.new", ast_config_AST_CONFIG_DIR);
531 configin = fopen(tmpin,"r");
533 configout = fopen(tmpout,"w+");
536 if (!configin || !configout) {
540 ast_log(LOG_WARNING, "Warning: Unable to open '%s' for reading: %s\n", tmpin, strerror(errno));
544 ast_log(LOG_WARNING, "Warning: Unable to open '%s' for writing: %s\n", tmpout, strerror(errno));
548 while (!feof(configin)) {
549 /* Read in the line */
550 fgets(inbuf, sizeof(inbuf), configin);
552 if (!feof(configin)) {
553 /* Make a backup of it */
554 memcpy(orig, inbuf, sizeof(orig));
555 /* Strip trailing \n and comment */
556 inbuf[strlen(inbuf) - 1] = '\0';
557 user = strchr(inbuf, ';');
563 /* check for '[' (opening of context name ) */
564 tempcontext = strchr(user, '[');
566 strncpy(currcontext, tempcontext +1, sizeof(currcontext) - 1);
567 /* now check for ']' */
568 tempcontext = strchr(currcontext, ']');
572 currcontext[0] = '\0';
574 pass = strchr(user, '=');
577 while (*trim && *trim < 33) {
587 while (*pass && *pass < 33)
591 rest = strchr(pass,',');
599 /* Compare user, pass AND context */
600 if (user && *user && !strcmp(user, vmu->mailbox) &&
601 pass && !strcmp(pass, vmu->password) &&
602 currcontext && *currcontext && !strcmp(currcontext, vmu->context)) {
603 /* This is the line */
605 fprintf(configout, "%s => %s,%s\n", vmu->mailbox,newpassword,rest);
607 fprintf(configout, "%s => %s\n", vmu->mailbox,newpassword);
610 /* Put it back like it was */
611 fprintf(configout, orig);
618 stat((char *)tmpin, &statbuf);
619 chmod((char *)tmpout, statbuf.st_mode);
620 chown((char *)tmpout, statbuf.st_uid, statbuf.st_gid);
621 unlink((char *)tmpin);
622 rename((char *)tmpout,(char *)tmpin);
623 reset_user_pw(vmu->context, vmu->mailbox, newpassword);
624 strncpy(vmu->password, newpassword, sizeof(vmu->password) - 1);
627 static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
630 snprintf(buf,255,"%s %s %s %s",ext_pass_cmd,vmu->context,vmu->mailbox,newpassword);
631 ast_safe_system(buf);
634 static int make_dir(char *dest, int len, char *context, char *ext, char *mailbox)
636 return snprintf(dest, len, "%s%s/%s/%s", VM_SPOOL_DIR, context, ext, mailbox);
639 static int make_file(char *dest, int len, char *dir, int num)
641 return snprintf(dest, len, "%s/msg%04d", dir, num);
645 #ifdef USE_ODBC_STORAGE
646 static int retrieve_file(char *dir, int msgnum)
654 SQLSMALLINT colcount=0;
661 SQLSMALLINT datatype;
662 SQLSMALLINT decimaldigits;
663 SQLSMALLINT nullable;
672 obj = fetch_odbc_obj(odbc_database, 0);
674 strncpy(fmt, vmfmts, sizeof(fmt) - 1);
675 c = strchr(fmt, '|');
678 if (!strcasecmp(fmt, "wav49"))
679 strncpy(fmt, "WAV", sizeof(fmt));
680 snprintf(msgnums, sizeof(msgnums),"%d", msgnum);
682 make_file(fn, sizeof(fn), dir, msgnum);
684 strncpy(fn, dir, sizeof(fn) - 1);
685 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
686 f = fopen(full_fn, "w+");
687 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
688 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
689 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
690 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
693 snprintf(sql, sizeof(sql), "SELECT * FROM voicemessages WHERE dir=? AND msgnum=?");
694 res = SQLPrepare(stmt, sql, SQL_NTS);
695 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
696 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
697 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
700 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(dir), 0, (void *)dir, 0, NULL);
701 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(msgnums), 0, (void *)msgnums, 0, NULL);
702 res = odbc_smart_execute(obj, stmt);
703 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
704 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
705 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
708 res = SQLRowCount(stmt, &rowcount);
709 if (((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO))) {
710 ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
711 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
715 fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC);
717 ast_log(LOG_WARNING, "Failed to write '%s': %s\n", full_fn, strerror(errno));
718 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
721 res = SQLNumResultCols(stmt, &colcount);
722 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
723 ast_log(LOG_WARNING, "SQL Column Count error!\n[%s]\n\n", sql);
724 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
727 res = SQLFetch(stmt);
728 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
729 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
730 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
734 fprintf(f, "[message]\n");
735 for (x=0;x<colcount;x++) {
737 collen = sizeof(coltitle);
738 res = SQLDescribeCol(stmt, x + 1, coltitle, sizeof(coltitle), &collen,
739 &datatype, &colsize, &decimaldigits, &nullable);
740 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
741 ast_log(LOG_WARNING, "SQL Describe Column error!\n[%s]\n\n", sql);
742 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
745 if (!strcmp(coltitle, "recording")) {
746 res = SQLGetData(stmt, x + 1, SQL_BINARY, NULL, 0, &colsize);
748 fd = open(full_fn, O_RDWR | O_TRUNC | O_CREAT, 0770);
751 lseek(fd, fdlen - 1, SEEK_SET);
752 if (write(fd, tmp, 1) != 1) {
757 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
760 memset(fdm, 0, fdlen);
761 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, fdlen, &colsize);
762 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
763 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
764 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
769 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
770 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
771 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
772 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
775 if (strcmp(coltitle, "msgnum") && strcmp(coltitle, "dir") && f)
776 fprintf(f, "%s=%s\n", coltitle, rowdata);
780 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
782 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
793 static int remove_file(char *dir, int msgnum)
800 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
801 make_file(fn, sizeof(fn), dir, msgnum);
803 strncpy(fn, dir, sizeof(fn) - 1);
804 ast_filedelete(fn, NULL);
805 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
810 static int last_message_index(char *dir)
820 obj = fetch_odbc_obj(odbc_database, 0);
822 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
823 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
824 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
827 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM voicemessages WHERE dir=?");
828 res = SQLPrepare(stmt, sql, SQL_NTS);
829 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
830 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
831 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
834 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(dir), 0, (void *)dir, 0, NULL);
835 res = odbc_smart_execute(obj, stmt);
836 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
837 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
838 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
841 res = SQLRowCount(stmt, &rowcount);
842 if (((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) || (rowcount < 1)) {
843 ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
844 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
847 res = SQLFetch(stmt);
848 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
849 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
850 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
853 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
854 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
855 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
856 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
859 if (sscanf(rowdata, "%i", &x) != 1)
860 ast_log(LOG_WARNING, "Failed to read message count!\n");
861 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
863 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
868 static int message_exists(char *dir, int msgnum)
879 obj = fetch_odbc_obj(odbc_database, 0);
881 snprintf(msgnums, sizeof(msgnums), "%d", msgnum);
882 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
883 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
884 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
887 snprintf(sql, sizeof(sql), "SELECT COUNT(*) FROM voicemessages WHERE dir=? AND msgnum=?");
888 res = SQLPrepare(stmt, sql, SQL_NTS);
889 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
890 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
891 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
894 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(dir), 0, (void *)dir, 0, NULL);
895 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(msgnums), 0, (void *)msgnums, 0, NULL);
896 res = odbc_smart_execute(obj, stmt);
897 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
898 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
899 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
902 res = SQLRowCount(stmt, &rowcount);
903 if (((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) || (rowcount < 1)) {
904 ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
905 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
908 res = SQLFetch(stmt);
909 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
910 ast_log(LOG_WARNING, "SQL Fetch error!\n[%s]\n\n", sql);
911 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
914 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata, sizeof(rowdata), NULL);
915 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
916 ast_log(LOG_WARNING, "SQL Get Data error!\n[%s]\n\n", sql);
917 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
920 if (sscanf(rowdata, "%i", &x) != 1)
921 ast_log(LOG_WARNING, "Failed to read message count!\n");
922 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
924 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
930 static int count_messages(char *dir)
932 return last_message_index(dir) + 1;
934 static void delete_file(char *sdir, int smsg)
943 obj = fetch_odbc_obj(odbc_database, 0);
945 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
946 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
947 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
948 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
951 snprintf(sql, sizeof(sql), "DELETE FROM voicemessages WHERE dir=? AND msgnum=?");
952 res = SQLPrepare(stmt, sql, SQL_NTS);
953 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
954 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
955 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
958 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(sdir), 0, (void *)sdir, 0, NULL);
959 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(msgnums), 0, (void *)msgnums, 0, NULL);
960 res = odbc_smart_execute(obj, stmt);
961 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
962 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
963 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
966 res = SQLRowCount(stmt, &rowcount);
967 if (((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO))) {
968 ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
969 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
972 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
974 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
979 static void copy_file(char *sdir, int smsg, char *ddir, int dmsg)
989 delete_file(ddir, dmsg);
990 obj = fetch_odbc_obj(odbc_database, 0);
992 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
993 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
994 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
995 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
996 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
999 snprintf(sql, sizeof(sql), "INSERT INTO voicemessages (dir, msgnum, context, macrocontext, callerid, origtime, duration, recording) SELECT ?,?,context,macrocontext,callerid,origtime,duration,recording FROM voicemessages WHERE dir=? AND msgnum=?");
1000 res = SQLPrepare(stmt, sql, SQL_NTS);
1001 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1002 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
1003 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1006 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(ddir), 0, (void *)ddir, 0, NULL);
1007 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(msgnumd), 0, (void *)msgnumd, 0, NULL);
1008 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(sdir), 0, (void *)sdir, 0, NULL);
1009 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(msgnums), 0, (void *)msgnums, 0, NULL);
1010 res = odbc_smart_execute(obj, stmt);
1011 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1012 ast_log(LOG_WARNING, "SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
1013 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1016 res = SQLRowCount(stmt, &rowcount);
1017 if (((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) || (rowcount < 1)) {
1018 ast_log(LOG_WARNING, "SQL Row Count error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
1019 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1022 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1024 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
1029 static int store_file(char *dir, int msgnum)
1045 char *context="", *macrocontext="", *callerid="", *origtime="", *duration="";
1046 char *category = "";
1047 struct ast_config *cfg=NULL;
1050 delete_file(dir, msgnum);
1051 obj = fetch_odbc_obj(odbc_database, 0);
1053 strncpy(fmt, vmfmts, sizeof(fmt) - 1);
1054 c = strchr(fmt, '|');
1057 if (!strcasecmp(fmt, "wav49"))
1058 strncpy(fmt, "WAV", sizeof(fmt));
1059 snprintf(msgnums, sizeof(msgnums),"%d", msgnum);
1061 make_file(fn, sizeof(fn), dir, msgnum);
1063 strncpy(fn, dir, sizeof(fn) - 1);
1064 snprintf(full_fn, sizeof(full_fn), "%s.txt", fn);
1065 cfg = ast_config_load(full_fn);
1066 snprintf(full_fn, sizeof(full_fn), "%s.%s", fn, fmt);
1067 fd = open(full_fn, O_RDWR);
1069 ast_log(LOG_WARNING, "Open of sound file '%s' failed: %s\n", full_fn, strerror(errno));
1073 context = ast_variable_retrieve(cfg, "message", "context");
1074 if (!context) context = "";
1075 macrocontext = ast_variable_retrieve(cfg, "message", "macrocontext");
1076 if (!macrocontext) macrocontext = "";
1077 callerid = ast_variable_retrieve(cfg, "message", "callerid");
1078 if (!callerid) callerid = "";
1079 origtime = ast_variable_retrieve(cfg, "message", "origtime");
1080 if (!origtime) origtime = "";
1081 duration = ast_variable_retrieve(cfg, "message", "duration");
1082 if (!duration) duration = "";
1083 category = ast_variable_retrieve(cfg, "message", "category");
1084 if (!category) category = "";
1086 fdlen = lseek(fd, 0, SEEK_END);
1087 lseek(fd, 0, SEEK_SET);
1088 printf("Length is %d\n", fdlen);
1089 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED,fd, 0);
1091 ast_log(LOG_WARNING, "Memory map failed!\n");
1094 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
1095 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1096 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
1099 if (!ast_strlen_zero(category))
1100 snprintf(sql, sizeof(sql), "INSERT INTO voicemessages (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,category) VALUES (?,?,?,?,?,?,?,?,?)");
1102 snprintf(sql, sizeof(sql), "INSERT INTO voicemessages (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration) VALUES (?,?,?,?,?,?,?,?)");
1103 res = SQLPrepare(stmt, sql, SQL_NTS);
1104 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1105 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
1106 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1109 len = fdlen; /* SQL_LEN_DATA_AT_EXEC(fdlen); */
1110 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(dir), 0, (void *)dir, 0, NULL);
1111 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(msgnums), 0, (void *)msgnums, 0, NULL);
1112 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_BINARY, fdlen, 0, (void *)fdm, fdlen, &len);
1113 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(context), 0, (void *)context, 0, NULL);
1114 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(macrocontext), 0, (void *)macrocontext, 0, NULL);
1115 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(callerid), 0, (void *)callerid, 0, NULL);
1116 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(origtime), 0, (void *)origtime, 0, NULL);
1117 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(duration), 0, (void *)duration, 0, NULL);
1118 if (!ast_strlen_zero(category))
1119 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(category), 0, (void *)category, 0, NULL);
1120 res = odbc_smart_execute(obj, stmt);
1121 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1122 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
1123 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1126 res = SQLRowCount(stmt, &rowcount);
1127 if (((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) || (rowcount < 1)) {
1128 ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
1129 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1132 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1134 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
1137 ast_config_destroy(cfg);
1145 static void rename_file(char *sdir, int smsg, char *ddir, int dmsg)
1155 delete_file(ddir, dmsg);
1156 obj = fetch_odbc_obj(odbc_database, 0);
1158 snprintf(msgnums, sizeof(msgnums), "%d", smsg);
1159 snprintf(msgnumd, sizeof(msgnumd), "%d", dmsg);
1160 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->con, &stmt);
1161 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1162 ast_log(LOG_WARNING, "SQL Alloc Handle failed!\n");
1165 snprintf(sql, sizeof(sql), "UPDATE voicemessages SET dir=?, msgnum=? WHERE dir=? AND msgnum=?");
1166 res = SQLPrepare(stmt, sql, SQL_NTS);
1167 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1168 ast_log(LOG_WARNING, "SQL Prepare failed![%s]\n", sql);
1169 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1172 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(ddir), 0, (void *)ddir, 0, NULL);
1173 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(msgnumd), 0, (void *)msgnumd, 0, NULL);
1174 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(sdir), 0, (void *)sdir, 0, NULL);
1175 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(msgnums), 0, (void *)msgnums, 0, NULL);
1176 res = odbc_smart_execute(obj, stmt);
1177 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
1178 ast_log(LOG_WARNING, "SQL Execute error!\n[%s]\n\n", sql);
1179 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1182 res = SQLRowCount(stmt, &rowcount);
1183 if (((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) || (rowcount < 1)) {
1184 ast_log(LOG_WARNING, "SQL Row Count error!\n[%s]\n\n", sql);
1185 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1188 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
1190 ast_log(LOG_WARNING, "Failed to obtain database object for '%s'!\n", odbc_database);
1197 static int count_messages(char *dir)
1199 /* Find all .txt files - even if they are not in sequence from 0000 */
1203 struct dirent *vment = NULL;
1205 if ((vmdir = opendir(dir))) {
1206 while ((vment = readdir(vmdir)))
1208 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7,".txt",4))
1219 static void rename_file(char *sfn, char *dfn)
1223 ast_filerename(sfn,dfn,NULL);
1224 snprintf(stxt, sizeof(stxt), "%s.txt", sfn);
1225 snprintf(dtxt, sizeof(dtxt), "%s.txt", dfn);
1229 static int copy(char *infile, char *outfile)
1237 #ifdef HARDLINK_WHEN_POSSIBLE
1238 /* Hard link if possible; saves disk space & is faster */
1239 if (link(infile, outfile)) {
1241 if ((ifd = open(infile, O_RDONLY)) < 0) {
1242 ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile);
1245 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) {
1246 ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile);
1251 len = read(ifd, buf, sizeof(buf));
1253 ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno));
1259 res = write(ofd, buf, len);
1261 ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno));
1271 #ifdef HARDLINK_WHEN_POSSIBLE
1273 /* Hard link succeeded */
1279 static void copy_file(char *frompath, char *topath)
1281 char frompath2[256],topath2[256];
1282 ast_filecopy(frompath, topath, NULL);
1283 snprintf(frompath2, sizeof(frompath2), "%s.txt", frompath);
1284 snprintf(topath2, sizeof(topath2), "%s.txt", topath);
1285 copy(frompath2, topath2);
1288 static int last_message_index(char *dir)
1293 for (x=0;x<MAXMSG;x++) {
1294 make_file(fn, sizeof(fn), dir, x);
1295 if (ast_fileexists(fn, NULL, NULL) < 1)
1298 ast_unlock_path(dir);
1302 static int vm_delete(char *file)
1307 txtsize = (strlen(file) + 5)*sizeof(char);
1308 txt = (char *)alloca(txtsize);
1309 /* Sprintf here would safe because we alloca'd exactly the right length,
1310 * but trying to eliminate all sprintf's anyhow
1312 snprintf(txt, txtsize, "%s.txt", file);
1314 return ast_filedelete(file, NULL);
1320 inbuf(struct baseio *bio, FILE *fi)
1327 if ((l = fread(bio->iobuf,1,BASEMAXINLINE,fi)) <= 0) {
1342 inchar(struct baseio *bio, FILE *fi)
1344 if (bio->iocp>=bio->iolen) {
1345 if (!inbuf(bio, fi))
1349 return bio->iobuf[bio->iocp++];
1353 ochar(struct baseio *bio, int c, FILE *so)
1355 if (bio->linelength>=BASELINELEN) {
1356 if (fputs(eol,so)==EOF)
1362 if (putc(((unsigned char)c),so)==EOF)
1370 static int base_encode(char *filename, FILE *so)
1372 unsigned char dtable[BASEMAXINLINE];
1377 memset(&bio, 0, sizeof(bio));
1378 bio.iocp = BASEMAXINLINE;
1380 if (!(fi = fopen(filename, "rb"))) {
1381 ast_log(LOG_WARNING, "Failed to open log file: %s: %s\n", filename, strerror(errno));
1385 for (i= 0;i<9;i++) {
1388 dtable[26+i]= 'a'+i;
1389 dtable[26+i+9]= 'j'+i;
1391 for (i= 0;i<8;i++) {
1392 dtable[i+18]= 'S'+i;
1393 dtable[26+i+18]= 's'+i;
1395 for (i= 0;i<10;i++) {
1396 dtable[52+i]= '0'+i;
1402 unsigned char igroup[3],ogroup[4];
1405 igroup[0]= igroup[1]= igroup[2]= 0;
1407 for (n= 0;n<3;n++) {
1408 if ((c = inchar(&bio, fi)) == EOF) {
1413 igroup[n]= (unsigned char)c;
1417 ogroup[0]= dtable[igroup[0]>>2];
1418 ogroup[1]= dtable[((igroup[0]&3)<<4)|(igroup[1]>>4)];
1419 ogroup[2]= dtable[((igroup[1]&0xF)<<2)|(igroup[2]>>6)];
1420 ogroup[3]= dtable[igroup[2]&0x3F];
1430 ochar(&bio, ogroup[i], so);
1434 if (fputs(eol,so)==EOF)
1442 static void prep_email_sub_vars(struct ast_channel *ast, struct ast_vm_user *vmu, int msgnum, char *mailbox, char *cidnum, char *cidname, char *dur, char *date, char *passdata, size_t passdatasize)
1445 /* Prepare variables for substition in email body and subject */
1446 pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname);
1447 pbx_builtin_setvar_helper(ast, "VM_DUR", dur);
1448 snprintf(passdata, passdatasize, "%d", msgnum);
1449 pbx_builtin_setvar_helper(ast, "VM_MSGNUM", passdata);
1450 pbx_builtin_setvar_helper(ast, "VM_MAILBOX", mailbox);
1451 pbx_builtin_setvar_helper(ast, "VM_CALLERID", ast_callerid_merge(callerid, sizeof(callerid), cidname, cidnum, "Unknown Caller"));
1452 pbx_builtin_setvar_helper(ast, "VM_CIDNAME", (cidname ? cidname : "an unknown caller"));
1453 pbx_builtin_setvar_helper(ast, "VM_CIDNUM", (cidnum ? cidnum : "an unknown caller"));
1454 pbx_builtin_setvar_helper(ast, "VM_DATE", date);
1457 static int sendmail(char *srcemail, struct ast_vm_user *vmu, int msgnum, char *mailbox, char *cidnum, char *cidname, char *attach, char *format, int duration, int attach_user_voicemail)
1467 char tmp[80] = "/tmp/astmail-XXXXXX";
1471 struct vm_zone *the_zone = NULL;
1472 if (vmu && ast_strlen_zero(vmu->email)) {
1473 ast_log(LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox);
1476 if (!strcmp(format, "wav49"))
1478 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));
1479 /* Make a temporary file instead of piping directly to sendmail, in case the mail
1483 p = fdopen(pfd, "w");
1490 gethostname(host, sizeof(host));
1491 if (strchr(srcemail, '@'))
1492 strncpy(who, srcemail, sizeof(who)-1);
1494 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
1496 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
1499 /* Does this user have a timezone specified? */
1500 if (!ast_strlen_zero(vmu->zonetag)) {
1501 /* Find the zone in the list */
1505 if (!strcmp(z->name, vmu->zonetag)) {
1514 ast_localtime(&t,&tm,the_zone->timezone);
1516 ast_localtime(&t,&tm,NULL);
1517 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", &tm);
1518 fprintf(p, "Date: %s\n", date);
1521 struct ast_channel *ast = ast_channel_alloc(0);
1524 int vmlen = strlen(fromstring)*3 + 200;
1525 if ((passdata = alloca(vmlen))) {
1526 memset(passdata, 0, vmlen);
1527 prep_email_sub_vars(ast,vmu,msgnum + 1,mailbox,cidnum, cidname,dur,date,passdata, vmlen);
1528 pbx_substitute_variables_helper(ast,fromstring,passdata,vmlen);
1529 fprintf(p, "From: %s <%s>\n",passdata,who);
1530 } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
1531 ast_channel_free(ast);
1532 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
1534 fprintf(p, "From: Asterisk PBX <%s>\n", who);
1535 fprintf(p, "To: %s <%s>\n", vmu->fullname, vmu->email);
1538 struct ast_channel *ast = ast_channel_alloc(0);
1541 int vmlen = strlen(emailsubject)*3 + 200;
1542 if ((passdata = alloca(vmlen))) {
1543 memset(passdata, 0, vmlen);
1544 prep_email_sub_vars(ast,vmu,msgnum + 1,mailbox,cidnum, cidname,dur,date,passdata, vmlen);
1545 pbx_substitute_variables_helper(ast,emailsubject,passdata,vmlen);
1546 fprintf(p, "Subject: %s\n",passdata);
1547 } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
1548 ast_channel_free(ast);
1549 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
1552 fprintf(p, emailtitle, msgnum + 1, mailbox) ;
1554 } else if (ast_test_flag((&globalflags), VM_PBXSKIP))
1555 fprintf(p, "Subject: New message %d in mailbox %s\n", msgnum + 1, mailbox);
1557 fprintf(p, "Subject: [PBX]: New message %d in mailbox %s\n", msgnum + 1, mailbox);
1558 fprintf(p, "Message-ID: <Asterisk-%d-%d-%s-%d@%s>\n", msgnum, (unsigned int)rand(), mailbox, getpid(), host);
1559 fprintf(p, "MIME-Version: 1.0\n");
1560 if (attach_user_voicemail) {
1561 /* Something unique. */
1562 snprintf(bound, sizeof(bound), "voicemail_%d%s%d%d", msgnum, mailbox, getpid(), (unsigned int)rand());
1564 fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"\n\n\n", bound);
1566 fprintf(p, "--%s\n", bound);
1568 fprintf(p, "Content-Type: text/plain; charset=%s\nContent-Transfer-Encoding: 8bit\n\n", charset);
1569 strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm);
1571 struct ast_channel *ast = ast_channel_alloc(0);
1574 int vmlen = strlen(emailbody)*3 + 200;
1575 if ((passdata = alloca(vmlen))) {
1576 memset(passdata, 0, vmlen);
1577 prep_email_sub_vars(ast,vmu,msgnum + 1,mailbox,cidnum, cidname,dur,date,passdata, vmlen);
1578 pbx_substitute_variables_helper(ast,emailbody,passdata,vmlen);
1579 fprintf(p, "%s\n",passdata);
1580 } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
1581 ast_channel_free(ast);
1582 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
1584 fprintf(p, "Dear %s:\n\n\tJust wanted to let you know you were just left a %s long message (number %d)\n"
1586 "in mailbox %s from %s, on %s so you might\n"
1587 "want to check it when you get a chance. Thanks!\n\n\t\t\t\t--Asterisk\n\n", vmu->fullname,
1588 dur, msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date);
1590 if (attach_user_voicemail) {
1591 fprintf(p, "--%s\n", bound);
1592 fprintf(p, "Content-Type: audio/x-%s; name=\"msg%04d.%s\"\n", format, msgnum, format);
1593 fprintf(p, "Content-Transfer-Encoding: base64\n");
1594 fprintf(p, "Content-Description: Voicemail sound attachment.\n");
1595 fprintf(p, "Content-Disposition: attachment; filename=\"msg%04d.%s\"\n\n", msgnum, format);
1597 snprintf(fname, sizeof(fname), "%s.%s", attach, format);
1598 base_encode(fname, p);
1599 fprintf(p, "\n\n--%s--\n.\n", bound);
1602 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
1603 ast_safe_system(tmp2);
1604 ast_log(LOG_DEBUG, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd);
1606 ast_log(LOG_WARNING, "Unable to launch '%s'\n", mailcmd);
1612 static int sendpage(char *srcemail, char *pager, int msgnum, char *mailbox, char *cidnum, char *cidname, int duration, struct ast_vm_user *vmu)
1620 char tmp[80] = "/tmp/astmail-XXXXXX";
1624 struct vm_zone *the_zone = NULL;
1628 p = fdopen(pfd, "w");
1636 gethostname(host, sizeof(host));
1637 if (strchr(srcemail, '@'))
1638 strncpy(who, srcemail, sizeof(who)-1);
1640 snprintf(who, sizeof(who), "%s@%s", srcemail, host);
1642 snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60);
1645 /* Does this user have a timezone specified? */
1646 if (!ast_strlen_zero(vmu->zonetag)) {
1647 /* Find the zone in the list */
1651 if (!strcmp(z->name, vmu->zonetag)) {
1660 ast_localtime(&t,&tm,the_zone->timezone);
1662 ast_localtime(&t,&tm,NULL);
1664 strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", &tm);
1665 fprintf(p, "Date: %s\n", date);
1667 if (*pagerfromstring) {
1668 struct ast_channel *ast = ast_channel_alloc(0);
1671 int vmlen = strlen(fromstring)*3 + 200;
1672 if ((passdata = alloca(vmlen))) {
1673 memset(passdata, 0, vmlen);
1674 prep_email_sub_vars(ast,vmu,msgnum + 1,mailbox,cidnum, cidname,dur,date,passdata, vmlen);
1675 pbx_substitute_variables_helper(ast,pagerfromstring,passdata,vmlen);
1676 fprintf(p, "From: %s <%s>\n",passdata,who);
1678 ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n");
1679 ast_channel_free(ast);
1680 } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n");
1682 fprintf(p, "From: Asterisk PBX <%s>\n", who);
1683 fprintf(p, "To: %s\n", pager);
1684 fprintf(p, "Subject: New VM\n\n");
1685 strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm);
1686 fprintf(p, "New %s long msg in box %s\n"
1687 "from %s, on %s", dur, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date);
1689 snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
1690 ast_safe_system(tmp2);
1691 ast_log(LOG_DEBUG, "Sent page to %s with command '%s'\n", pager, mailcmd);
1693 ast_log(LOG_WARNING, "Unable to launch '%s'\n", mailcmd);
1699 static int get_date(char *s, int len)
1704 localtime_r(&t,&tm);
1705 return strftime(s, len, "%a %b %e %r %Z %Y", &tm);
1708 static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
1712 snprintf(fn, sizeof(fn), "%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
1714 if (ast_fileexists(fn, NULL, NULL) > 0) {
1715 res = ast_streamfile(chan, fn, chan->language);
1720 res = ast_waitstream(chan, ecodes);
1726 /* Dispose just in case */
1728 res = ast_streamfile(chan, "vm-theperson", chan->language);
1731 res = ast_waitstream(chan, ecodes);
1734 res = ast_say_digit_str(chan, ext, ecodes, chan->language);
1739 res = ast_streamfile(chan, "vm-isonphone", chan->language);
1741 res = ast_streamfile(chan, "vm-isunavail", chan->language);
1744 res = ast_waitstream(chan, ecodes);
1748 static void free_user(struct ast_vm_user *vmu)
1750 if (ast_test_flag(vmu, VM_ALLOCED))
1754 static void free_zone(struct vm_zone *z)
1759 static char *mbox(int id)
1787 static int has_voicemail(const char *mailbox, const char *folder)
1798 /* If no mailbox, return immediately */
1799 if (ast_strlen_zero(mailbox))
1801 if (strchr(mailbox, ',')) {
1802 strncpy(tmp, mailbox, sizeof(tmp) - 1);
1805 while((cur = strsep(&mb, ","))) {
1806 if (!ast_strlen_zero(cur)) {
1807 if (has_voicemail(cur, folder))
1813 strncpy(tmp, mailbox, sizeof(tmp) - 1);
1814 context = strchr(tmp, '@');
1819 context = "default";
1820 snprintf(fn, sizeof(fn), "%s/%s/%s/%s", VM_SPOOL_DIR, context, tmp, folder);
1824 while ((de = readdir(dir))) {
1825 if (!strncasecmp(de->d_name, "msg", 3))
1834 static int messagecount(const char *mailbox, int *newmsgs, int *oldmsgs)
1847 /* If no mailbox, return immediately */
1848 if (ast_strlen_zero(mailbox))
1850 if (strchr(mailbox, ',')) {
1852 strncpy(tmp, mailbox, sizeof(tmp) - 1);
1855 while((cur = strsep(&mb, ", "))) {
1856 if (!ast_strlen_zero(cur)) {
1857 if (messagecount(cur, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
1869 strncpy(tmp, mailbox, sizeof(tmp) - 1);
1870 context = strchr(tmp, '@');
1875 context = "default";
1877 snprintf(fn, sizeof(fn), "%s/%s/%s/INBOX", VM_SPOOL_DIR, context, tmp);
1880 while ((de = readdir(dir))) {
1881 if ((strlen(de->d_name) > 3) && !strncasecmp(de->d_name, "msg", 3) &&
1882 !strcasecmp(de->d_name + strlen(de->d_name) - 3, "txt"))
1890 snprintf(fn, sizeof(fn), "%s/%s/%s/Old", VM_SPOOL_DIR, context, tmp);
1893 while ((de = readdir(dir))) {
1894 if ((strlen(de->d_name) > 3) && !strncasecmp(de->d_name, "msg", 3) &&
1895 !strcasecmp(de->d_name + strlen(de->d_name) - 3, "txt"))
1905 static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, int msgnum, long duration, char *fmt, char *cidnum, char *cidname);
1907 static void copy_message(struct ast_channel *chan, struct ast_vm_user *vmu, int imbox, int msgnum, long duration, struct ast_vm_user *recip, char *fmt)
1909 char fromdir[256], todir[256], frompath[256], topath[256];
1910 char *frombox = mbox(imbox);
1913 ast_log(LOG_NOTICE, "Copying message from %s@%s to %s@%s\n", vmu->mailbox, vmu->context, recip->mailbox, recip->context);
1915 make_dir(todir, sizeof(todir), recip->context, "", "");
1916 /* It's easier just to try to make it than to check for its existence */
1917 if (mkdir(todir, 0700) && (errno != EEXIST))
1918 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", todir, strerror(errno));
1919 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, "");
1920 /* It's easier just to try to make it than to check for its existence */
1921 if (mkdir(todir, 0700) && (errno != EEXIST))
1922 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", todir, strerror(errno));
1923 make_dir(todir, sizeof(todir), recip->context, recip->mailbox, "INBOX");
1924 if (mkdir(todir, 0700) && (errno != EEXIST))
1925 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", todir, strerror(errno));
1927 make_dir(fromdir, sizeof(fromdir), vmu->context, vmu->mailbox, frombox);
1928 make_file(frompath, sizeof(frompath), fromdir, msgnum);
1929 ast_lock_path(topath);
1932 make_file(topath, sizeof(topath), todir, recipmsgnum);
1933 if (!EXISTS(todir, recipmsgnum, topath, chan->language))
1936 } while (recipmsgnum < MAXMSG);
1937 if (recipmsgnum < MAXMSG) {
1938 COPY(fromdir, msgnum, todir, recipmsgnum, frompath, topath);
1940 ast_log(LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context);
1942 ast_unlock_path(topath);
1943 notify_new_message(chan, recip, recipmsgnum, duration, fmt, chan->cid.cid_num, chan->cid.cid_name);
1946 static void run_externnotify(char *context, char *extension)
1948 char arguments[255];
1949 int newvoicemails = 0, oldvoicemails = 0;
1951 if (!ast_strlen_zero(externnotify)) {
1952 if (messagecount(extension, &newvoicemails, &oldvoicemails)) {
1953 ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension);
1955 snprintf(arguments, sizeof(arguments), "%s %s %s %d&", externnotify, context, extension, newvoicemails);
1956 ast_log(LOG_DEBUG, "Executing %s\n", arguments);
1957 ast_safe_system(arguments);
1963 static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int busy, int unavail)
1977 char prefile[256]="";
1978 char tempfile[256]="";
1979 char ext_context[256] = "";
1982 char ecodes[16] = "#";
1983 char tmp[256] = "", *tmpptr;
1984 struct ast_vm_user *vmu;
1985 struct ast_vm_user svm;
1986 char *category = NULL;
1988 strncpy(tmp, ext, sizeof(tmp) - 1);
1990 context = strchr(tmp, '@');
1994 tmpptr = strchr(context, '&');
1996 tmpptr = strchr(ext, '&');
2004 category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY");
2006 if ((vmu = find_user(&svm, context, ext))) {
2007 /* Setup pre-file if appropriate */
2008 if (strcmp(vmu->context, "default"))
2009 snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context);
2011 strncpy(ext_context, vmu->context, sizeof(ext_context) - 1);
2013 snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext);
2015 snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext);
2016 snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext);
2017 RETRIEVE(tempfile, -1);
2018 if (ast_fileexists(tempfile, NULL, NULL) > 0)
2019 strncpy(prefile, tempfile, sizeof(prefile) - 1);
2020 DISPOSE(tempfile, -1);
2021 make_dir(dir, sizeof(dir), vmu->context, "", "");
2022 /* It's easier just to try to make it than to check for its existence */
2023 if (mkdir(dir, 0700) && (errno != EEXIST))
2024 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
2025 make_dir(dir, sizeof(dir), vmu->context, ext, "");
2026 /* It's easier just to try to make it than to check for its existence */
2027 if (mkdir(dir, 0700) && (errno != EEXIST))
2028 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
2029 make_dir(dir, sizeof(dir), vmu->context, ext, "INBOX");
2030 if (mkdir(dir, 0700) && (errno != EEXIST))
2031 ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno));
2033 /* Check current or macro-calling context for special extensions */
2034 if (!ast_strlen_zero(vmu->exit)) {
2035 if (ast_exists_extension(chan, vmu->exit, "o", 1, chan->cid.cid_num))
2036 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
2037 } else if (ast_exists_extension(chan, chan->context, "o", 1, chan->cid.cid_num))
2038 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
2039 else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "o", 1, chan->cid.cid_num)) {
2040 strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1);
2044 if (!ast_strlen_zero(vmu->exit)) {
2045 if (ast_exists_extension(chan, vmu->exit, "a", 1, chan->cid.cid_num))
2046 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
2047 } else if (ast_exists_extension(chan, chan->context, "a", 1, chan->cid.cid_num))
2048 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
2049 else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "a", 1, chan->cid.cid_num)) {
2050 strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1);
2055 /* Play the beginning intro if desired */
2056 if (!ast_strlen_zero(prefile)) {
2057 RETRIEVE(prefile, -1);
2058 if (ast_fileexists(prefile, NULL, NULL) > 0) {
2059 if (ast_streamfile(chan, prefile, chan->language) > -1)
2060 res = ast_waitstream(chan, ecodes);
2062 ast_log(LOG_DEBUG, "%s doesn't exist, doing what we can\n", prefile);
2063 res = invent_message(chan, vmu->context, ext, busy, ecodes);
2065 DISPOSE(prefile, -1);
2067 ast_log(LOG_DEBUG, "Hang up during prefile playback\n");
2073 /* On a '#' we skip the instructions */
2077 if (!res && !silent) {
2078 res = ast_streamfile(chan, INTRO, chan->language);
2080 res = ast_waitstream(chan, ecodes);
2087 ast_stopstream(chan);
2088 /* Check for a '*' here in case the caller wants to escape from voicemail to something
2089 other than the operator -- an automated attendant or mailbox login for example */
2091 strncpy(chan->exten, "a", sizeof(chan->exten) - 1);
2092 if (!ast_strlen_zero(vmu->exit)) {
2093 strncpy(chan->context, vmu->exit, sizeof(chan->context) - 1);
2094 } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) {
2095 strncpy(chan->context, chan->macrocontext, sizeof(chan->context) - 1);
2101 /* Check for a '0' here */
2104 if (ast_test_flag(vmu, VM_OPERATOR)) {
2105 strncpy(chan->exten, "o", sizeof(chan->exten) - 1);
2106 if (!ast_strlen_zero(vmu->exit)) {
2107 strncpy(chan->context, vmu->exit, sizeof(chan->context) - 1);
2108 } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) {
2109 strncpy(chan->context, chan->macrocontext, sizeof(chan->context) - 1);
2111 ast_play_and_wait(chan, "transfer");
2116 ast_play_and_wait(chan, "vm-sorry");
2124 /* The meat of recording the message... All the announcements and beeps have been played*/
2125 strncpy(fmt, vmfmts, sizeof(fmt) - 1);
2126 if (!ast_strlen_zero(fmt)) {
2129 /* Unless we're *really* silent, try to send the beep */
2130 res = ast_streamfile(chan, "beep", chan->language);
2132 res = ast_waitstream(chan, "");
2136 make_file(fn, sizeof(fn), dir, msgnum);
2137 if (!EXISTS(dir,msgnum,fn,chan->language))
2140 } while (msgnum < MAXMSG);
2141 if (msgnum < MAXMSG) {
2142 /* Store information */
2143 snprintf(txtfile, sizeof(txtfile), "%s.txt", fn);
2144 txt = fopen(txtfile, "w+");
2146 get_date(date, sizeof(date));
2149 "; Message Information file\n"
2168 ast_callerid_merge(callerid, sizeof(callerid), chan->cid.cid_name, chan->cid.cid_num, "Unknown"),
2169 date, (long)time(NULL),
2170 category ? category : "");
2173 ast_log(LOG_WARNING, "Error opening text file for output\n");
2174 res = play_record_review(chan, NULL, fn, vmmaxmessage, fmt, 1, vmu, &duration, dir);
2179 fd = open(txtfile, O_APPEND | O_WRONLY);
2181 txt = fdopen(fd, "a");
2183 fprintf(txt, "duration=%d\n", duration);
2188 if (duration < vmminmessage) {
2189 if (option_verbose > 2)
2190 ast_verbose( VERBOSE_PREFIX_3 "Recording was %d seconds long but needs to be at least %d - abandoning\n", duration, vmminmessage);
2191 DELETE(dir,msgnum,fn);
2192 /* XXX We should really give a prompt too short/option start again, with leave_vm_out called only after a timeout XXX */
2195 /* Are there to be more recipients of this message? */
2197 struct ast_vm_user recipu, *recip;
2198 char *exten, *context;
2200 exten = strsep(&tmpptr, "&");
2201 context = strchr(exten, '@');
2206 if ((recip = find_user(&recipu, context, exten))) {
2207 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt);
2211 if (ast_fileexists(fn, NULL, NULL)) {
2212 notify_new_message(chan, vmu, msgnum, duration, fmt, chan->cid.cid_num, chan->cid.cid_name);
2214 DISPOSE(dir, msgnum);
2217 ast_unlock_path(dir);
2218 res = ast_streamfile(chan, "vm-mailboxfull", chan->language);
2220 res = ast_waitstream(chan, "");
2221 ast_log(LOG_WARNING, "No more messages possible\n");
2224 ast_log(LOG_WARNING, "No format for saving voicemail?\n");
2228 ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
2229 /*Send the call to n+101 priority, where n is the current priority*/
2230 if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num))
2231 chan->priority+=100;
2238 static void resequence_mailbox(char * dir)
2240 /* we know max messages, so stop process when number is hit */
2247 for (x=0,dest=0;x<MAXMSG;x++) {
2248 make_file(sfn, sizeof(sfn), dir, x);
2249 if (EXISTS(dir, x, sfn, NULL)) {
2252 make_file(dfn, sizeof(dfn), dir, dest);
2253 RENAME(dir, x, dir, dest, sfn, dfn);
2259 ast_unlock_path(dir);
2263 static int say_and_wait(struct ast_channel *chan, int num, char *language)
2266 d = ast_say_number(chan, num, AST_DIGIT_ANY, language, (char *) NULL);
2270 static int save_to_folder(char *dir, int msg, char *context, char *username, int box)
2275 char *dbox = mbox(box);
2277 make_file(sfn, sizeof(sfn), dir, msg);
2278 make_dir(ddir, sizeof(ddir), context, username, dbox);
2280 ast_lock_path(ddir);
2281 for (x=0;x<MAXMSG;x++) {
2282 make_file(dfn, sizeof(dfn), ddir, x);
2283 if (!EXISTS(ddir, x, dfn, NULL))
2287 ast_unlock_path(ddir);
2290 if (strcmp(sfn, dfn)) {
2291 COPY(dir, msg, ddir, x, sfn, dfn);
2293 ast_unlock_path(ddir);
2297 static int adsi_logo(unsigned char *buf)
2300 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, "Comedian Mail", "");
2301 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, "(C)2002 LSS, Inc.", "");
2305 static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
2313 bytes += adsi_data_mode(buf + bytes);
2314 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2317 bytes += adsi_logo(buf);
2318 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
2320 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .", "");
2322 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2323 bytes += adsi_data_mode(buf + bytes);
2324 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2326 if (adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
2328 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Cancelled.", "");
2329 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
2330 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2331 bytes += adsi_voice_mode(buf + bytes, 0);
2332 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2339 bytes += adsi_logo(buf);
2340 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Downloading Scripts", "");
2341 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ..", "");
2342 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2343 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2346 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 0, "Listen", "Listen", "1", 1);
2347 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 1, "Folder", "Folder", "2", 1);
2348 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 2, "Advanced", "Advnced", "3", 1);
2349 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Options", "Options", "0", 1);
2350 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 4, "Help", "Help", "*", 1);
2351 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 5, "Exit", "Exit", "#", 1);
2352 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
2355 /* Add another dot */
2357 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ...", "");
2358 bytes += adsi_voice_mode(buf + bytes, 0);
2360 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2361 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2365 /* These buttons we load but don't use yet */
2366 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 6, "Previous", "Prev", "4", 1);
2367 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 8, "Repeat", "Repeat", "5", 1);
2368 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 7, "Delete", "Delete", "7", 1);
2369 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 9, "Next", "Next", "6", 1);
2370 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 10, "Save", "Save", "9", 1);
2371 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 11, "Undelete", "Restore", "7", 1);
2372 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
2375 /* Add another dot */
2377 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " ....", "");
2378 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2379 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2384 snprintf(num, sizeof(num), "%d", x);
2385 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(x), mbox(x), num, 1);
2387 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + 5, "Cancel", "Cancel", "#", 1);
2388 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
2391 /* Add another dot */
2393 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, " .....", "");
2394 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2395 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2398 if (adsi_end_download(chan)) {
2400 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Download Unsuccessful.", "");
2401 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "ADSI Unavailable", "");
2402 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2403 bytes += adsi_voice_mode(buf + bytes, 0);
2404 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2408 bytes += adsi_download_disconnect(buf + bytes);
2409 bytes += adsi_voice_mode(buf + bytes, 0);
2410 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
2412 ast_log(LOG_DEBUG, "Done downloading scripts...\n");
2417 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ......", "");
2418 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2420 ast_log(LOG_DEBUG, "Restarting session...\n");
2423 /* Load the session now */
2424 if (adsi_load_session(chan, adsifdn, adsiver, 1) == 1) {
2426 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Scripts Loaded!", "");
2428 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, "Load Failed!", "");
2430 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2434 static void adsi_begin(struct ast_channel *chan, int *useadsi)
2437 if (!adsi_available(chan))
2439 x = adsi_load_session(chan, adsifdn, adsiver, 1);
2443 if (adsi_load_vmail(chan, useadsi)) {
2444 ast_log(LOG_WARNING, "Unable to upload voicemail scripts\n");
2451 static void adsi_login(struct ast_channel *chan)
2455 unsigned char keys[8];
2457 if (!adsi_available(chan))
2462 /* Set one key for next */
2463 keys[3] = ADSI_KEY_APPS + 3;
2465 bytes += adsi_logo(buf + bytes);
2466 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0, " ", "");
2467 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, " ", "");
2468 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2469 bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Mailbox: ******", "");
2470 bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 1, 1, ADSI_JUST_LEFT);
2471 bytes += adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 3, "Enter", "Enter", "#", 1);
2472 bytes += adsi_set_keys(buf + bytes, keys);
2473 bytes += adsi_voice_mode(buf + bytes, 0);
2474 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2477 static void adsi_password(struct ast_channel *chan)
2481 unsigned char keys[8];
2483 if (!adsi_available(chan))
2488 /* Set one key for next */
2489 keys[3] = ADSI_KEY_APPS + 3;
2491 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2492 bytes += adsi_input_format(buf + bytes, 1, ADSI_DIR_FROM_LEFT, 0, "Password: ******", "");
2493 bytes += adsi_input_control(buf + bytes, ADSI_COMM_PAGE, 4, 0, 1, ADSI_JUST_LEFT);
2494 bytes += adsi_set_keys(buf + bytes, keys);
2495 bytes += adsi_voice_mode(buf + bytes, 0);
2496 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2499 static void adsi_folders(struct ast_channel *chan, int start, char *label)
2503 unsigned char keys[8];
2506 if (!adsi_available(chan))
2510 y = ADSI_KEY_APPS + 12 + start + x;
2511 if (y > ADSI_KEY_APPS + 12 + 4)
2513 keys[x] = ADSI_KEY_SKT | y;
2515 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
2519 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label, "");
2520 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0, " ", "");
2521 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2522 bytes += adsi_set_keys(buf + bytes, keys);
2523 bytes += adsi_voice_mode(buf + bytes, 0);
2525 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2528 static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
2531 char buf[256], buf1[256], buf2[256];
2537 char datetime[21]="";
2540 unsigned char keys[8];
2544 if (!adsi_available(chan))
2547 /* Retrieve important info */
2548 snprintf(fn2, sizeof(fn2), "%s.txt", vms->fn);
2549 f = fopen(fn2, "r");
2552 fgets(buf, sizeof(buf), f);
2556 strsep(&stringp, "=");
2557 val = strsep(&stringp, "=");
2558 if (val && !ast_strlen_zero(val)) {
2559 if (!strcmp(buf, "callerid"))
2560 strncpy(cid, val, sizeof(cid) - 1);
2561 if (!strcmp(buf, "origdate"))
2562 strncpy(datetime, val, sizeof(datetime) - 1);
2568 /* New meaning for keys */
2570 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
2575 /* No prev key, provide "Folder" instead */
2576 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
2578 if (vms->curmsg >= vms->lastmsg) {
2579 /* If last message ... */
2581 /* but not only message, provide "Folder" instead */
2582 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
2583 bytes += adsi_voice_mode(buf + bytes, 0);
2586 /* Otherwise if only message, leave blank */
2591 if (!ast_strlen_zero(cid)) {
2592 ast_callerid_parse(cid, &name, &num);
2596 name = "Unknown Caller";
2598 /* If deleted, show "undeleted" */
2600 if (vms->deleted[vms->curmsg])
2601 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
2604 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
2605 snprintf(buf1, sizeof(buf1), "%s%s", vms->curbox,
2606 strcasecmp(vms->curbox, "INBOX") ? " Messages" : "");
2607 snprintf(buf2, sizeof(buf2), "Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
2609 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
2610 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
2611 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name, "");
2612 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime, "");
2613 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2614 bytes += adsi_set_keys(buf + bytes, keys);
2615 bytes += adsi_voice_mode(buf + bytes, 0);
2617 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2620 static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
2624 unsigned char keys[8];
2628 if (!adsi_available(chan))
2631 /* New meaning for keys */
2633 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
2639 /* No prev key, provide "Folder" instead */
2640 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
2642 if (vms->curmsg >= vms->lastmsg) {
2643 /* If last message ... */
2645 /* but not only message, provide "Folder" instead */
2646 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
2648 /* Otherwise if only message, leave blank */
2653 /* If deleted, show "undeleted" */
2654 if (vms->deleted[vms->curmsg])
2655 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
2658 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
2659 bytes += adsi_set_keys(buf + bytes, keys);
2660 bytes += adsi_voice_mode(buf + bytes, 0);
2662 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2665 static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
2667 char buf[256] = "", buf1[256] = "", buf2[256] = "";
2669 unsigned char keys[8];
2672 char *newm = (vms->newmessages == 1) ? "message" : "messages";
2673 char *oldm = (vms->oldmessages == 1) ? "message" : "messages";
2674 if (!adsi_available(chan))
2676 if (vms->newmessages) {
2677 snprintf(buf1, sizeof(buf1), "You have %d new", vms->newmessages);
2678 if (vms->oldmessages) {
2679 strncat(buf1, " and", sizeof(buf1) - strlen(buf1) - 1);
2680 snprintf(buf2, sizeof(buf2), "%d old %s.", vms->oldmessages, oldm);
2682 snprintf(buf2, sizeof(buf2), "%s.", newm);
2684 } else if (vms->oldmessages) {
2685 snprintf(buf1, sizeof(buf1), "You have %d old", vms->oldmessages);
2686 snprintf(buf2, sizeof(buf2), "%s.", oldm);
2688 strncpy(buf1, "You have no messages.", sizeof(buf1) - 1);
2692 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
2693 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
2694 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2697 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
2701 /* Don't let them listen if there are none */
2702 if (vms->lastmsg < 0)
2704 bytes += adsi_set_keys(buf + bytes, keys);
2706 bytes += adsi_voice_mode(buf + bytes, 0);
2708 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2711 static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
2713 char buf[256] = "", buf1[256] = "", buf2[256] = "";
2715 unsigned char keys[8];
2718 char *mess = (vms->lastmsg == 0) ? "message" : "messages";
2720 if (!adsi_available(chan))
2723 /* Original command keys */
2725 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
2730 if ((vms->lastmsg + 1) < 1)
2733 snprintf(buf1, sizeof(buf1), "%s%s has", vms->curbox,
2734 strcasecmp(vms->curbox, "INBOX") ? " folder" : "");
2736 if (vms->lastmsg + 1)
2737 snprintf(buf2, sizeof(buf2), "%d %s.", vms->lastmsg + 1, mess);
2739 strncpy(buf2, "no messages.", sizeof(buf2) - 1);
2740 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1, "");
2741 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2, "");
2742 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, "", "");
2743 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2744 bytes += adsi_set_keys(buf + bytes, keys);
2746 bytes += adsi_voice_mode(buf + bytes, 0);
2748 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2753 static void adsi_clear(struct ast_channel *chan)
2757 if (!adsi_available(chan))
2759 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2760 bytes += adsi_voice_mode(buf + bytes, 0);
2762 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2766 static void adsi_goodbye(struct ast_channel *chan)
2771 if (!adsi_available(chan))
2773 bytes += adsi_logo(buf + bytes);
2774 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, " ", "");
2775 bytes += adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0, "Goodbye", "");
2776 bytes += adsi_set_line(buf + bytes, ADSI_COMM_PAGE, 1);
2777 bytes += adsi_voice_mode(buf + bytes, 0);
2779 adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
2782 /*--- get_folder: Folder menu ---*/
2783 /* Plays "press 1 for INBOX messages" etc
2784 Should possibly be internationalized
2786 static int get_folder(struct ast_channel *chan, int start)
2791 d = ast_play_and_wait(chan, "vm-press"); /* "Press" */
2794 for (x = start; x< 5; x++) { /* For all folders */
2795 if ((d = ast_say_number(chan, x, AST_DIGIT_ANY, chan->language, (char *) NULL)))
2797 d = ast_play_and_wait(chan, "vm-for"); /* "for" */
2800 snprintf(fn, sizeof(fn), "vm-%s", mbox(x)); /* Folder name */
2801 d = vm_play_folder_name(chan, fn);
2804 d = ast_waitfordigit(chan, 500);
2808 d = ast_play_and_wait(chan, "vm-tocancel"); /* "or pound to cancel" */
2811 d = ast_waitfordigit(chan, 4000);
2815 static int get_folder2(struct ast_channel *chan, char *fn, int start)
2818 res = ast_play_and_wait(chan, fn); /* Folder name */
2819 while (((res < '0') || (res > '9')) &&
2820 (res != '#') && (res >= 0)) {
2821 res = get_folder(chan, 0);
2826 static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vmfts, char *context)
2832 while ((cmd >= 0) && (cmd != 't') && (cmd != '*')) {
2837 /* prepend a message to the current message and return */
2840 snprintf(file, sizeof(file), "%s/msg%04d", curdir, curmsg);
2841 cmd = ast_play_and_prepend(chan, NULL, file, 0, vmfmts, &duration, 1, silencethreshold, maxsilence);
2851 cmd = ast_play_and_wait(chan,"vm-forwardoptions");
2852 /* "Press 1 to prepend a message or 2 to forward the message without prepending" */
2854 cmd = ast_play_and_wait(chan,"vm-starmain");
2855 /* "press star to return to the main menu" */
2857 cmd = ast_waitfordigit(chan,6000);
2869 static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, int msgnum, long duration, char *fmt, char *cidnum, char *cidname)
2871 char todir[256], fn[256], ext_context[256], *stringp;
2872 int newmsgs = 0, oldmsgs = 0;
2874 make_dir(todir, sizeof(todir), vmu->context, vmu->mailbox, "INBOX");
2875 make_file(fn, sizeof(fn), todir, msgnum);
2876 snprintf(ext_context, sizeof(ext_context), "%s@%s", vmu->mailbox, vmu->context);
2878 /* Attach only the first format */
2879 fmt = ast_strdupa(fmt);
2882 strsep(&stringp, "|");
2884 if (!ast_strlen_zero(vmu->email)) {
2885 int attach_user_voicemail = ast_test_flag((&globalflags), VM_ATTACH);
2886 char *myserveremail = serveremail;
2887 attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH);
2888 if (!ast_strlen_zero(vmu->serveremail))
2889 myserveremail = vmu->serveremail;
2890 sendmail(myserveremail, vmu, msgnum, vmu->mailbox, cidnum, cidname, fn, fmt, duration, attach_user_voicemail);
2893 if (!ast_strlen_zero(vmu->pager)) {
2894 char *myserveremail = serveremail;
2895 if (!ast_strlen_zero(vmu->serveremail))
2896 myserveremail = vmu->serveremail;
2897 sendpage(myserveremail, vmu->pager, msgnum, vmu->mailbox, cidnum, cidname, duration, vmu);
2900 ast_log(LOG_ERROR, "Out of memory\n");
2903 if (ast_test_flag(vmu, VM_DELETE)) {
2904 DELETE(todir, msgnum, fn);
2907 /* Leave voicemail for someone */
2908 if (ast_app_has_voicemail(ext_context, NULL)) {
2909 ast_app_messagecount(ext_context, &newmsgs, &oldmsgs);
2911 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);
2912 run_externnotify(chan->context, ext_context);
2916 static int forward_message(struct ast_channel *chan, char *context, char *dir, int curmsg, struct ast_vm_user *sender, char *fmt,int flag)
2918 char username[70]="";
2923 struct ast_config *mif;
2927 char ext_context[256]="";
2928 int res = 0, cmd = 0;
2929 struct ast_vm_user *receiver, *extensions = NULL, *vmtmp = NULL, *vmfree;
2932 int saved_messages = 0, found = 0;
2933 int valid_extensions = 0;
2935 while (!res && !valid_extensions) {
2937 int use_directory = 0;
2938 if(ast_test_flag((&globalflags), VM_DIRECFORWARD)) {
2942 while((cmd >= 0) && !done ){
2959 /* Press 1 to enter an extension press 2 to use the directory */
2960 cmd = ast_play_and_wait(chan,"vm-forward");
2962 cmd = ast_waitfordigit(chan,3000);
2973 if( cmd<0 || cmd=='t' )
2977 if( use_directory ) {
2978 /* use app_directory */
2980 char old_context[sizeof(chan->context)];
2981 char old_exten[sizeof(chan->exten)];
2983 struct ast_app* app;
2986 app = pbx_findapp("Directory");
2988 /* make mackup copies */
2989 memcpy(old_context, chan->context, sizeof(chan->context));
2990 memcpy(old_exten, chan->exten, sizeof(chan->exten));
2991 old_priority = chan->priority;
2993 /* call the the Directory, changes the channel */
2994 res = pbx_exec(chan, app, ((context)?context:chan->context), 1);
2996 strncpy(username, chan->exten, sizeof(username)-1);