Index: apps/app_voicemail.c =================================================================== RCS file: /usr/cvsroot/asterisk/apps/app_voicemail.c,v retrieving revision 1.233 diff -u -r1.233 app_voicemail.c --- apps/app_voicemail.c 20 Jul 2005 00:25:54 -0000 1.233 +++ apps/app_voicemail.c 20 Jul 2005 20:44:30 -0000 @@ -210,6 +210,8 @@ int starting; int repeats; }; +static char host[MAXHOSTNAMELEN] = ""; + static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg, int option); static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context); 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); @@ -1260,9 +1262,9 @@ #else +/*--- count_messages: Find all .txt files - even if they are not in sequence from 0000 */ static int count_messages(struct ast_vm_user *vmu, char *dir) { - /* Find all .txt files - even if they are not in sequence from 0000 */ int vmcount = 0; DIR *vmdir = NULL; @@ -1283,6 +1285,7 @@ return vmcount; } +/*--- rename_file: Rename message .txt file */ static void rename_file(char *sfn, char *dfn) { char stxt[256]; @@ -1293,6 +1296,7 @@ rename(stxt, dtxt); } +/*--- copy: Copy voicemail file */ static int copy(char *infile, char *outfile) { int ifd; @@ -1306,18 +1310,18 @@ if (link(infile, outfile)) { #endif if ((ifd = open(infile, O_RDONLY)) < 0) { - ast_log(LOG_WARNING, "Unable to open %s in read-only mode\n", infile); + ast_log(LOG_ERROR, "Unable to open %s in read-only mode\n", infile); return -1; } if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, 0600)) < 0) { - ast_log(LOG_WARNING, "Unable to open %s in write-only mode\n", outfile); + ast_log(LOG_ERROR, "Unable to open %s in write-only mode\n", outfile); close(ifd); return -1; } do { len = read(ifd, buf, sizeof(buf)); if (len < 0) { - ast_log(LOG_WARNING, "Read failed on %s: %s\n", infile, strerror(errno)); + ast_log(LOG_ERROR, "Read failed on %s: %s\n", infile, strerror(errno)); close(ifd); close(ofd); unlink(outfile); @@ -1325,7 +1329,7 @@ if (len) { res = write(ofd, buf, len); if (res != len) { - ast_log(LOG_WARNING, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno)); + ast_log(LOG_ERROR, "Write failed on %s (%d of %d): %s\n", outfile, res, len, strerror(errno)); close(ifd); close(ofd); unlink(outfile); @@ -1343,6 +1347,7 @@ #endif } +/*--- copy_file: Copy file (with path) */ static void copy_file(char *frompath, char *topath) { char frompath2[256],topath2[256]; @@ -1352,6 +1357,7 @@ copy(frompath2, topath2); } +/*--- last_message_index: Find last message in folder */ /* * A negative return value indicates an error. */ @@ -1373,6 +1379,7 @@ return x - 1; } +/*--- vm_delete: Delete voicemail */ static int vm_delete(char *file) { char *txt; @@ -1383,15 +1390,15 @@ /* Sprintf here would safe because we alloca'd exactly the right length, * but trying to eliminate all sprintf's anyhow */ - snprintf(txt, txtsize, "%s.txt", file); + snprintf(txt, txtsize, "%s.txt", file); /* Unlink metadata file */ unlink(txt); - return ast_filedelete(file, NULL); + return ast_filedelete(file, NULL); /* Unlink voicemail message */ } #endif -static int -inbuf(struct baseio *bio, FILE *fi) +/*--- inbuf: ??? */ +static int inbuf(struct baseio *bio, FILE *fi) { int l; @@ -1412,8 +1419,8 @@ return 1; } -static int -inchar(struct baseio *bio, FILE *fi) +/*--- inchar: ??? */ +static int inchar(struct baseio *bio, FILE *fi) { if (bio->iocp>=bio->iolen) { if (!inbuf(bio, fi)) @@ -1423,8 +1430,7 @@ return bio->iobuf[bio->iocp++]; } -static int -ochar(struct baseio *bio, int c, FILE *so) +static int ochar(struct baseio *bio, int c, FILE *so) { if (bio->linelength>=BASELINELEN) { if (fputs(eol,so)==EOF) @@ -1441,10 +1447,11 @@ return 1; } +/*--- base_encode: Base64 encode voicemail e-mail attachment */ static int base_encode(char *filename, FILE *so) { unsigned char dtable[BASEMAXINLINE]; - int i,hiteof= 0; + int i, hiteof = 0; FILE *fi; struct baseio bio; @@ -1452,26 +1459,29 @@ bio.iocp = BASEMAXINLINE; if (!(fi = fopen(filename, "rb"))) { - ast_log(LOG_WARNING, "Failed to open log file: %s: %s\n", filename, strerror(errno)); + ast_log(LOG_WARNING, "Failed to open data file: %s: %s\n", filename, strerror(errno)); return -1; } - for (i= 0;i<9;i++) { + /* Build conversion table */ + /* Hmmm... Do we have to do this every time? */ + for (i=0; i<9; i++) { dtable[i]= 'A'+i; dtable[i+9]= 'J'+i; dtable[26+i]= 'a'+i; dtable[26+i+9]= 'j'+i; } - for (i= 0;i<8;i++) { + for (i=0; i<8; i++) { dtable[i+18]= 'S'+i; dtable[26+i+18]= 's'+i; } - for (i= 0;i<10;i++) { + for (i=0; i<10; i++) { dtable[52+i]= '0'+i; } dtable[62]= '+'; dtable[63]= '/'; + /* Start converting the file */ while (!hiteof){ unsigned char igroup[3],ogroup[4]; int c,n; @@ -1480,11 +1490,11 @@ for (n= 0;n<3;n++) { if ((c = inchar(&bio, fi)) == EOF) { - hiteof= 1; + hiteof = 1; break; } - igroup[n]= (unsigned char)c; + igroup[n] = (unsigned char) c; } if (n> 0) { @@ -1513,10 +1523,11 @@ return 1; } +/*--- prep_email_sub_vars: Prepare variables for substition in email body and subject */ +/* The text strings in this function should be made localizable :-) */ 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) { char callerid[256]; - /* Prepare variables for substition in email body and subject */ pbx_builtin_setvar_helper(ast, "VM_NAME", vmu->fullname); pbx_builtin_setvar_helper(ast, "VM_DUR", dur); snprintf(passdata, passdatasize, "%d", msgnum); @@ -1529,28 +1540,29 @@ pbx_builtin_setvar_helper(ast, "VM_DATE", date); } +/*--- sendmail: Send voicemail as e-mail */ 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) { FILE *p=NULL; int pfd; char date[256]; - char host[MAXHOSTNAMELEN] = ""; char who[256]; char bound[256]; char fname[256]; char dur[256]; - char tmp[80] = "/tmp/astmail-XXXXXX"; + char tmp[80] = "/tmp/astmail-XXXXXX"; /* Temporary file - should this be hard coded ??? */ char tmp2[256]; time_t t; struct tm tm; struct vm_zone *the_zone = NULL; + if (vmu && ast_strlen_zero(vmu->email)) { - ast_log(LOG_WARNING, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox); + ast_log(LOG_DEBUG, "E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->mailbox); return(0); } if (!strcmp(format, "wav49")) format = "WAV"; - 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)); + ast_log(LOG_DEBUG, "Attaching file '%s' to e-mail, format '%s', uservm is '%d', global is %d\n", attach, format, attach_user_voicemail, ast_test_flag((&globalflags), VM_ATTACH)); /* Make a temporary file instead of piping directly to sendmail, in case the mail command hangs */ pfd = mkstemp(tmp); @@ -1561,145 +1573,137 @@ pfd = -1; } } - if (p) { - gethostname(host, sizeof(host)-1); - if (strchr(srcemail, '@')) - ast_copy_string(who, srcemail, sizeof(who)); - else { - snprintf(who, sizeof(who), "%s@%s", srcemail, host); - } - snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60); - time(&t); + if (!p) { + ast_log(LOG_WARNING, "Unable to create make file and launch '%s'\n", mailcmd); + return -1; + } + if (strchr(srcemail, '@')) + strncpy(who, srcemail, sizeof(who)-1); + else { + snprintf(who, sizeof(who), "%s@%s", srcemail, host); + } + snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60); + time(&t); - /* Does this user have a timezone specified? */ - if (!ast_strlen_zero(vmu->zonetag)) { - /* Find the zone in the list */ - struct vm_zone *z; - z = zones; - while (z) { - if (!strcmp(z->name, vmu->zonetag)) { - the_zone = z; - break; - } - z = z->next; + /* Does this user have a timezone specified? */ + if (!ast_strlen_zero(vmu->zonetag)) { + /* Find the zone in the list */ + struct vm_zone *z; + z = zones; + while (z) { + if (!strcmp(z->name, vmu->zonetag)) { + the_zone = z; + break; } + z = z->next; } + } - if (the_zone) - ast_localtime(&t,&tm,the_zone->timezone); - else - ast_localtime(&t,&tm,NULL); - strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", &tm); - fprintf(p, "Date: %s\n", date); - - /* Set date format for voicemail mail */ - strftime(date, sizeof(date), emaildateformat, &tm); - - if (*fromstring) { - struct ast_channel *ast = ast_channel_alloc(0); - if (ast) { - char *passdata; - int vmlen = strlen(fromstring)*3 + 200; - if ((passdata = alloca(vmlen))) { - memset(passdata, 0, vmlen); - prep_email_sub_vars(ast,vmu,msgnum + 1,context,mailbox,cidnum, cidname,dur,date,passdata, vmlen); - pbx_substitute_variables_helper(ast,fromstring,passdata,vmlen); - fprintf(p, "From: %s <%s>\n",passdata,who); - } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n"); - ast_channel_free(ast); - } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n"); - } else - fprintf(p, "From: Asterisk PBX <%s>\n", who); - fprintf(p, "To: %s <%s>\n", vmu->fullname, vmu->email); + if (the_zone) + ast_localtime(&t,&tm,the_zone->timezone); + else + ast_localtime(&t,&tm,NULL); - if (emailsubject) { - struct ast_channel *ast = ast_channel_alloc(0); - if (ast) { - char *passdata; - int vmlen = strlen(emailsubject)*3 + 200; - if ((passdata = alloca(vmlen))) { - memset(passdata, 0, vmlen); - prep_email_sub_vars(ast,vmu,msgnum + 1,context,mailbox,cidnum, cidname,dur,date,passdata, vmlen); - pbx_substitute_variables_helper(ast,emailsubject,passdata,vmlen); - fprintf(p, "Subject: %s\n",passdata); - } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n"); - ast_channel_free(ast); - } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n"); - } else - if (*emailtitle) { - fprintf(p, emailtitle, msgnum + 1, mailbox) ; - fprintf(p,"\n") ; - } else if (ast_test_flag((&globalflags), VM_PBXSKIP)) - fprintf(p, "Subject: New message %d in mailbox %s\n", msgnum + 1, mailbox); - else - fprintf(p, "Subject: [PBX]: New message %d in mailbox %s\n", msgnum + 1, mailbox); - fprintf(p, "Message-ID: \n", msgnum, (unsigned int)rand(), mailbox, getpid(), host); - fprintf(p, "MIME-Version: 1.0\n"); - if (attach_user_voicemail) { - /* Something unique. */ - snprintf(bound, sizeof(bound), "voicemail_%d%s%d%d", msgnum, mailbox, getpid(), (unsigned int)rand()); + /* Set date format for voicemail mail */ + strftime(date, sizeof(date), emaildateformat, &tm); - fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"\n\n\n", bound); + fprintf(p, "Date: %s\n", date); - fprintf(p, "--%s\n", bound); - } - fprintf(p, "Content-Type: text/plain; charset=%s\nContent-Transfer-Encoding: 8bit\n\n", charset); - if (emailbody) { - struct ast_channel *ast = ast_channel_alloc(0); - if (ast) { - char *passdata; - int vmlen = strlen(emailbody)*3 + 200; - if ((passdata = alloca(vmlen))) { - memset(passdata, 0, vmlen); - prep_email_sub_vars(ast,vmu,msgnum + 1,context,mailbox,cidnum, cidname,dur,date,passdata, vmlen); - pbx_substitute_variables_helper(ast,emailbody,passdata,vmlen); - fprintf(p, "%s\n",passdata); - } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n"); - ast_channel_free(ast); - } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n"); - } else { - fprintf(p, "Dear %s:\n\n\tJust wanted to let you know you were just left a %s long message (number %d)\n" + if (*fromstring) { + struct ast_channel *ast = ast_channel_alloc(0); + if (ast) { + char *passdata; + int vmlen = strlen(fromstring) * 3 + 200; + if ((passdata = alloca(vmlen))) { + memset(passdata, 0, vmlen); + prep_email_sub_vars(ast,vmu,msgnum + 1,context,mailbox,cidnum, cidname,dur,date,passdata, vmlen); + pbx_substitute_variables_helper(ast,fromstring,passdata,vmlen); + fprintf(p, "From: %s <%s>\n",passdata,who); + } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n"); + ast_channel_free(ast); + } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n"); + } else + fprintf(p, "From: Asterisk PBX <%s>\n", who); + fprintf(p, "To: %s <%s>\n", vmu->fullname, vmu->email); - "in mailbox %s from %s, on %s so you might\n" - "want to check it when you get a chance. Thanks!\n\n\t\t\t\t--Asterisk\n\n", vmu->fullname, - dur, msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date); - } - if (attach_user_voicemail) { - /* Eww. We want formats to tell us their own MIME type */ - char *ctype = "audio/x-"; - if (!strcasecmp(format, "ogg")) - ctype = "application/"; - - fprintf(p, "--%s\n", bound); - fprintf(p, "Content-Type: %s%s; name=\"msg%04d.%s\"\n", ctype, format, msgnum, format); - fprintf(p, "Content-Transfer-Encoding: base64\n"); - fprintf(p, "Content-Description: Voicemail sound attachment.\n"); - fprintf(p, "Content-Disposition: attachment; filename=\"msg%04d.%s\"\n\n", msgnum, format); - - snprintf(fname, sizeof(fname), "%s.%s", attach, format); - base_encode(fname, p); - fprintf(p, "\n\n--%s--\n.\n", bound); - } - fclose(p); - snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp); - ast_safe_system(tmp2); - ast_log(LOG_DEBUG, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd); + if (emailsubject) { + struct ast_channel *ast = ast_channel_alloc(0); + if (ast) { + char *passdata; + int vmlen = strlen(emailsubject)*3 + 200; + if ((passdata = alloca(vmlen))) { + memset(passdata, 0, vmlen); + prep_email_sub_vars(ast,vmu,msgnum + 1,context,mailbox,cidnum, cidname,dur,date,passdata, vmlen); + pbx_substitute_variables_helper(ast,emailsubject,passdata,vmlen); + fprintf(p, "Subject: %s\n",passdata); + } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n"); + ast_channel_free(ast); + } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n"); + } else if (*emailtitle) { + fprintf(p, emailtitle, msgnum + 1, mailbox) ; + fprintf(p,"\n") ; + } else if (ast_test_flag((&globalflags), VM_PBXSKIP)) + fprintf(p, "Subject: New message %d in mailbox %s\n", msgnum + 1, mailbox); + else + fprintf(p, "Subject: [PBX]: New message %d in mailbox %s\n", msgnum + 1, mailbox); + fprintf(p, "Message-ID: \n", msgnum, (unsigned int)rand(), mailbox, getpid(), host); + fprintf(p, "MIME-Version: 1.0\n"); + if (attach_user_voicemail) { + /* Something unique. */ + snprintf(bound, sizeof(bound), "voicemail_%d%s%d%d", msgnum, mailbox, getpid(), (unsigned int)rand()); + + fprintf(p, "Content-Type: multipart/mixed; boundary=\"%s\"\n\n\n", bound); + + fprintf(p, "--%s\n", bound); + } + fprintf(p, "Content-Type: text/plain; charset=%s\nContent-Transfer-Encoding: 8bit\n\n", charset); + strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm); + if (emailbody) { + struct ast_channel *ast = ast_channel_alloc(0); + if (ast) { + char *passdata; + int vmlen = strlen(emailbody)*3 + 200; + if ((passdata = alloca(vmlen))) { + memset(passdata, 0, vmlen); + prep_email_sub_vars(ast,vmu,msgnum + 1,context,mailbox,cidnum, cidname,dur,date,passdata, vmlen); + pbx_substitute_variables_helper(ast,emailbody,passdata,vmlen); + fprintf(p, "%s\n",passdata); + } else ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n"); + ast_channel_free(ast); + } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n"); } else { - ast_log(LOG_WARNING, "Unable to launch '%s'\n", mailcmd); - return -1; - } + fprintf(p, "Dear %s:\n\n\tJust wanted to let you know you were just left a %s long message (number %d)\n" + "in mailbox %s from %s, on %s so you might\n" + "want to check it when you get a chance. Thanks!\n\n\t\t\t\t--Asterisk\n\n", vmu->fullname, + dur, msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum : "an unknown caller")), date); + } + if (attach_user_voicemail) { + fprintf(p, "--%s\n", bound); + fprintf(p, "Content-Type: audio/x-%s; name=\"msg%04d.%s\"\n", format, msgnum, format); + fprintf(p, "Content-Transfer-Encoding: base64\n"); + fprintf(p, "Content-Description: Voicemail sound attachment.\n"); + fprintf(p, "Content-Disposition: attachment; filename=\"msg%04d.%s\"\n\n", msgnum, format); + + snprintf(fname, sizeof(fname), "%s.%s", attach, format); + base_encode(fname, p); + fprintf(p, "\n\n--%s--\n.\n", bound); + } + fclose(p); + snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp); + ast_safe_system(tmp2); + ast_log(LOG_DEBUG, "Sent mail to %s with command '%s'\n", vmu->email, mailcmd); return 0; } +/*--- sendpage: Send pager e-mail (no attachments, short message) */ static int sendpage(char *srcemail, char *pager, int msgnum, char *context, char *mailbox, char *cidnum, char *cidname, int duration, struct ast_vm_user *vmu) { FILE *p=NULL; int pfd; char date[256]; - char host[MAXHOSTNAMELEN]=""; char who[256]; char dur[256]; - char tmp[80] = "/tmp/astmail-XXXXXX"; + char tmp[80] = "/tmp/astmail-XXXXXX"; /* Should this really be a hard coded directory? */ char tmp2[256]; time_t t; struct tm tm; @@ -1714,70 +1718,69 @@ } } - if (p) { - gethostname(host, sizeof(host)-1); - if (strchr(srcemail, '@')) - ast_copy_string(who, srcemail, sizeof(who)); - else { - snprintf(who, sizeof(who), "%s@%s", srcemail, host); - } - snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60); - time(&t); + if (!p) { + ast_log(LOG_WARNING, "Unable to create temporary message file '%s'\n", mailcmd); + return -1; + } + if (strchr(srcemail, '@')) + strncpy(who, srcemail, sizeof(who)-1); + else { + snprintf(who, sizeof(who), "%s@%s", srcemail, host); + } + snprintf(dur, sizeof(dur), "%d:%02d", duration / 60, duration % 60); + time(&t); - /* Does this user have a timezone specified? */ - if (!ast_strlen_zero(vmu->zonetag)) { - /* Find the zone in the list */ - struct vm_zone *z; - z = zones; - while (z) { - if (!strcmp(z->name, vmu->zonetag)) { - the_zone = z; - break; - } - z = z->next; + /* Does this user have a timezone specified? */ + if (!ast_strlen_zero(vmu->zonetag)) { + /* Find the zone in the list */ + struct vm_zone *z; + z = zones; + while (z) { + if (!strcmp(z->name, vmu->zonetag)) { + the_zone = z; + break; } + z = z->next; } + } - if (the_zone) - ast_localtime(&t,&tm,the_zone->timezone); - else - ast_localtime(&t,&tm,NULL); + if (the_zone) + ast_localtime(&t,&tm,the_zone->timezone); + else + ast_localtime(&t,&tm,NULL); - strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", &tm); - fprintf(p, "Date: %s\n", date); + strftime(date, sizeof(date), "%a, %d %b %Y %H:%M:%S %z", &tm); + fprintf(p, "Date: %s\n", date); - if (*pagerfromstring) { - struct ast_channel *ast = ast_channel_alloc(0); - if (ast) { - char *passdata; - int vmlen = strlen(fromstring)*3 + 200; - if ((passdata = alloca(vmlen))) { - memset(passdata, 0, vmlen); - prep_email_sub_vars(ast,vmu,msgnum + 1,context,mailbox,cidnum, cidname,dur,date,passdata, vmlen); - pbx_substitute_variables_helper(ast,pagerfromstring,passdata,vmlen); - fprintf(p, "From: %s <%s>\n",passdata,who); - } else - ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n"); - ast_channel_free(ast); - } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n"); - } else - fprintf(p, "From: Asterisk PBX <%s>\n", who); - fprintf(p, "To: %s\n", pager); - fprintf(p, "Subject: New VM\n\n"); - strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm); - fprintf(p, "New %s long msg in box %s\n" - "from %s, on %s", dur, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date); - fclose(p); - snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp); - ast_safe_system(tmp2); - ast_log(LOG_DEBUG, "Sent page to %s with command '%s'\n", pager, mailcmd); - } else { - ast_log(LOG_WARNING, "Unable to launch '%s'\n", mailcmd); - return -1; - } + if (*pagerfromstring) { + struct ast_channel *ast = ast_channel_alloc(0); + if (ast) { + char *passdata; + int vmlen = strlen(fromstring)*3 + 200; + if ((passdata = alloca(vmlen))) { + memset(passdata, 0, vmlen); + prep_email_sub_vars(ast,vmu,msgnum + 1,context,mailbox,cidnum, cidname,dur,date,passdata, vmlen); + pbx_substitute_variables_helper(ast,pagerfromstring,passdata,vmlen); + fprintf(p, "From: %s <%s>\n",passdata,who); + } else + ast_log(LOG_WARNING, "Cannot allocate workspace for variable substitution\n"); + ast_channel_free(ast); + } else ast_log(LOG_WARNING, "Cannot allocate the channel for variables substitution\n"); + } else + fprintf(p, "From: Asterisk PBX <%s>\n", who); + fprintf(p, "To: %s\n", pager); + fprintf(p, "Subject: New VM\n\n"); /* The pager message should be configurable, for localization */ + strftime(date, sizeof(date), "%A, %B %d, %Y at %r", &tm); + fprintf(p, "New %s long msg in box %s\n" + "from %s, on %s", dur, mailbox, (cidname ? cidname : (cidnum ? cidnum : "unknown")), date); + fclose(p); + snprintf(tmp2, sizeof(tmp2), "( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp); + ast_safe_system(tmp2); + ast_log(LOG_DEBUG, "Sent page to %s with command '%s'\n", pager, mailcmd); return 0; } +/* get_date: Get current date */ static int get_date(char *s, int len) { struct tm tm; @@ -1866,6 +1869,8 @@ } } +/*--- has_voicemail: Dialplan application */ +/*! \return 1 if user has voicemail, 0 if not */ static int has_voicemail(const char *mailbox, const char *folder) { DIR *dir; @@ -1875,11 +1880,15 @@ char *mb, *cur; char *context; int ret; + if (!folder) folder = "INBOX"; + /* If no mailbox, return immediately */ if (ast_strlen_zero(mailbox)) return 0; + + /* If we have several mailboxes as an argument, do recursive calls on each one */ if (strchr(mailbox, ',')) { ast_copy_string(tmp, mailbox, sizeof(tmp)); mb = tmp; @@ -1890,6 +1899,7 @@ return 1; } } + /* No mailbox had voicemail, return failure */ return 0; } ast_copy_string(tmp, mailbox, sizeof(tmp)); @@ -1899,6 +1909,7 @@ context++; } else context = "default"; + snprintf(fn, sizeof(fn), "%s/%s/%s/%s", VM_SPOOL_DIR, context, tmp, folder); dir = opendir(fn); if (!dir) @@ -1913,6 +1924,8 @@ return 0; } +/*--- messagecount: Find number of old and new messages in voicemailbox */ +/* Supports multiple mailboxes separated with a comma */ static int messagecount(const char *mailbox, int *newmsgs, int *oldmsgs) { DIR *dir; @@ -1922,6 +1935,7 @@ char *mb, *cur; char *context; int ret; + if (newmsgs) *newmsgs = 0; if (oldmsgs) @@ -1929,12 +1943,15 @@ /* If no mailbox, return immediately */ if (ast_strlen_zero(mailbox)) return 0; + + /* If we have several mailboxes as arguments, check each one and summarize */ if (strchr(mailbox, ',')) { int tmpnew, tmpold; ast_copy_string(tmp, mailbox, sizeof(tmp)); mb = tmp; ret = 0; while((cur = strsep(&mb, ", "))) { + /* We should check for whitespace after the comma */ if (!ast_strlen_zero(cur)) { if (messagecount(cur, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL)) return -1; @@ -1955,6 +1972,7 @@ context++; } else context = "default"; + /* Check new messages in INBOX */ if (newmsgs) { snprintf(fn, sizeof(fn), "%s/%s/%s/INBOX", VM_SPOOL_DIR, context, tmp); dir = opendir(fn); @@ -1968,6 +1986,7 @@ closedir(dir); } } + /* Check old (read) messages in Old */ if (oldmsgs) { snprintf(fn, sizeof(fn), "%s/%s/%s/Old", VM_SPOOL_DIR, context, tmp); dir = opendir(fn); @@ -1986,6 +2005,7 @@ static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, int msgnum, long duration, char *fmt, char *cidnum, char *cidname); +/*--- copy_message: Copy messages between mailboxes */ 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) { char fromdir[256], todir[256], frompath[256], topath[256]; @@ -2025,12 +2045,14 @@ ast_log(LOG_ERROR, "Recipient mailbox %s@%s is full\n", recip->mailbox, recip->context); } ast_unlock_path(topath); + /* Notify recipient of new message */ notify_new_message(chan, recip, recipmsgnum, duration, fmt, chan->cid.cid_num, chan->cid.cid_name); return 0; } -static void run_externnotify(char *context, char *extension) +/*-- run_externnotify: Run external notification for voicemail */ +static void run_externnotify(char *context, char *extension, int oldmsgs, int newmsgs) { char arguments[255]; char ext_context[256] = ""; @@ -2040,19 +2062,25 @@ snprintf(ext_context, sizeof(ext_context), "%s@%s", extension, context); else ast_copy_string(ext_context, extension, sizeof(ext_context)); - - if (!ast_strlen_zero(externnotify)) { - if (messagecount(ext_context, &newvoicemails, &oldvoicemails)) { - ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension); + if (!ast_strlen_zero(externnotify)) { /* This could be settable per context if we wanted to :-) */ + /* OH BOY, do we really have to calculate this again? */ + if (oldmsgs > -1 && newmsgs > -1) { + newvoicemails = newmsgs; + oldvoicemails = oldmsgs; } else { - snprintf(arguments, sizeof(arguments), "%s %s %s %d&", externnotify, context, extension, newvoicemails); - ast_log(LOG_DEBUG, "Executing %s\n", arguments); - ast_safe_system(arguments); + if (messagecount(extension, &newvoicemails, &oldvoicemails)) { + ast_log(LOG_ERROR, "Problem in calculating number of voicemail messages available for extension %s\n", extension); + return; + } } + snprintf(arguments, sizeof(arguments), "%s %s %s %d&", externnotify, context, extension, newvoicemails); + ast_log(LOG_DEBUG, "Executing external vm notification: %s\n", arguments); + ast_safe_system(arguments); } } +/*--- leave_voicemail: the voicemail() dialplan application */ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int busy, int unavail) { char txtfile[256]; @@ -2085,9 +2113,11 @@ context++; tmpptr = strchr(context, '&'); } else { + /* OEJ: Shouldn't we set context to "default" here?? */ tmpptr = strchr(ext, '&'); } + /* If we have several mailboxes as arguments, set tmpptr to point to the next one */ if (tmpptr) { *tmpptr = '\0'; tmpptr++; @@ -2095,245 +2125,251 @@ category = pbx_builtin_getvar_helper(chan, "VM_CATEGORY"); - if ((vmu = find_user(&svm, context, ext))) { - /* Setup pre-file if appropriate */ - if (strcmp(vmu->context, "default")) - snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context); - else - ast_copy_string(ext_context, vmu->context, sizeof(ext_context)); - if (busy) - snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext); - else if (unavail) - snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext); - snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext); - RETRIEVE(tempfile, -1); - if (ast_fileexists(tempfile, NULL, NULL) > 0) - ast_copy_string(prefile, tempfile, sizeof(prefile)); - DISPOSE(tempfile, -1); - make_dir(dir, sizeof(dir), vmu->context, "", ""); - /* It's easier just to try to make it than to check for its existence */ - if (mkdir(dir, 0700) && (errno != EEXIST)) - ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno)); - make_dir(dir, sizeof(dir), vmu->context, ext, ""); - /* It's easier just to try to make it than to check for its existence */ - if (mkdir(dir, 0700) && (errno != EEXIST)) - ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno)); - make_dir(dir, sizeof(dir), vmu->context, ext, "INBOX"); - if (mkdir(dir, 0700) && (errno != EEXIST)) - ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno)); - - /* Check current or macro-calling context for special extensions */ - if (!ast_strlen_zero(vmu->exit)) { - if (ast_exists_extension(chan, vmu->exit, "o", 1, chan->cid.cid_num)) - strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1); - } else if (ast_exists_extension(chan, chan->context, "o", 1, chan->cid.cid_num)) - strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1); - else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "o", 1, chan->cid.cid_num)) { + /* Find voicemail account in configuration */ + if (!(vmu = find_user(&svm, context, ext))) { + ast_log(LOG_WARNING, "No entry in voicemail config file for '%s@%s'\n", ext, context); + /* OEJ: This should be changed toa VMSTATUS variable */ + /*Send the call to n+101 priority, where n is the current priority*/ + if (ast_exists_extension(chan, chan->context, chan->exten, chan->priority + 101, chan->cid.cid_num)) + chan->priority+=100; + return 0; + } + /* Setup pre-file if appropriate */ + if (strcmp(vmu->context, "default")) + snprintf(ext_context, sizeof(ext_context), "%s@%s", ext, vmu->context); + else + ast_copy_string(ext_context, vmu->context, sizeof(ext_context)); + if (busy) + snprintf(prefile, sizeof(prefile), "%s%s/%s/busy", VM_SPOOL_DIR, vmu->context, ext); + else if (unavail) + snprintf(prefile, sizeof(prefile), "%s%s/%s/unavail", VM_SPOOL_DIR, vmu->context, ext); + snprintf(tempfile, sizeof(tempfile), "%s%s/%s/temp", VM_SPOOL_DIR, vmu->context, ext); + RETRIEVE(tempfile, -1); + if (ast_fileexists(tempfile, NULL, NULL) > 0) + ast_copy_string(prefile, tempfile, sizeof(prefile)); + DISPOSE(tempfile, -1); + make_dir(dir, sizeof(dir), vmu->context, "", ""); + /* It's easier just to try to make it than to check for its existence */ + if (mkdir(dir, 0700) && (errno != EEXIST)) + ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno)); + make_dir(dir, sizeof(dir), vmu->context, ext, ""); + /* It's easier just to try to make it than to check for its existence */ + if (mkdir(dir, 0700) && (errno != EEXIST)) + ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno)); + make_dir(dir, sizeof(dir), vmu->context, ext, "INBOX"); + if (mkdir(dir, 0700) && (errno != EEXIST)) + ast_log(LOG_WARNING, "mkdir '%s' failed: %s\n", dir, strerror(errno)); + + /* Check current or macro-calling context for special extensions */ + if (!ast_strlen_zero(vmu->exit)) { + if (ast_exists_extension(chan, vmu->exit, "o", 1, chan->cid.cid_num)) strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1); - ousemacro = 1; - } + } else if (ast_exists_extension(chan, chan->context, "o", 1, chan->cid.cid_num)) + strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1); + else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "o", 1, chan->cid.cid_num)) { + strncat(ecodes, "0", sizeof(ecodes) - strlen(ecodes) - 1); + ousemacro = 1; + } - if (!ast_strlen_zero(vmu->exit)) { - if (ast_exists_extension(chan, vmu->exit, "a", 1, chan->cid.cid_num)) - strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1); - } else if (ast_exists_extension(chan, chan->context, "a", 1, chan->cid.cid_num)) - strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1); - else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "a", 1, chan->cid.cid_num)) { + if (!ast_strlen_zero(vmu->exit)) { + if (ast_exists_extension(chan, vmu->exit, "a", 1, chan->cid.cid_num)) strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1); - ausemacro = 1; - } + } else if (ast_exists_extension(chan, chan->context, "a", 1, chan->cid.cid_num)) + strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1); + else if (!ast_strlen_zero(chan->macrocontext) && ast_exists_extension(chan, chan->macrocontext, "a", 1, chan->cid.cid_num)) { + strncat(ecodes, "*", sizeof(ecodes) - strlen(ecodes) - 1); + ausemacro = 1; + } - /* Play the beginning intro if desired */ - if (!ast_strlen_zero(prefile)) { - RETRIEVE(prefile, -1); - if (ast_fileexists(prefile, NULL, NULL) > 0) { - if (ast_streamfile(chan, prefile, chan->language) > -1) - res = ast_waitstream(chan, ecodes); - } else { - ast_log(LOG_DEBUG, "%s doesn't exist, doing what we can\n", prefile); - res = invent_message(chan, vmu->context, ext, busy, ecodes); - } - DISPOSE(prefile, -1); - if (res < 0) { - ast_log(LOG_DEBUG, "Hang up during prefile playback\n"); - free_user(vmu); - return -1; - } + /* Play the beginning intro if desired */ + if (!ast_strlen_zero(prefile)) { + RETRIEVE(prefile, -1); + if (ast_fileexists(prefile, NULL, NULL) > 0) { + if (ast_streamfile(chan, prefile, chan->language) > -1) + res = ast_waitstream(chan, ecodes); + } else { + ast_log(LOG_DEBUG, "%s doesn't exist, doing what we can\n", prefile); + res = invent_message(chan, vmu->context, ext, busy, ecodes); + } + DISPOSE(prefile, -1); + if (res < 0) { + ast_log(LOG_DEBUG, "Caller hang up during prefile playback\n"); + free_user(vmu); + return -1; } + } + if (res == '#') { + /* On a '#' we skip the instructions */ + silent = 1; + res = 0; + } + if (!res && !silent) { + res = ast_streamfile(chan, INTRO, chan->language); + if (!res) + res = ast_waitstream(chan, ecodes); if (res == '#') { - /* On a '#' we skip the instructions */ silent = 1; res = 0; } - if (!res && !silent) { - res = ast_streamfile(chan, INTRO, chan->language); - if (!res) - res = ast_waitstream(chan, ecodes); - if (res == '#') { - silent = 1; - res = 0; - } + } + if (res > 0) + ast_stopstream(chan); + /* Check for a '*' here in case the caller wants to escape from voicemail to something + other than the operator -- an automated attendant or mailbox login for example */ + if (res == '*') { + chan->exten[0] = 'a'; + chan->exten[1] = '\0'; + if (!ast_strlen_zero(vmu->exit)) { + strncpy(chan->context, vmu->exit, sizeof(chan->context) - 1); + } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) { + strncpy(chan->context, chan->macrocontext, sizeof(chan->context) - 1); } - if (res > 0) - ast_stopstream(chan); - /* Check for a '*' here in case the caller wants to escape from voicemail to something - other than the operator -- an automated attendant or mailbox login for example */ - if (res == '*') { - chan->exten[0] = 'a'; + chan->priority = 0; + free_user(vmu); + return 0; + } + /* Check for a '0' here */ + if (res == '0') { + transfer: + if (ast_test_flag(vmu, VM_OPERATOR)) { + chan->exten[0] = 'o'; chan->exten[1] = '\0'; if (!ast_strlen_zero(vmu->exit)) { ast_copy_string(chan->context, vmu->exit, sizeof(chan->context)); - } else if (ausemacro && !ast_strlen_zero(chan->macrocontext)) { + } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) { ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context)); } + ast_play_and_wait(chan, "transfer"); chan->priority = 0; free_user(vmu); return 0; + } else { + ast_play_and_wait(chan, "vm-sorry"); + return 0; } - /* Check for a '0' here */ - if (res == '0') { - transfer: - if (ast_test_flag(vmu, VM_OPERATOR)) { - chan->exten[0] = 'o'; - chan->exten[1] = '\0'; - if (!ast_strlen_zero(vmu->exit)) { - ast_copy_string(chan->context, vmu->exit, sizeof(chan->context)); - } else if (ousemacro && !ast_strlen_zero(chan->macrocontext)) { - ast_copy_string(chan->context, chan->macrocontext, sizeof(chan->context)); - } - ast_play_and_wait(chan, "transfer"); - chan->priority = 0; - free_user(vmu); - return 0; - } else { - ast_play_and_wait(chan, "vm-sorry"); - return 0; - } + } + if (res < 0) { + free_user(vmu); + return -1; + } + /* The meat of recording the message... All the announcements and beeps have been played*/ + strncpy(fmt, vmfmts, sizeof(fmt) - 1); + if (ast_strlen_zero(fmt)) { + ast_log(LOG_WARNING, "No format for saving voicemail to %s@%s\n", ext, context); + free_user(vmu); + return res; + } + msgnum = 0; + if (res >= 0) { + /* Unless we're *really* silent, try to send the beep */ + res = ast_streamfile(chan, "beep", chan->language); + if (!res) + res = ast_waitstream(chan, ""); + } + ast_lock_path(dir); /* Lock the directory */ + do { + make_file(fn, sizeof(fn), dir, msgnum); + if (!EXISTS(dir, msgnum, fn, chan->language)) + break; + msgnum++; + } while (msgnum < vmu->maxmsg); + + if (msgnum >= vmu->maxmsg) { + ast_unlock_path(dir); + res = ast_streamfile(chan, "vm-mailboxfull", chan->language); + if (!res) + res = ast_waitstream(chan, ""); + ast_log(LOG_WARNING, "No more vm messages possible for mailbox %s@%s\n", ext, context); + /* OEJ: Should we have a manager event here? */ + } else { + /* assign a variable with the name of the voicemail file */ + pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn); + + /* Store information */ + snprintf(txtfile, sizeof(txtfile), "%s.txt", fn); + txt = fopen(txtfile, "w+"); + if (!txt) { + ast_log(LOG_WARNING, "Error opening text file for output\n"); + } else { + get_date(date, sizeof(date)); + fprintf(txt, + ";\n" + "; Message Information file\n" + ";\n" + "[message]\n" + "origmailbox=%s\n" + "context=%s\n" + "macrocontext=%s\n" + "exten=%s\n" + "priority=%d\n" + "callerchan=%s\n" + "callerid=%s\n" + "origdate=%s\n" + "origtime=%ld\n" + "category=%s\n", + ext, + chan->context, + chan->macrocontext, + chan->exten, + chan->priority, + chan->name, + ast_callerid_merge(callerid, sizeof(callerid), chan->cid.cid_name, chan->cid.cid_num, "Unknown"), + date, (long)time(NULL), + category ? category : ""); + } + res = play_record_review(chan, NULL, fn, vmmaxmessage, fmt, 1, vmu, &duration, dir); + if (res == '0') { /* Operator exit */ + if (txt) + fclose(txt); + goto transfer; } - if (res < 0) { - free_user(vmu); - return -1; + if (res > 0) + res = 0; + if (txt) { + fprintf(txt, "duration=%d\n", duration); + fclose(txt); } - /* The meat of recording the message... All the announcements and beeps have been played*/ - ast_copy_string(fmt, vmfmts, sizeof(fmt)); - if (!ast_strlen_zero(fmt)) { - msgnum = 0; - - if (vm_lock_path(dir)) { - free_user(vmu); - return ERROR_LOCK_PATH; - } + + if (duration < vmminmessage) { + if (option_verbose > 2) + ast_verbose( VERBOSE_PREFIX_3 "VM Recording was %d seconds long but needs to be at least %d - abandoning\n", duration, vmminmessage); + DELETE(dir,msgnum,fn); + /* XXX We should really give a prompt too short/option start again, with leave_vm_out called only after a timeout XXX */ + goto leave_vm_out; + } + /* Are there to be more recipients of this message? */ + while (tmpptr) { + struct ast_vm_user recipu, *recip; + char *exten, *context; + + exten = strsep(&tmpptr, "&"); + context = strchr(exten, '@'); + if (context) { + *context = '\0'; + context++; + } + if ((recip = find_user(&recipu, context, exten))) { + copy_message(chan, vmu, 0, msgnum, duration, recip, fmt); + free_user(recip); + } + } + if (ast_fileexists(fn, NULL, NULL)) { + /* Notify mailbox owner of new message */ + notify_new_message(chan, vmu, msgnum, duration, fmt, chan->cid.cid_num, chan->cid.cid_name); + STORE(dir, msgnum); /* Store message in ODBC storage */ + DISPOSE(dir, msgnum); - if (res >= 0) { - /* Unless we're *really* silent, try to send the beep */ - res = ast_streamfile(chan, "beep", chan->language); - if (!res) - res = ast_waitstream(chan, ""); - } - do { - make_file(fn, sizeof(fn), dir, msgnum); - if (!EXISTS(dir,msgnum,fn,chan->language)) - break; - msgnum++; - } while (msgnum < vmu->maxmsg); - if (msgnum < vmu->maxmsg) { - /* assign a variable with the name of the voicemail file */ - pbx_builtin_setvar_helper(chan, "VM_MESSAGEFILE", fn); - - /* Store information */ - snprintf(txtfile, sizeof(txtfile), "%s.txt", fn); - txt = fopen(txtfile, "w+"); - if (txt) { - get_date(date, sizeof(date)); - fprintf(txt, - ";\n" - "; Message Information file\n" - ";\n" - "[message]\n" - "origmailbox=%s\n" - "context=%s\n" - "macrocontext=%s\n" - "exten=%s\n" - "priority=%d\n" - "callerchan=%s\n" - "callerid=%s\n" - "origdate=%s\n" - "origtime=%ld\n" - "category=%s\n", - ext, - chan->context, - chan->macrocontext, - chan->exten, - chan->priority, - chan->name, - ast_callerid_merge(callerid, sizeof(callerid), chan->cid.cid_name, chan->cid.cid_num, "Unknown"), - date, (long)time(NULL), - category ? category : ""); - } else - ast_log(LOG_WARNING, "Error opening text file for output\n"); - res = play_record_review(chan, NULL, fn, vmmaxmessage, fmt, 1, vmu, &duration, dir); - if (res == '0') { - if (txt) - fclose(txt); - goto transfer; - } - if (res > 0) - res = 0; - if (txt) { - fprintf(txt, "duration=%d\n", duration); - fclose(txt); - } - - if (duration < vmminmessage) { - if (option_verbose > 2) - ast_verbose( VERBOSE_PREFIX_3 "Recording was %d seconds long but needs to be at least %d - abandoning\n", duration, vmminmessage); - DELETE(dir,msgnum,fn); - /* XXX We should really give a prompt too short/option start again, with leave_vm_out called only after a timeout XXX */ - goto leave_vm_out; - } - /* Are there to be more recipients of this message? */ - while (tmpptr) { - struct ast_vm_user recipu, *recip; - char *exten, *context; - - exten = strsep(&tmpptr, "&"); - context = strchr(exten, '@'); - if (context) { - *context = '\0'; - context++; - } - if ((recip = find_user(&recipu, context, exten))) { - copy_message(chan, vmu, 0, msgnum, duration, recip, fmt); - free_user(recip); - } - } - if (ast_fileexists(fn, NULL, NULL)) { - notify_new_message(chan, vmu, msgnum, duration, fmt, chan->cid.cid_num, chan->cid.cid_name); - STORE(dir, msgnum); - DISPOSE(dir, msgnum); - } - } else { - ast_unlock_path(dir); - res = ast_streamfile(chan, "vm-mailboxfull", chan->language); - if (!res) - res = ast_waitstream(chan, ""); - ast_log(LOG_WARNING, "No more messages possible\n"); - } - } else - ast_log(LOG_WARNING, "No format for saving voicemail?\n"); + + } leave_vm_out: free_user(vmu); - } else { - ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext); - /*Send the call to n+101 priority, where n is the current priority*/ - ast_goto_if_exists(chan, chan->context, chan->exten, chan->priority + 101); } - return res; } +/*--- resequence_mailbox: Resteructure mailbox after deleteion of message */ static int resequence_mailbox(struct ast_vm_user *vmu, char *dir) { /* we know max messages, so stop process when number is hit */ @@ -2973,6 +3009,7 @@ return cmd; } +/*--- notify_new_message: Notify mailbox owner of new mailbox message */ static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, int msgnum, long duration, char *fmt, char *cidnum, char *cidname) { char todir[256], fn[256], ext_context[256], *stringp; @@ -2984,14 +3021,19 @@ /* Attach only the first format */ fmt = ast_strdupa(fmt); - if (fmt) { + if (!fmt) { + ast_log(LOG_ERROR, "Out of memory\n"); + } else { stringp = fmt; strsep(&stringp, "|"); if (!ast_strlen_zero(vmu->email)) { int attach_user_voicemail = ast_test_flag((&globalflags), VM_ATTACH); char *myserveremail = serveremail; - attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH); + attach_user_voicemail = ast_test_flag(vmu, VM_ATTACH); /* Override ? CHECK */ + /* If the global is set to no, and user to yes - user overrides */ + /* If the global is set, user is unset - how do we know? */ + if (!ast_strlen_zero(vmu->serveremail)) myserveremail = vmu->serveremail; sendmail(myserveremail, vmu, msgnum, vmu->context, vmu->mailbox, cidnum, cidname, fn, fmt, duration, attach_user_voicemail); @@ -3003,8 +3045,6 @@ myserveremail = vmu->serveremail; sendpage(myserveremail, vmu->pager, msgnum, vmu->context, vmu->mailbox, cidnum, cidname, duration, vmu); } - } else { - ast_log(LOG_ERROR, "Out of memory\n"); } if (ast_test_flag(vmu, VM_DELETE)) { @@ -3016,11 +3056,12 @@ ast_app_messagecount(ext_context, &newmsgs, &oldmsgs); } 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); - run_externnotify(vmu->context, vmu->mailbox); + run_externnotify(vmu->context, vmu->mailbox, newmsgs, oldmsgs); return 0; } -static int forward_message(struct ast_channel *chan, char *context, char *dir, int curmsg, struct ast_vm_user *sender, char *fmt,int flag) +/*--- forvard_message: Forward voicemail message to another user */ +static int forward_message(struct ast_channel *chan, char *context, char *dir, int curmsg, struct ast_vm_user *sender, char *fmt, int flag) { char username[70]=""; char sys[256]; @@ -3040,11 +3081,12 @@ int valid_extensions = 0; while (!res && !valid_extensions) { - int use_directory = 0; + if(ast_test_flag((&globalflags), VM_DIRECFORWARD)) { int done = 0; int retries = 0; + cmd=0; while((cmd >= 0) && !done ){ if (cmd) @@ -3069,8 +3111,7 @@ cmd = ast_waitfordigit(chan,3000); if (!cmd) retries++; - if (retries > 3) - { + if (retries > 3) { cmd = 't'; done = 1; } @@ -3091,7 +3132,10 @@ app = pbx_findapp("Directory"); - if (app) { + if (!app) { + ast_log(LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n"); + ast_clear_flag((&globalflags), VM_DIRECFORWARD); + } else { /* make mackup copies */ memcpy(old_context, chan->context, sizeof(chan->context)); memcpy(old_exten, chan->exten, sizeof(chan->exten)); @@ -3106,10 +3150,6 @@ memcpy(chan->context, old_context, sizeof(chan->context)); memcpy(chan->exten, old_exten, sizeof(chan->exten)); chan->priority = old_priority; - - } else { - ast_log(LOG_WARNING, "Could not find the Directory application, disabling directory_forward\n"); - ast_clear_flag((&globalflags), VM_DIRECFORWARD); } } else { /* Ask for an extension */ @@ -3155,7 +3195,7 @@ vmtmp = extensions; if (flag==1) { /* Send VoiceMail */ - cmd=leave_voicemail(chan,username,0,0,0); + cmd=leave_voicemail(chan, username, 0, 0, 0); } else { /* Forward VoiceMail */ cmd = vm_forwardoptions(chan, sender, dir, curmsg, vmfmts, context); @@ -3167,7 +3207,7 @@ snprintf(todir, sizeof(todir), "%s%s/%s/INBOX", VM_SPOOL_DIR, vmtmp->context, vmtmp->mailbox); snprintf(sys, sizeof(sys), "mkdir -p %s\n", todir); snprintf(ext_context, sizeof(ext_context), "%s@%s", vmtmp->mailbox, vmtmp->context); - ast_log(LOG_DEBUG, "%s", sys); + ast_log(LOG_DEBUG, "Creating (or checking) voicmail directory %s", sys); ast_safe_system(sys); if ( (res = count_messages(receiver, todir)) ) @@ -3181,11 +3221,11 @@ if (!strcasecmp(s, "wav49")) s = "WAV"; snprintf(sys, sizeof(sys), "cp %s/msg%04d.%s %s/msg%04d.%s\n", dir, curmsg, s, todir, todircount, s); - ast_log(LOG_DEBUG, "%s", sys); + ast_log(LOG_DEBUG, "VM copy file: %s", sys); ast_safe_system(sys); } snprintf(sys, sizeof(sys), "cp %s/msg%04d.txt %s/msg%04d.txt\n", dir, curmsg, todir, todircount); - ast_log(LOG_DEBUG, "%s", sys); + ast_log(LOG_DEBUG, "VM copy file: %s", sys); ast_safe_system(sys); snprintf(fn, sizeof(fn), "%s/msg%04d", todir,todircount); @@ -3193,7 +3233,7 @@ snprintf(miffile, sizeof(miffile), "%s/msg%04d.txt", dir, curmsg); if ((mif=ast_config_load(miffile))) { - /* set callerid and duration variables */ + /* set callerid and duration variables (should be configurable for localization) */ snprintf(callerid, sizeof(callerid), "FWD from: %s from %s", sender->fullname, ast_variable_retrieve(mif, NULL, "callerid")); s = ast_variable_retrieve(mif, NULL, "duration"); if (s) @@ -3220,8 +3260,7 @@ } /* Leave voicemail for someone */ manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL)); - run_externnotify(vmtmp->context, vmtmp->mailbox); - + run_externnotify(vmtmp->context, vmtmp->mailbox, -1, -1); saved_messages++; vmfree = vmtmp; vmtmp = vmtmp->next; @@ -3581,6 +3620,7 @@ return 0; } +/* vm_play_folder_name_gr: Play folder name in greek syntax (enabled if language code for channel is "gr") */ /* In Greek even though we CAN use a syntax like "friends messages" * ("filika mynhmata") it is not elegant. This also goes for "work/family messages" * ("ergasiaka/oikogeniaka mynhmata"). Therefore it is better to use a reversed @@ -3609,6 +3649,7 @@ } } +/*--- vm_play_folder_name: Play folder name in current language */ static int vm_play_folder_name(struct ast_channel *chan, char *mbox) { int cmd; @@ -5117,7 +5158,7 @@ if (valid) { snprintf(ext_context, sizeof(ext_context), "%s@%s", vms.username, vmu->context); manager_event(EVENT_FLAG_CALL, "MessageWaiting", "Mailbox: %s\r\nWaiting: %d\r\n", ext_context, has_voicemail(ext_context, NULL)); - run_externnotify(vmu->context, vmu->mailbox); + run_externnotify(vmu->context, vmu->mailbox, -1, -1); } if (vmu) free_user(vmu); @@ -5844,6 +5885,7 @@ return(load_config()); } +/*--- unload_module: Unload voicemail application */ int unload_module(void) { int res; @@ -5860,6 +5902,7 @@ return res; } +/*--- load_module: Load voicemail application into Asterisk */ int load_module(void) { int res; @@ -5879,6 +5922,9 @@ /* compute the location of the voicemail spool directory */ snprintf(VM_SPOOL_DIR, sizeof(VM_SPOOL_DIR), "%s/voicemail/", ast_config_AST_SPOOL_DIR); + + /* Find host name */ + gethostname(host, sizeof(host)-1); ast_install_vm_functions(has_voicemail, messagecount);