79 #ifdef USE_SYSTEM_IMAP
80 #include <imap/c-client.h>
81 #include <imap/imap4r1.h>
82 #include <imap/linkage.h>
83 #elif defined (USE_SYSTEM_CCLIENT)
84 #include <c-client/c-client.h>
85 #include <c-client/imap4r1.h>
86 #include <c-client/linkage.h>
96 #include "asterisk/paths.h"
102 #if defined(__FreeBSD__) || defined(__OpenBSD__)
103 #include <sys/wait.h>
375 static char imapserver[48];
376 static char imapport[8];
377 static char imapflags[128];
378 static char imapfolder[64];
379 static char imapparentfolder[64] =
"\0";
380 static char greetingfolder[64];
381 static char authuser[32];
382 static char authpassword[42];
383 static int imapversion = 1;
385 static int expungeonhangup = 1;
386 static int imapgreetings = 0;
387 static char delimiter =
'\0';
395 static int init_mailstream(
struct vm_state *vms,
int box);
396 static void write_file(
char *filename,
char *buffer,
unsigned long len);
397 static char *get_header_by_tag(
char *header,
char *tag,
char *buf,
size_t len);
398 static void vm_imap_delete(
char *file,
int msgnum,
struct ast_vm_user *vmu);
399 static char *get_user_by_mailbox(
char *
mailbox,
char *buf,
size_t len);
400 static struct vm_state *get_vm_state_by_imapuser(
const char *
user,
int interactive);
401 static struct vm_state *get_vm_state_by_mailbox(
const char *
mailbox,
const char *
context,
int interactive);
403 static void vmstate_insert(
struct vm_state *vms);
404 static void vmstate_delete(
struct vm_state *vms);
405 static void set_update(MAILSTREAM * stream);
406 static void init_vm_state(
struct vm_state *vms);
407 static int save_body(BODY *body,
struct vm_state *vms,
char *section,
char *
format,
int is_intro);
408 static void get_mailbox_delimiter(MAILSTREAM *stream);
409 static void mm_parsequota (MAILSTREAM *stream,
unsigned char *msg, QUOTALIST *pquota);
410 static void imap_mailbox_name(
char *spec,
size_t len,
struct vm_state *vms,
int box,
int target);
411 static int imap_store_file(
const char *dir,
const char *mailboxuser,
const char *mailboxcontext,
int msgnum,
struct ast_channel *chan,
struct ast_vm_user *vmu,
char *fmt,
int duration,
struct vm_state *vms,
const char *flag);
412 static void update_messages_by_imapuser(
const char *
user,
unsigned long number);
415 static int imap_remove_file (
char *dir,
int msgnum);
416 static int imap_retrieve_file (
const char *dir,
const int msgnum,
const char *
mailbox,
const char *
context);
417 static int imap_delete_old_greeting (
char *dir,
struct vm_state *vms);
429 #define SMDI_MWI_WAIT_TIMEOUT 1000
431 #define COMMAND_TIMEOUT 5000
433 #define VOICEMAIL_DIR_MODE 0777
434 #define VOICEMAIL_FILE_MODE 0666
435 #define CHUNKSIZE 65536
437 #define VOICEMAIL_CONFIG "voicemail.conf"
438 #define ASTERISK_USERNAME "asterisk"
443 #define DEFAULT_LISTEN_CONTROL_FORWARD_KEY "#"
444 #define DEFAULT_LISTEN_CONTROL_REVERSE_KEY "*"
445 #define DEFAULT_LISTEN_CONTROL_PAUSE_KEY "0"
446 #define DEFAULT_LISTEN_CONTROL_RESTART_KEY "2"
447 #define DEFAULT_LISTEN_CONTROL_STOP_KEY "13456789"
448 #define VALID_DTMF "1234567890*#"
452 #define SENDMAIL "/usr/sbin/sendmail -t"
454 #define INTRO "vm-intro"
457 #define MAXMSGLIMIT 9999
459 #define MINPASSWORD 0
461 #define BASELINELEN 72
462 #define BASEMAXINLINE 256
469 #define MAX_DATETIME_FORMAT 512
470 #define MAX_NUM_CID_CONTEXTS 10
472 #define VM_REVIEW (1 << 0)
473 #define VM_OPERATOR (1 << 1)
474 #define VM_SAYCID (1 << 2)
475 #define VM_SVMAIL (1 << 3)
476 #define VM_ENVELOPE (1 << 4)
477 #define VM_SAYDURATION (1 << 5)
478 #define VM_SKIPAFTERCMD (1 << 6)
479 #define VM_FORCENAME (1 << 7)
480 #define VM_FORCEGREET (1 << 8)
481 #define VM_PBXSKIP (1 << 9)
482 #define VM_DIRECFORWARD (1 << 10)
483 #define VM_ATTACH (1 << 11)
484 #define VM_DELETE (1 << 12)
485 #define VM_ALLOCED (1 << 13)
486 #define VM_SEARCH (1 << 14)
487 #define VM_TEMPGREETWARN (1 << 15)
488 #define VM_MOVEHEARD (1 << 16)
489 #define VM_MESSAGEWRAP (1 << 17)
490 #define VM_FWDURGAUTO (1 << 18)
491 #define ERROR_LOCK_PATH -100
492 #define OPERATOR_EXIT 300
543 #ifdef TEST_FRAMEWORK
668 char imappassword[80];
670 char imapvmshareid[80];
682 char msg_format[512];
685 #define VMSTATE_MAX_MSG_ARRAY 256
692 char curdir[PATH_MAX];
693 char vmbox[PATH_MAX];
695 char intro[PATH_MAX];
710 unsigned msg_array_max;
711 MAILSTREAM *mailstream;
717 char introfn[PATH_MAX];
718 unsigned int quota_limit;
719 unsigned int quota_usage;
725 static char odbc_database[80];
726 static char odbc_table[80];
727 #define RETRIEVE(a,b,c,d) retrieve_file(a,b)
728 #define DISPOSE(a,b) remove_file(a,b)
729 #define STORE(a,b,c,d,e,f,g,h,i,j) store_file(a,b,c,d)
730 #define EXISTS(a,b,c,d) (message_exists(a,b))
731 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(a,b,c,d,e,f))
732 #define COPY(a,b,c,d,e,f,g,h) (copy_file(a,b,c,d,e,f))
733 #define DELETE(a,b,c,d) (delete_file(a,b))
736 #define DISPOSE(a,b) (imap_remove_file(a,b))
737 #define STORE(a,b,c,d,e,f,g,h,i,j) (imap_store_file(a,b,c,d,e,f,g,h,i,j))
738 #define RETRIEVE(a,b,c,d) imap_retrieve_file(a,b,c,d)
739 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
740 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
741 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
742 #define DELETE(a,b,c,d) (vm_imap_delete(a,b,d))
744 #define RETRIEVE(a,b,c,d)
746 #define STORE(a,b,c,d,e,f,g,h,i,j)
747 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
748 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
749 #define COPY(a,b,c,d,e,f,g,h) (copy_plain_file(g,h));
750 #define DELETE(a,b,c,d) (vm_delete(c))
761 #define PWDCHANGE_INTERNAL (1 << 1)
762 #define PWDCHANGE_EXTERNAL (1 << 2)
766 #define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
769 # define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
771 # define tdesc "Comedian Mail (Voicemail System)"
780 static char *
app =
"VoiceMail";
783 static char *
app2 =
"VoiceMailMain";
785 static char *
app3 =
"MailboxExists";
786 static char *
app4 =
"VMAuthenticate";
819 #define DEFAULT_POLL_FREQ 30
904 static unsigned char adsifdn[4] =
"\x00\x00\x00\x0F";
905 static unsigned char adsisec[4] =
"\x9B\xDB\xF7\xAC";
915 char *fmt,
int outsidecaller,
struct ast_vm_user *vmu,
int *duration,
int *sound_duration,
const char *unlockdir,
916 signed char record_gain,
struct vm_state *vms,
char *flag);
920 static void make_email_file(FILE *p,
char *srcemail,
struct ast_vm_user *vmu,
int msgnum,
char *
context,
char *
mailbox,
const char *fromfolder,
char *cidnum,
char *cidname,
char *attach,
char *attach2,
char *
format,
int duration,
int attach_user_voicemail,
struct ast_channel *chan,
const char *category,
int imap,
const char *flag);
946 if (strcmp(i->
mailbox, j->mailbox)) {
954 struct inprocess *i, *arg =
ast_alloca(
sizeof(*arg) + strlen(context) + strlen(mailbox) + 2);
959 if ((i =
ao2_find(inprocess_container, arg, 0))) {
968 if (!(i =
ao2_alloc(
sizeof(*i) + strlen(context) + strlen(mailbox) + 2, NULL))) {
982 #if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
995 for (; *
input; input++) {
1000 if (bufptr == buf + buflen - 1) {
1026 if (saydurationminfo) {
1043 if (maxdeletedmsg) {
1052 ast_copy_string(vmu->imapfolder, imapfolder,
sizeof(vmu->imapfolder));
1067 if (!strcasecmp(var,
"attach")) {
1069 }
else if (!strcasecmp(var,
"attachfmt")) {
1071 }
else if (!strcasecmp(var,
"serveremail")) {
1073 }
else if (!strcasecmp(var,
"emailbody")) {
1075 }
else if (!strcasecmp(var,
"emailsubject")) {
1077 }
else if (!strcasecmp(var,
"language")) {
1079 }
else if (!strcasecmp(var,
"tz")) {
1081 }
else if (!strcasecmp(var,
"locale")) {
1084 }
else if (!strcasecmp(var,
"imapuser")) {
1086 vmu->imapversion = imapversion;
1087 }
else if (!strcasecmp(var,
"imappassword") || !strcasecmp(var,
"imapsecret")) {
1089 vmu->imapversion = imapversion;
1090 }
else if (!strcasecmp(var,
"imapfolder")) {
1092 }
else if (!strcasecmp(var,
"imapvmshareid")) {
1093 ast_copy_string(vmu->imapvmshareid, value,
sizeof(vmu->imapvmshareid));
1094 vmu->imapversion = imapversion;
1096 }
else if (!strcasecmp(var,
"delete") || !strcasecmp(var,
"deletevoicemail")) {
1098 }
else if (!strcasecmp(var,
"saycid")){
1100 }
else if (!strcasecmp(var,
"sendvoicemail")){
1102 }
else if (!strcasecmp(var,
"review")){
1104 }
else if (!strcasecmp(var,
"tempgreetwarn")){
1106 }
else if (!strcasecmp(var,
"messagewrap")){
1108 }
else if (!strcasecmp(var,
"operator")) {
1110 }
else if (!strcasecmp(var,
"envelope")){
1112 }
else if (!strcasecmp(var,
"moveheard")){
1114 }
else if (!strcasecmp(var,
"sayduration")){
1116 }
else if (!strcasecmp(var,
"saydurationm")){
1117 if (sscanf(value,
"%30d", &x) == 1) {
1122 }
else if (!strcasecmp(var,
"forcename")){
1124 }
else if (!strcasecmp(var,
"forcegreetings")){
1126 }
else if (!strcasecmp(var,
"callback")) {
1128 }
else if (!strcasecmp(var,
"dialout")) {
1130 }
else if (!strcasecmp(var,
"exitcontext")) {
1132 }
else if (!strcasecmp(var,
"minsecs")) {
1133 if (sscanf(value,
"%30d", &x) == 1 && x >= 0) {
1136 ast_log(
LOG_WARNING,
"Invalid min message length of %s. Using global value %d\n", value, vmminsecs);
1139 }
else if (!strcasecmp(var,
"maxmessage") || !strcasecmp(var,
"maxsecs")) {
1147 if (!strcasecmp(var,
"maxmessage"))
1148 ast_log(
AST_LOG_WARNING,
"Option 'maxmessage' has been deprecated in favor of 'maxsecs'. Please make that change in your voicemail config.\n");
1149 }
else if (!strcasecmp(var,
"maxmsg")) {
1150 vmu->
maxmsg = atoi(value);
1159 }
else if (!strcasecmp(var,
"nextaftercmd")) {
1161 }
else if (!strcasecmp(var,
"backupdeleted")) {
1162 if (sscanf(value,
"%30d", &x) == 1)
1170 ast_log(
AST_LOG_WARNING,
"Invalid number of deleted messages saved per mailbox backupdeleted=%s. Using default value %d\n", value,
MAXMSG);
1176 }
else if (!strcasecmp(var,
"volgain")) {
1177 sscanf(value,
"%30lf", &vmu->
volgain);
1178 }
else if (!strcasecmp(var,
"passwordlocation")) {
1179 if (!strcasecmp(value,
"spooldir")) {
1184 }
else if (!strcasecmp(var,
"options")) {
1191 int fds[2], pid = 0;
1193 memset(buf, 0, len);
1196 snprintf(buf, len,
"FAILURE: Pipe failed: %s", strerror(
errno));
1205 snprintf(buf, len,
"FAILURE: Fork failed");
1209 if (read(fds[0], buf, len) < 0) {
1221 dup2(fds[1], STDOUT_FILENO);
1227 execv(arg.v[0], arg.v);
1228 printf(
"FAILURE: %s", strerror(
errno));
1245 if (strlen(password) < minpassword)
1251 char cmd[255], buf[255];
1255 snprintf(cmd,
sizeof(cmd),
"%s %s %s %s %s", ext_pass_check_cmd, vmu->
mailbox, vmu->
context, vmu->
password, password);
1258 if (!strncasecmp(buf,
"VALID", 5)) {
1259 ast_debug(3,
"Passed password check: '%s'\n", buf);
1261 }
else if (!strncasecmp(buf,
"FAILURE", 7)) {
1286 if (!strcmp(vmu->
password, password)) {
1291 if (strlen(password) > 10) {
1311 while ((s =
strsep(&stringp,
"|"))) {
1313 if ((var =
strsep(&value,
"=")) && value) {
1326 for (;
var; var = var->
next) {
1327 if (!strcasecmp(var->
name,
"vmsecret")) {
1329 }
else if (!strcasecmp(var->
name,
"secret") || !strcasecmp(var->
name,
"password")) {
1333 "\n\tmust be reset in voicemail.conf.\n", retval->
mailbox);
1338 }
else if (!strcasecmp(var->
name,
"uniqueid")) {
1340 }
else if (!strcasecmp(var->
name,
"pager")) {
1342 }
else if (!strcasecmp(var->
name,
"email")) {
1344 }
else if (!strcasecmp(var->
name,
"fullname")) {
1346 }
else if (!strcasecmp(var->
name,
"context")) {
1348 }
else if (!strcasecmp(var->
name,
"emailsubject")) {
1351 }
else if (!strcasecmp(var->
name,
"emailbody")) {
1355 }
else if (!strcasecmp(var->
name,
"imapuser")) {
1357 retval->imapversion = imapversion;
1358 }
else if (!strcasecmp(var->
name,
"imappassword") || !strcasecmp(var->
name,
"imapsecret")) {
1360 retval->imapversion = imapversion;
1361 }
else if (!strcasecmp(var->
name,
"imapfolder")) {
1363 }
else if (!strcasecmp(var->
name,
"imapvmshareid")) {
1365 retval->imapversion = imapversion;
1384 for (i = 0; i < strlen(key); ++i) {
1409 if ((retval = (ivm ? ivm :
ast_calloc(1,
sizeof(*retval))))) {
1411 memset(retval, 0,
sizeof(*retval));
1452 context =
"default";
1456 if (cur->imapversion != imapversion) {
1462 if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
1467 if ((vmu = (ivm ? ivm :
ast_malloc(
sizeof(*vmu))))) {
1499 if ((!context || !strcasecmp(context, cur->
context)) &&
1500 (!strcasecmp(mailbox, cur->
mailbox)))
1531 char *category = NULL, *
value = NULL, *
new = NULL;
1532 const char *tmp = NULL;
1534 char secretfn[PATH_MAX] =
"";
1543 snprintf(secretfn,
sizeof(secretfn),
"%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->
context, vmu->
mailbox);
1546 ast_verb(4,
"Writing voicemail password to file %s succeeded\n", secretfn);
1551 ast_verb(4,
"Writing voicemail password to file %s failed, falling back to config file\n", secretfn);
1557 if (!strcasecmp(category, vmu->
context)) {
1562 value = strstr(tmp,
",");
1565 sprintf(
new,
"%s", newpassword);
1567 new =
ast_alloca((strlen(value) + strlen(newpassword) + 1));
1568 sprintf(
new,
"%s%s", newpassword, value);
1580 ast_test_suite_event_notify(
"PASSWORDCHANGED",
"Message: voicemail.conf updated with new password\r\nPasswordSource: voicemail.conf");
1597 ast_debug(4,
"users.conf: %s\n", category);
1598 if (!strcasecmp(category, vmu->
mailbox)) {
1600 ast_debug(3,
"looks like we need to make vmsecret!\n");
1606 sprintf(
new,
"%s", newpassword);
1608 ast_debug(4,
"failed to get category!\n");
1637 snprintf(buf,
sizeof(buf),
"%s %s %s %s", ext_pass_cmd, vmu->
context, vmu->
mailbox, newpassword);
1638 ast_debug(1,
"External password: %s\n",buf);
1662 return snprintf(dest, len,
"%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
1677 static int make_file(
char *dest,
const int len,
const char *dir,
const int num)
1679 return snprintf(dest, len,
"%s/msg%04d", dir, num);
1686 int pfd = mkstemp(
template);
1689 p = fdopen(pfd,
"w+");
1711 make_dir(dest, len, context, ext, folder);
1741 if (vmu &&
id == 0) {
1742 return vmu->imapfolder;
1745 return (
id >= 0 &&
id <
ARRAY_LEN(mailbox_folders)) ? mailbox_folders[
id] :
"Unknown";
1752 for (i = 0; i <
ARRAY_LEN(mailbox_folders); i++) {
1753 if (strcasecmp(name, mailbox_folders[i]) == 0) {
1777 int arraysize = (vmu->
maxmsg > count_msg ? vmu->
maxmsg : count_msg);
1790 if (arraysize > 0) {
1808 static void vm_imap_delete(
char *file,
int msgnum,
struct ast_vm_user *vmu)
1812 unsigned long messageNum;
1815 if (msgnum < 0 && !imapgreetings) {
1820 if (!(vms = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 0))) {
1821 ast_log(
LOG_WARNING,
"Couldn't find a vm_state for mailbox %s. Unable to set \\DELETED flag for message %d\n", vmu->
mailbox, msgnum);
1826 imap_delete_old_greeting(file, vms);
1832 messageNum = vms->msgArray[msgnum];
1833 if (messageNum == 0) {
1834 ast_log(
LOG_WARNING,
"msgnum %d, mailbox message %lu is zero.\n", msgnum, messageNum);
1838 ast_log(
LOG_DEBUG,
"deleting msgnum %d, which is mailbox message %lu\n", msgnum, messageNum);
1840 snprintf (arg,
sizeof(arg),
"%lu", messageNum);
1842 mail_setflag (vms->mailstream, arg,
"\\DELETED");
1843 mail_expunge(vms->mailstream);
1847 static int imap_retrieve_greeting(
const char *dir,
const int msgnum,
struct ast_vm_user *vmu)
1850 char *file, *filename;
1858 if (msgnum > -1 || !imapgreetings) {
1865 ast_debug (1,
"Failed to procure file name from directory passed.\n");
1871 if (!(vms_p = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 1)) &&
1872 !(vms_p = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 0))) {
1877 if (!(vms_p = create_vm_state_from_user(vmu))) {
1884 *vms_p->introfn =
'\0';
1888 if (!vms_p->mailstream) {
1895 for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
1896 mail_fetchstructure(vms_p->mailstream, i + 1, &body);
1898 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
1899 attachment =
ast_strdupa(body->nested.part->next->body.parameter->value);
1905 filename =
strsep(&attachment,
".");
1906 if (!strcmp(filename, file)) {
1908 vms_p->msgArray[vms_p->
curmsg] = i + 1;
1909 save_body(body, vms_p,
"2", attachment, 0);
1919 static int imap_retrieve_file(
const char *dir,
const int msgnum,
const char *
mailbox,
const char *
context)
1922 char *header_content;
1923 char *attachedfilefmt;
1926 char text_file[PATH_MAX];
1927 FILE *text_file_ptr;
1931 if (!(vmu =
find_user(NULL, context, mailbox))) {
1937 if (imapgreetings) {
1938 res = imap_retrieve_greeting(dir, msgnum, vmu);
1949 if (!(vms = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 0))) {
1963 snprintf(vms->introfn,
sizeof(vms->introfn),
"%sintro", vms->
fn);
1972 ast_log(
LOG_DEBUG,
"Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
1973 if (vms->msgArray[msgnum] == 0) {
1981 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
1985 ast_log(
LOG_ERROR,
"Could not fetch header for message number %ld\n", vms->msgArray[msgnum]);
1991 mail_fetchstructure(vms->mailstream, vms->msgArray[msgnum], &body);
1995 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
1996 attachedfilefmt =
ast_strdupa(body->nested.part->next->body.parameter->value);
2005 strsep(&attachedfilefmt,
".");
2006 if (!attachedfilefmt) {
2007 ast_log(
LOG_ERROR,
"File format could not be obtained from IMAP message attachment\n");
2012 save_body(body, vms,
"2", attachedfilefmt, 0);
2013 if (save_body(body, vms,
"3", attachedfilefmt, 1)) {
2014 *vms->introfn =
'\0';
2018 snprintf(text_file,
sizeof(text_file),
"%s.%s", vms->
fn,
"txt");
2020 if (!(text_file_ptr = fopen(text_file,
"w"))) {
2024 fprintf(text_file_ptr,
"%s\n",
"[message]");
2026 get_header_by_tag(header_content,
"X-Asterisk-VM-Caller-ID-Name:", buf,
sizeof(buf));
2027 fprintf(text_file_ptr,
"callerid=\"%s\" ",
S_OR(buf,
""));
2028 get_header_by_tag(header_content,
"X-Asterisk-VM-Caller-ID-Num:", buf,
sizeof(buf));
2029 fprintf(text_file_ptr,
"<%s>\n",
S_OR(buf,
""));
2030 get_header_by_tag(header_content,
"X-Asterisk-VM-Context:", buf,
sizeof(buf));
2031 fprintf(text_file_ptr,
"context=%s\n",
S_OR(buf,
""));
2032 get_header_by_tag(header_content,
"X-Asterisk-VM-Orig-time:", buf,
sizeof(buf));
2033 fprintf(text_file_ptr,
"origtime=%s\n",
S_OR(buf,
""));
2034 get_header_by_tag(header_content,
"X-Asterisk-VM-Duration:", buf,
sizeof(buf));
2035 fprintf(text_file_ptr,
"duration=%s\n",
S_OR(buf,
""));
2036 get_header_by_tag(header_content,
"X-Asterisk-VM-Category:", buf,
sizeof(buf));
2037 fprintf(text_file_ptr,
"category=%s\n",
S_OR(buf,
""));
2038 get_header_by_tag(header_content,
"X-Asterisk-VM-Flag:", buf,
sizeof(buf));
2039 fprintf(text_file_ptr,
"flag=%s\n",
S_OR(buf,
""));
2040 fclose(text_file_ptr);
2047 static int folder_int(
const char *folder)
2053 if (!strcasecmp(folder, imapfolder)) {
2055 }
else if (!strcasecmp(folder,
"Old")) {
2057 }
else if (!strcasecmp(folder,
"Work")) {
2059 }
else if (!strcasecmp(folder,
"Family")) {
2061 }
else if (!strcasecmp(folder,
"Friends")) {
2063 }
else if (!strcasecmp(folder,
"Cust1")) {
2065 }
else if (!strcasecmp(folder,
"Cust2")) {
2067 }
else if (!strcasecmp(folder,
"Cust3")) {
2069 }
else if (!strcasecmp(folder,
"Cust4")) {
2071 }
else if (!strcasecmp(folder,
"Cust5")) {
2073 }
else if (!strcasecmp(folder,
"Urgent")) {
2080 static int __messagecount(
const char *context,
const char *mailbox,
const char *folder)
2088 int fold = folder_int(folder);
2101 vmu =
find_user(&vmus, context, mailbox);
2107 if (vmu->imapuser[0] ==
'\0') {
2114 if (vmu->imapuser[0] ==
'\0') {
2122 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1);
2124 vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
2127 ast_debug(3,
"Returning before search - user is logged in\n");
2137 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 0);
2139 vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
2143 vms_p = create_vm_state_from_user(vmu);
2145 ret = init_mailstream(vms_p, fold);
2146 if (!vms_p->mailstream) {
2152 pgm = mail_newsearchpgm ();
2153 hdr = mail_newsearchheader (
"X-Asterisk-VM-Extension", (
char *)(!
ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
2154 hdr->next = mail_newsearchheader(
"X-Asterisk-VM-Context", (
char *)
S_OR(context,
"default"));
2180 vms_p->vmArrayIndex = 0;
2181 mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
2182 if (fold == 0 && urgent == 0)
2186 if (fold == 0 && urgent == 1)
2189 mail_free_searchpgm(&pgm);
2192 return vms_p->vmArrayIndex;
2195 mail_ping(vms_p->mailstream);
2204 check_quota(vms, vmu->imapfolder);
2205 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
2206 ast_debug(1,
"*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
2214 ast_log(
LOG_WARNING,
"Unable to leave message since we will exceed the maximum number of messages allowed (%u >= %u)\n", msgnum, vmu->
maxmsg);
2232 static int messagecount(
const char *context,
const char *mailbox,
const char *folder)
2235 return __messagecount(context, mailbox,
"INBOX") + __messagecount(context, mailbox,
"Urgent");
2237 return __messagecount(context, mailbox, folder);
2241 static int imap_store_file(
const char *dir,
const char *mailboxuser,
const char *mailboxcontext,
int msgnum,
struct ast_channel *chan,
struct ast_vm_user *vmu,
char *fmt,
int duration,
struct vm_state *vms,
const char *flag)
2245 char introfn[PATH_MAX];
2249 char tmp[80] =
"/tmp/astmail-XXXXXX";
2255 char *imap_flags = NIL;
2261 if(!imapgreetings) {
2268 if (imap_check_limits(chan, vms, vmu, msgcount)) {
2274 ast_debug(3,
"Setting message flag \\\\FLAGGED.\n");
2275 imap_flags =
"\\FLAGGED";
2291 snprintf(introfn,
sizeof(introfn),
"%sintro", fn);
2306 if (!strcmp(fmt,
"wav49"))
2308 ast_debug(3,
"Storing file '%s', format '%s'\n", fn, fmt);
2315 *(vmu->
email) =
'\0';
2319 if (msgnum < 0 && imapgreetings) {
2324 imap_delete_old_greeting(fn, vms);
2330 fn, introfn, fmt, duration, 1, chan, NULL, 1, flag);
2338 *(vmu->
email) =
'\0';
2341 if (fread(buf, len, 1, p) <
len) {
2347 ((
char *) buf)[
len] =
'\0';
2348 INIT(&str, mail_string, buf, len);
2349 ret = init_mailstream(vms, box);
2351 imap_mailbox_name(mailbox,
sizeof(mailbox), vms, box, 1);
2353 if(!mail_append_full(vms->mailstream, mailbox, imap_flags, NIL, &str))
2369 *(vmu->
email) =
'\0';
2388 static int inboxcount2(
const char *mailbox_context,
int *urgentmsgs,
int *newmsgs,
int *oldmsgs)
2390 char tmp[PATH_MAX] =
"";
2402 ast_debug(3,
"Mailbox is set to %s\n", mailbox_context);
2408 context = strchr(tmp,
'@');
2409 if (strchr(mailbox_context,
',')) {
2410 int tmpnew, tmpold, tmpurgent;
2413 while ((cur =
strsep(&mb,
", "))) {
2415 if (
inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
2423 *urgentmsgs += tmpurgent;
2434 context =
"default";
2435 mailboxnc = (
char *) mailbox_context;
2444 if ((*newmsgs = __messagecount(context, mailboxnc, vmu->imapfolder)) < 0) {
2451 if ((*oldmsgs = __messagecount(context, mailboxnc,
"Old")) < 0) {
2456 if ((*urgentmsgs = __messagecount(context, mailboxnc,
"Urgent")) < 0) {
2473 static int has_voicemail(
const char *mailbox,
const char *folder)
2475 char tmp[256], *tmp2, *box, *
context;
2478 if (strchr(tmp2,
',') || strchr(tmp2,
'&')) {
2479 while ((box =
strsep(&tmp2,
",&"))) {
2487 if ((context = strchr(tmp,
'@'))) {
2490 context =
"default";
2492 return __messagecount(context, tmp, folder) ? 1 : 0;
2512 struct vm_state *sendvms = NULL, *destvms = NULL;
2513 char messagestring[10];
2514 if (msgnum >= recip->
maxmsg) {
2518 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
2522 if (!(destvms = get_vm_state_by_imapuser(recip->imapuser, 0))) {
2526 snprintf(messagestring,
sizeof(messagestring),
"%ld", sendvms->msgArray[msgnum]);
2528 if ((mail_copy(sendvms->mailstream, messagestring, (
char *)
mbox(vmu, imbox)) == T)) {
2537 static void imap_mailbox_name(
char *spec,
size_t len,
struct vm_state *vms,
int box,
int use_folder)
2539 char tmp[256], *t = tmp;
2540 size_t left =
sizeof(tmp);
2551 snprintf(vms->
vmbox,
sizeof(vms->
vmbox),
"vm-%s",
mbox(NULL, box));
2572 snprintf(spec, len,
"%s%s", tmp, use_folder? vms->imapfolder:
"INBOX");
2574 snprintf(spec, len,
"%s%s", tmp, greetingfolder);
2578 snprintf(spec, len,
"%s%s%c%s", tmp, imapparentfolder, delimiter,
mbox(NULL, box));
2580 snprintf(spec, len,
"%s%s", tmp,
mbox(NULL, box));
2585 static int init_mailstream(
struct vm_state *vms,
int box)
2587 MAILSTREAM *stream = NIL;
2597 if (vms->mailstream == NIL || !vms->mailstream) {
2601 stream = vms->mailstream;
2606 if (delimiter ==
'\0') {
2608 #ifdef USE_SYSTEM_IMAP
2609 #include <imap/linkage.c>
2610 #elif defined(USE_SYSTEM_CCLIENT)
2611 #include <c-client/linkage.c>
2613 #include "linkage.c"
2616 imap_mailbox_name(tmp,
sizeof(tmp), vms, 0, 1);
2618 stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
2620 if (stream == NIL) {
2624 get_mailbox_delimiter(stream);
2626 for (cp = vms->imapfolder; *cp; cp++)
2631 imap_mailbox_name(tmp,
sizeof(tmp), vms, box, 1);
2635 vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
2637 if (vms->mailstream == NIL) {
2648 int ret, urgent = 0;
2657 ast_copy_string(vms->imapfolder, vmu->imapfolder,
sizeof(vms->imapfolder));
2658 vms->imapversion = vmu->imapversion;
2659 ast_debug(3,
"Before init_mailstream, user is %s\n", vmu->imapuser);
2661 if ((ret = init_mailstream(vms, box)) || !vms->mailstream) {
2670 ast_debug(3,
"Mailbox name set to: %s, about to check quotas\n",
mbox(vmu, box));
2671 check_quota(vms, (
char *)
mbox(vmu, box));
2675 pgm = mail_newsearchpgm();
2678 hdr = mail_newsearchheader(
"X-Asterisk-VM-Extension", (!
ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->
mailbox));
2679 hdr->next = mail_newsearchheader(
"X-Asterisk-VM-Context", vmu->
context);
2690 }
else if (box ==
NEW_FOLDER && urgent == 0) {
2700 ast_debug(3,
"Before mail_search_full, user is %s\n", vmu->imapuser);
2702 vms->vmArrayIndex = 0;
2703 mail_search_full (vms->mailstream, NULL, pgm, NIL);
2704 vms->
lastmsg = vms->vmArrayIndex - 1;
2705 mail_free_searchpgm(&pgm);
2711 ast_log(
LOG_WARNING,
"The code expects the old messages to be checked first, fix the code.\n");
2722 static void write_file(
char *filename,
char *buffer,
unsigned long len)
2726 output = fopen (filename,
"w");
2727 if (fwrite(buffer, len, 1, output) != 1) {
2728 if (ferror(output)) {
2735 static void update_messages_by_imapuser(
const char *
user,
unsigned long number)
2737 struct vm_state *vms = get_vm_state_by_imapuser(user, 1);
2739 if (!vms && !(vms = get_vm_state_by_imapuser(user, 0))) {
2743 ast_debug(3,
"saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive);
2746 if (vms->vmArrayIndex >= vms->msg_array_max) {
2747 long *new_mem =
ast_realloc(vms->msgArray, 2 * vms->msg_array_max *
sizeof(
long));
2751 vms->msgArray = new_mem;
2752 vms->msg_array_max *= 2;
2755 vms->msgArray[vms->vmArrayIndex++] = number;
2758 void mm_searched(MAILSTREAM *stream,
unsigned long number)
2760 char *mailbox = stream->mailbox, buf[1024] =
"", *
user;
2762 if (!(user = get_user_by_mailbox(mailbox, buf,
sizeof(buf))))
2765 update_messages_by_imapuser(user, number);
2768 static struct ast_vm_user *find_user_realtime_imapuser(
const char *imapuser)
2793 void mm_exists(MAILSTREAM * stream,
unsigned long number)
2796 ast_debug(4,
"Entering EXISTS callback for message %ld\n", number);
2797 if (number == 0)
return;
2802 void mm_expunged(MAILSTREAM * stream,
unsigned long number)
2805 ast_debug(4,
"Entering EXPUNGE callback for message %ld\n", number);
2806 if (number == 0)
return;
2811 void mm_flags(MAILSTREAM * stream,
unsigned long number)
2814 ast_debug(4,
"Entering FLAGS callback for message %ld\n", number);
2815 if (number == 0)
return;
2820 void mm_notify(MAILSTREAM * stream,
char *
string,
long errflg)
2822 ast_debug(5,
"Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg,
string);
2823 mm_log (
string, errflg);
2827 void mm_list(MAILSTREAM * stream,
int delim,
char *mailbox,
long attributes)
2829 if (delimiter ==
'\0') {
2833 ast_debug(5,
"Delimiter set to %c and mailbox %s\n", delim, mailbox);
2834 if (attributes & LATT_NOINFERIORS)
2836 if (attributes & LATT_NOSELECT)
2838 if (attributes & LATT_MARKED)
2840 if (attributes & LATT_UNMARKED)
2845 void mm_lsub(MAILSTREAM * stream,
int delim,
char *mailbox,
long attributes)
2847 ast_debug(5,
"Delimiter set to %c and mailbox %s\n", delim, mailbox);
2848 if (attributes & LATT_NOINFERIORS)
2850 if (attributes & LATT_NOSELECT)
2852 if (attributes & LATT_MARKED)
2854 if (attributes & LATT_UNMARKED)
2859 void mm_status(MAILSTREAM * stream,
char *mailbox, MAILSTATUS *
status)
2862 if (status->flags & SA_MESSAGES)
2864 if (status->flags & SA_RECENT)
2866 if (status->flags & SA_UNSEEN)
2868 if (status->flags & SA_UIDVALIDITY)
2870 if (status->flags & SA_UIDNEXT)
2876 void mm_log(
char *
string,
long errflg)
2878 switch ((
short) errflg) {
2880 ast_debug(1,
"IMAP Info: %s\n",
string);
2893 void mm_dlog(
char *
string)
2899 void mm_login(NETMBX * mb,
char *user,
char *pwd,
long trial)
2903 ast_debug(4,
"Entering callback mm_login\n");
2912 if (!strcasecmp(mb->user, vmu->imapuser)) {
2918 if ((vmu = find_user_realtime_imapuser(mb->user))) {
2927 void mm_critical(MAILSTREAM * stream)
2932 void mm_nocritical(MAILSTREAM * stream)
2937 long mm_diskerror(MAILSTREAM * stream,
long errcode,
long serious)
2939 kill (getpid (), SIGSTOP);
2944 void mm_fatal(
char *
string)
2950 static void mm_parsequota(MAILSTREAM *stream,
unsigned char *msg, QUOTALIST *pquota)
2953 char *mailbox = stream->mailbox, *
user;
2954 char buf[1024] =
"";
2955 unsigned long usage = 0, limit = 0;
2958 usage = pquota->usage;
2959 limit = pquota->limit;
2960 pquota = pquota->next;
2963 if (!(user = get_user_by_mailbox(mailbox, buf,
sizeof(buf))) || (!(vms = get_vm_state_by_imapuser(user, 2)) && !(vms = get_vm_state_by_imapuser(user, 0)))) {
2968 ast_debug(3,
"User %s usage is %lu, limit is %lu\n", user, usage, limit);
2970 vms->quota_usage = usage;
2971 vms->quota_limit = limit;
2974 static char *get_header_by_tag(
char *header,
char *tag,
char *buf,
size_t len)
2976 char *start, *eol_pnt;
2982 taglen = strlen(tag) + 1;
2986 if (!(start = strstr(header, tag)))
2990 memset(buf, 0, len);
2993 if ((eol_pnt = strchr(buf,
'\r')) || (eol_pnt = strchr(buf,
'\n')))
2998 static char *get_user_by_mailbox(
char *mailbox,
char *buf,
size_t len)
3000 char *start, *
quote, *eol_pnt;
3005 if (!(start = strstr(mailbox,
"/user=")))
3010 if (!(quote = strchr(buf,
'\"'))) {
3011 if (!(eol_pnt = strchr(buf,
'/')))
3012 eol_pnt = strchr(buf,
'}');
3016 eol_pnt = strchr(buf+1,
'\"');
3026 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
3027 if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->
username, vmu->
mailbox)) {
3033 if (!(vms_p =
ast_calloc(1,
sizeof(*vms_p))))
3035 ast_copy_string(vms_p->imapuser, vmu->imapuser,
sizeof(vms_p->imapuser));
3036 ast_copy_string(vms_p->imapfolder, vmu->imapfolder,
sizeof(vms_p->imapfolder));
3039 vms_p->mailstream = NIL;
3040 vms_p->imapversion = vmu->imapversion;
3046 init_vm_state(vms_p);
3047 vmstate_insert(vms_p);
3051 static struct vm_state *get_vm_state_by_imapuser(
const char *user,
int interactive)
3053 struct vmstate *vlist = NULL;
3057 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
3058 vms = pthread_getspecific(ts_vmstate.key);
3065 ast_debug(3,
"error: vms is NULL for %s\n", user);
3068 if (vlist->vms->imapversion != imapversion) {
3071 if (!vlist->vms->imapuser) {
3072 ast_debug(3,
"error: imapuser is NULL for %s\n", user);
3076 if (!strcmp(vlist->vms->imapuser, user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
3083 ast_debug(3,
"%s not found in vmstates\n", user);
3088 static struct vm_state *get_vm_state_by_mailbox(
const char *mailbox,
const char *context,
int interactive)
3091 struct vmstate *vlist = NULL;
3092 const char *local_context =
S_OR(context,
"default");
3096 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
3097 vms = pthread_getspecific(ts_vmstate.key);
3104 ast_debug(3,
"error: vms is NULL for %s\n", mailbox);
3107 if (vlist->vms->imapversion != imapversion) {
3110 if (!vlist->vms->username || !vlist->vms->context) {
3111 ast_debug(3,
"error: username is NULL for %s\n", mailbox);
3115 ast_debug(3,
"comparing mailbox %s@%s (i=%d) to vmstate mailbox %s@%s (i=%d)\n", mailbox, local_context, interactive, vlist->vms->username, vlist->vms->context, vlist->vms->interactive);
3117 if (!strcmp(vlist->vms->username, mailbox) && !strcmp(vlist->vms->context, local_context) && vlist->vms->interactive == interactive) {
3125 ast_debug(3,
"%s not found in vmstates\n", mailbox);
3130 static void vmstate_insert(
struct vm_state *vms)
3138 if (vms->interactive == 1) {
3144 vms->vmArrayIndex = altvms->vmArrayIndex;
3149 vms->persist_vms = altvms;
3151 #ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
3152 vms->mailstream = altvms->mailstream;
3154 vms->mailstream = NIL;
3165 ast_debug(3,
"Inserting vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->
username);
3172 static void vmstate_delete(
struct vm_state *vms)
3174 struct vmstate *vc = NULL;
3179 if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
3183 altvms->updated = 1;
3184 vms->mailstream = mail_close(vms->mailstream);
3190 ast_debug(3,
"Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->
username);
3194 if (vc->vms == vms) {
3205 vc->vms->msgArray = NULL;
3206 vc->vms->msg_array_max = 0;
3214 static void set_update(MAILSTREAM * stream)
3217 char *mailbox = stream->mailbox, *
user;
3218 char buf[1024] =
"";
3220 if (!(user = get_user_by_mailbox(mailbox, buf,
sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 0))) {
3226 ast_debug(3,
"User %s mailbox set for update.\n", user);
3231 static void init_vm_state(
struct vm_state *vms)
3234 vms->msgArray =
ast_calloc(vms->msg_array_max,
sizeof(
long));
3235 if (!vms->msgArray) {
3237 vms->msg_array_max = 0;
3239 vms->vmArrayIndex = 0;
3243 static int save_body(BODY *body,
struct vm_state *vms,
char *section,
char *
format,
int is_intro)
3247 char *fn = is_intro ? vms->introfn : vms->
fn;
3249 unsigned long newlen;
3252 if (!body || body == NIL)
3256 body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->
curmsg], section, &len);
3258 if (body_content != NIL) {
3259 snprintf(filename,
sizeof(filename),
"%s.%s", fn, format);
3261 body_decoded = rfc822_base64((
unsigned char *) body_content, len, &newlen);
3266 write_file(filename, (
char *) body_decoded, newlen);
3268 ast_debug(5,
"Body of message is NULL.\n");
3281 static void get_mailbox_delimiter(MAILSTREAM *stream) {
3283 snprintf(tmp,
sizeof(tmp),
"{%s}", imapserver);
3284 mail_list(stream, tmp,
"*");
3294 static void check_quota(
struct vm_state *vms,
char *mailbox) {
3296 mail_parameters(NULL, SET_QUOTA, (
void *) mm_parsequota);
3297 ast_debug(3,
"Mailbox name set to: %s, about to check quotas\n", mailbox);
3298 if (vms && vms->mailstream != NULL) {
3299 imap_getquotaroot(vms->mailstream, mailbox);
3324 struct generic_prepare_struct {
3332 struct generic_prepare_struct *gps = data;
3336 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->
con, &stmt);
3337 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
3341 res = SQLPrepare(stmt, (
unsigned char *) gps->sql, SQL_NTS);
3342 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
3344 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
3347 for (i = 0; i < gps->argc; i++)
3348 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL);
3367 static int retrieve_file(
char *dir,
int msgnum)
3373 void *fdm = MAP_FAILED;
3374 SQLSMALLINT colcount = 0;
3381 SQLSMALLINT datatype;
3382 SQLSMALLINT decimaldigits;
3383 SQLSMALLINT nullable;
3389 char full_fn[PATH_MAX];
3391 char *argv[] = { dir, msgnums };
3392 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
3398 c = strchr(fmt,
'|');
3401 if (!strcasecmp(fmt,
"wav49"))
3403 snprintf(msgnums,
sizeof(msgnums),
"%d", msgnum);
3410 snprintf(full_fn,
sizeof(full_fn),
"%s.txt", fn);
3412 if (!(f = fopen(full_fn,
"w+"))) {
3417 snprintf(full_fn,
sizeof(full_fn),
"%s.%s", fn, fmt);
3418 snprintf(sql,
sizeof(sql),
"SELECT * FROM %s WHERE dir=? AND msgnum=?", odbc_table);
3425 res = SQLFetch(stmt);
3426 if (res == SQL_NO_DATA) {
3427 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
3430 }
else if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
3432 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
3439 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
3443 res = SQLNumResultCols(stmt, &colcount);
3444 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
3446 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
3451 fprintf(f,
"[message]\n");
3452 for (x = 0; x < colcount; x++) {
3455 collen =
sizeof(coltitle);
3456 res = SQLDescribeCol(stmt, x + 1, (
unsigned char *) coltitle,
sizeof(coltitle), &collen,
3457 &datatype, &colsize, &decimaldigits, &nullable);
3458 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
3460 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
3464 if (!strcasecmp(coltitle,
"recording")) {
3466 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
3470 lseek(fd, fdlen - 1, SEEK_SET);
3471 if (write(fd, tmp, 1) != 1) {
3477 for (offset = 0; offset < colsize2; offset +=
CHUNKSIZE) {
3478 if ((fdm = mmap(NULL,
CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
3480 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
3484 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm,
CHUNKSIZE, NULL);
3486 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
3489 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
3495 if (truncate(full_fn, fdlen) < 0) {
3500 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata,
sizeof(rowdata), NULL);
3501 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
3503 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
3507 if (strcasecmp(coltitle,
"msgnum") && strcasecmp(coltitle,
"dir") && f)
3508 fprintf(f,
"%s=%s\n", coltitle, rowdata);
3511 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
3541 char *argv[] = { dir };
3542 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
3547 snprintf(sql,
sizeof(sql),
"SELECT msgnum FROM %s WHERE dir=? order by msgnum desc", odbc_table);
3555 res = SQLFetch(stmt);
3556 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
3557 if (res == SQL_NO_DATA) {
3558 ast_log(
AST_LOG_DEBUG,
"Directory '%s' has no messages and therefore no index was retrieved.\n", dir);
3563 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
3567 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata,
sizeof(rowdata), NULL);
3568 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
3570 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
3574 if (sscanf(rowdata,
"%30d", &x) != 1)
3576 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
3594 static int message_exists(
char *dir,
int msgnum)
3602 char *argv[] = { dir, msgnums };
3603 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
3608 snprintf(msgnums,
sizeof(msgnums),
"%d", msgnum);
3609 snprintf(sql,
sizeof(sql),
"SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?", odbc_table);
3616 res = SQLFetch(stmt);
3617 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
3619 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
3623 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata,
sizeof(rowdata), NULL);
3624 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
3626 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
3630 if (sscanf(rowdata,
"%30d", &x) != 1)
3632 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
3656 char *argv[] = { dir };
3657 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
3662 snprintf(sql,
sizeof(sql),
"SELECT COUNT(*) FROM %s WHERE dir=?", odbc_table);
3669 res = SQLFetch(stmt);
3670 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
3672 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
3676 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata,
sizeof(rowdata), NULL);
3677 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
3679 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
3683 if (sscanf(rowdata,
"%30d", &x) != 1)
3685 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
3705 static void delete_file(
const char *sdir,
int smsg)
3710 char *argv[] = { NULL, msgnums };
3711 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
3718 snprintf(msgnums,
sizeof(msgnums),
"%d", smsg);
3719 snprintf(sql,
sizeof(sql),
"DELETE FROM %s WHERE dir=? AND msgnum=?", odbc_table);
3724 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
3742 static void copy_file(
char *sdir,
int smsg,
char *ddir,
int dmsg,
char *dmailboxuser,
char *dmailboxcontext)
3749 char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums };
3750 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
3755 snprintf(msgnums,
sizeof(msgnums),
"%d", smsg);
3756 snprintf(msgnumd,
sizeof(msgnumd),
"%d", dmsg);
3757 snprintf(sql,
sizeof(sql),
"INSERT INTO %s (dir, msgnum, context, macrocontext, callerid, origtime, duration, recording, flag, mailboxuser, mailboxcontext) SELECT ?,?,context,macrocontext,callerid,origtime,duration,recording,flag,?,? FROM %s WHERE dir=? AND msgnum=?", odbc_table, odbc_table);
3760 ast_log(
AST_LOG_WARNING,
"SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
3762 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
3769 struct insert_data {
3772 const char *msgnums;
3777 const char *macrocontext;
3778 const char *callerid;
3779 const char *origtime;
3780 const char *duration;
3781 const char *mailboxuser;
3782 const char *mailboxcontext;
3783 const char *category;
3787 static SQLHSTMT insert_data_cb(
struct odbc_obj *obj,
void *vdata)
3789 struct insert_data *data = vdata;
3793 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->
con, &stmt);
3794 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
3796 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
3800 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->dir), 0, (
void *) data->dir, 0, NULL);
3801 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msgnums), 0, (
void *) data->msgnums, 0, NULL);
3802 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, data->datalen, 0, (
void *) data->data, data->datalen, &data->indlen);
3803 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->context), 0, (
void *) data->context, 0, NULL);
3804 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->macrocontext), 0, (
void *) data->macrocontext, 0, NULL);
3805 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->callerid), 0, (
void *) data->callerid, 0, NULL);
3806 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->origtime), 0, (
void *) data->origtime, 0, NULL);
3807 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->duration), 0, (
void *) data->duration, 0, NULL);
3808 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxuser), 0, (
void *) data->mailboxuser, 0, NULL);
3809 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxcontext), 0, (
void *) data->mailboxcontext, 0, NULL);
3810 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->flag), 0, (
void *) data->flag, 0, NULL);
3812 SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (
void *) data->category, 0, NULL);
3814 res = SQLExecDirect(stmt, (
unsigned char *) data->sql, SQL_NTS);
3815 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
3817 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
3837 static int store_file(
const char *dir,
const char *mailboxuser,
const char *mailboxcontext,
int msgnum)
3841 void *fdm = MAP_FAILED;
3847 char full_fn[PATH_MAX];
3852 struct insert_data idata = { .sql = sql, .msgnums = msgnums, .dir = dir, .mailboxuser = mailboxuser, .mailboxcontext = mailboxcontext,
3853 .context =
"", .macrocontext =
"", .callerid =
"", .origtime =
"", .duration =
"", .category =
"", .flag =
"" };
3864 c = strchr(fmt,
'|');
3867 if (!strcasecmp(fmt,
"wav49"))
3869 snprintf(msgnums,
sizeof(msgnums),
"%d", msgnum);
3874 snprintf(full_fn,
sizeof(full_fn),
"%s.txt", fn);
3876 snprintf(full_fn,
sizeof(full_fn),
"%s.%s", fn, fmt);
3877 fd = open(full_fn, O_RDWR);
3888 idata.macrocontext =
"";
3891 idata.callerid =
"";
3894 idata.origtime =
"";
3897 idata.duration =
"";
3900 idata.category =
"";
3906 fdlen = lseek(fd, 0, SEEK_END);
3907 if (fdlen < 0 || lseek(fd, 0, SEEK_SET) < 0) {
3912 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
3913 if (fdm == MAP_FAILED) {
3919 idata.datalen = idata.indlen = fdlen;
3922 snprintf(sql,
sizeof(sql),
"INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag,category) VALUES (?,?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
3924 snprintf(sql,
sizeof(sql),
"INSERT INTO %s (dir,msgnum,recording,context,macrocontext,callerid,origtime,duration,mailboxuser,mailboxcontext,flag) VALUES (?,?,?,?,?,?,?,?,?,?,?)", odbc_table);
3927 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
3938 if (fdm != MAP_FAILED)
3958 static void rename_file(
char *sdir,
int smsg,
char *mailboxuser,
char *mailboxcontext,
char *ddir,
int dmsg)
3965 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
3966 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
3971 snprintf(msgnums,
sizeof(msgnums),
"%d", smsg);
3972 snprintf(msgnumd,
sizeof(msgnumd),
"%d", dmsg);
3973 snprintf(sql,
sizeof(sql),
"UPDATE %s SET dir=?, msgnum=?, mailboxuser=?, mailboxcontext=? WHERE dir=? AND msgnum=?", odbc_table);
3978 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
3996 static int remove_file(
char *dir,
int msgnum)
3999 char full_fn[PATH_MAX];
4003 snprintf(msgnums,
sizeof(msgnums),
"%d", msgnum);
4008 snprintf(full_fn,
sizeof(full_fn),
"%s.txt", fn);
4013 #ifndef IMAP_STORAGE
4028 struct dirent *vment = NULL;
4033 if ((vmdir = opendir(dir))) {
4034 while ((vment = readdir(vmdir))) {
4035 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7,
".txt", 4)) {
4055 char stxt[PATH_MAX];
4056 char dtxt[PATH_MAX];
4058 snprintf(stxt,
sizeof(stxt),
"%s.txt", sfn);
4059 snprintf(dtxt,
sizeof(dtxt),
"%s.txt", dfn);
4082 struct dirent *msgdirent;
4091 if (!(msgdir = opendir(dir))) {
4095 while ((msgdirent = readdir(msgdir))) {
4096 if (sscanf(msgdirent->d_name,
"msg%30d.%3s", &msgdirint, extension) == 2 && !strcmp(extension,
"txt") && msgdirint <
MAXMSGLIMIT) {
4099 ast_debug(4,
"%s map[%d] = %d, count = %d\n", dir, msgdirint, map[msgdirint], stopcount);
4104 for (x = 0; x < vmu->
maxmsg; x++) {
4107 }
else if (map[x] == 0 && !stopcount) {
4117 #ifndef IMAP_STORAGE
4128 static int copy(
char *infile,
char *outfile)
4136 #ifdef HARDLINK_WHEN_POSSIBLE
4138 if (link(infile, outfile)) {
4140 if ((ifd = open(infile, O_RDONLY)) < 0) {
4150 len = read(ifd, buf,
sizeof(buf));
4157 res = write(ofd, buf, len);
4158 if (
errno == ENOMEM ||
errno == ENOSPC || res != len) {
4169 #ifdef HARDLINK_WHEN_POSSIBLE
4188 char frompath2[PATH_MAX], topath2[PATH_MAX];
4190 const char *origmailbox = NULL, *context = NULL, *macrocontext = NULL, *
exten = NULL, *priority = NULL, *callerchan = NULL, *callerid = NULL, *origdate = NULL, *origtime = NULL, *category = NULL, *duration = NULL;
4192 snprintf(frompath2,
sizeof(frompath2),
"%s.txt", frompath);
4193 snprintf(topath2,
sizeof(topath2),
"%s.txt", topath);
4197 for (tmp = var; tmp; tmp = tmp->
next) {
4198 if (!strcasecmp(tmp->
name,
"origmailbox")) {
4199 origmailbox = tmp->
value;
4200 }
else if (!strcasecmp(tmp->
name,
"context")) {
4201 context = tmp->
value;
4202 }
else if (!strcasecmp(tmp->
name,
"macrocontext")) {
4203 macrocontext = tmp->
value;
4204 }
else if (!strcasecmp(tmp->
name,
"exten")) {
4206 }
else if (!strcasecmp(tmp->
name,
"priority")) {
4207 priority = tmp->
value;
4208 }
else if (!strcasecmp(tmp->
name,
"callerchan")) {
4209 callerchan = tmp->
value;
4210 }
else if (!strcasecmp(tmp->
name,
"callerid")) {
4211 callerid = tmp->
value;
4212 }
else if (!strcasecmp(tmp->
name,
"origdate")) {
4213 origdate = tmp->
value;
4214 }
else if (!strcasecmp(tmp->
name,
"origtime")) {
4215 origtime = tmp->
value;
4216 }
else if (!strcasecmp(tmp->
name,
"category")) {
4217 category = tmp->
value;
4218 }
else if (!strcasecmp(tmp->
name,
"duration")) {
4219 duration = tmp->
value;
4222 ast_store_realtime(
"voicemail_data",
"filename", topath,
"origmailbox", origmailbox,
"context", context,
"macrocontext", macrocontext,
"exten", exten,
"priority", priority,
"callerchan", callerchan,
"callerid", callerid,
"origdate", origdate,
"origtime", origtime,
"category", category,
"duration", duration,
SENTINEL);
4224 copy(frompath2, topath2);
4242 txtsize = (strlen(file) + 5)*
sizeof(
char);
4250 snprintf(txt, txtsize,
"%s.txt", file);
4285 if (!
inbuf(bio, fi))
4298 if (fputs(
ENDL, so) == EOF) {
4305 if (putc(((
unsigned char) c), so) == EOF) {
4325 static const unsigned char dtable[] = {
'A',
'B',
'C',
'D',
'E',
'F',
'G',
'H',
'I',
'J',
'K',
4326 'L',
'M',
'N',
'O',
'P',
'Q',
'R',
'S',
'T',
'U',
'V',
'W',
'X',
'Y',
'Z',
'a',
'b',
'c',
'd',
'e',
'f',
4327 'g',
'h',
'i',
'j',
'k',
'l',
'm',
'n',
'o',
'p',
'q',
'r',
's',
't',
'u',
'v',
'w',
'x',
'y',
'z',
'0',
4328 '1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'+',
'/'};
4333 memset(&bio, 0,
sizeof(bio));
4336 if (!(fi = fopen(filename,
"rb"))) {
4342 unsigned char igroup[3], ogroup[4];
4345 memset(igroup, 0,
sizeof(igroup));
4347 for (n = 0; n < 3; n++) {
4348 if ((c =
inchar(&bio, fi)) == EOF) {
4353 igroup[n] = (
unsigned char) c;
4357 ogroup[0]= dtable[igroup[0] >> 2];
4358 ogroup[1]= dtable[((igroup[0] & 3) << 4) | (igroup[1] >> 4)];
4359 ogroup[2]= dtable[((igroup[1] & 0xF) << 2) | (igroup[2] >> 6)];
4360 ogroup[3]= dtable[igroup[2] & 0x3F];
4369 for (i = 0; i < 4; i++)
4370 ochar(&bio, ogroup[i], so);
4376 if (fputs(
ENDL, so) == EOF) {
4383 static void prep_email_sub_vars(
struct ast_channel *ast,
struct ast_vm_user *vmu,
int msgnum,
char *context,
char *mailbox,
const char *fromfolder,
char *cidnum,
char *cidname,
char *dur,
char *date,
const char *category,
const char *flag)
4387 char fromdir[256], fromfile[256];
4389 const char *origcallerid, *origtime;
4390 char origcidname[80], origcidnum[80], origdate[80];
4397 snprintf(num,
sizeof(num),
"%d", msgnum);
4402 ast_callerid_merge(callerid,
sizeof(callerid), cidname, cidnum, NULL) :
"an unknown caller");
4411 make_file(fromfile,
sizeof(fromfile), fromdir, msgnum - 1);
4412 if (strlen(fromfile) <
sizeof(fromfile) - 5) {
4413 strcat(fromfile,
".txt");
4417 ast_log(
LOG_DEBUG,
"Config load for message text file '%s' failed\n", fromfile);
4424 ast_callerid_split(origcallerid, origcidname,
sizeof(origcidname), origcidnum,
sizeof(origcidnum));
4429 if ((origtime =
ast_variable_retrieve(msg_cfg,
"message",
"origtime")) && sscanf(origtime,
"%30d", &inttime) == 1) {
4430 struct timeval tv = { inttime, };
4453 for (ptr = from; *ptr; ptr++) {
4454 if (*ptr ==
'"' || *ptr ==
'\\') {
4471 const struct vm_zone *z = NULL;
4494 for (; *
str; str++) {
4495 if (*str > 126 || *str < 32 || strchr(
"()<>@,:;/\"[]?.=", *str)) {
4522 int first_section = 1;
4526 for (; *start; start++) {
4527 int need_encoding = 0;
4528 if (*start < 33 || *start > 126 || strchr(
"()<>@,:;/\"[]?.=_", *start)) {
4531 if ((first_section && need_encoding && preamble +
ast_str_strlen(tmp) > 70) ||
4532 (first_section && !need_encoding && preamble +
ast_str_strlen(tmp) > 72) ||
4534 (!first_section && !need_encoding &&
ast_str_strlen(tmp) > 72)) {
4540 if (need_encoding && *start ==
' ') {
4542 }
else if (need_encoding) {
4575 static void make_email_file(FILE *p,
char *srcemail,
struct ast_vm_user *vmu,
int msgnum,
char *context,
char *mailbox,
const char *fromfolder,
char *cidnum,
char *cidname,
char *attach,
char *attach2,
char *format,
int duration,
int attach_user_voicemail,
struct ast_channel *chan,
const char *category,
int imap,
const char *flag)
4583 char enc_cidnum[256] =
"", enc_cidname[256] =
"";
4585 char *greeting_attachment;
4588 if (!str1 || !str2) {
4600 gethostname(host,
sizeof(host) - 1);
4602 if (strchr(srcemail,
'@')) {
4605 snprintf(who,
sizeof(who),
"%s@%s", srcemail, host);
4608 greeting_attachment = strrchr(
ast_strdupa(attach),
'/');
4609 if (greeting_attachment) {
4610 *greeting_attachment++ =
'\0';
4613 snprintf(dur,
sizeof(dur),
"%d:%02d", duration / 60, duration % 60);
4615 fprintf(p,
"Date: %s" ENDL, date);
4624 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
4646 fprintf(p,
"From: Asterisk PBX <%s>" ENDL, who);
4669 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
4692 fprintf(p,
"Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
4694 fprintf(p,
"Subject: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
4698 fprintf(p,
"Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
4700 fprintf(p,
"Subject: [PBX]: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
4704 fprintf(p,
"Message-ID: <Asterisk-%d-%u-%s-%d@%s>" ENDL, msgnum + 1,
4705 (
unsigned int)
ast_random(), mailbox, (
int) getpid(), host);
4708 fprintf(p,
"X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
4710 fprintf(p,
"X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
4711 fprintf(p,
"X-Asterisk-VM-Context: %s" ENDL, context);
4713 fprintf(p,
"X-Asterisk-VM-Extension: %s" ENDL, (!
ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
4715 fprintf(p,
"X-Asterisk-VM-Extension: %s" ENDL, mailbox);
4718 fprintf(p,
"X-Asterisk-VM-Flag: %s" ENDL, flag);
4719 fprintf(p,
"X-Asterisk-VM-Priority: %d" ENDL, chan->
priority);
4720 fprintf(p,
"X-Asterisk-VM-Caller-channel: %s" ENDL, chan->
name);
4721 fprintf(p,
"X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
4722 fprintf(p,
"X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
4723 fprintf(p,
"X-Asterisk-VM-Duration: %d" ENDL, duration);
4725 fprintf(p,
"X-Asterisk-VM-Category: %s" ENDL, category);
4727 fprintf(p,
"X-Asterisk-VM-Category: " ENDL);
4729 fprintf(p,
"X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ?
"Message" : greeting_attachment);
4730 fprintf(p,
"X-Asterisk-VM-Orig-date: %s" ENDL, date);
4731 fprintf(p,
"X-Asterisk-VM-Orig-time: %ld" ENDL, (
long) time(NULL));
4734 fprintf(p,
"X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
4737 fprintf(p,
"X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
4739 fprintf(p,
"MIME-Version: 1.0" ENDL);
4740 if (attach_user_voicemail) {
4742 snprintf(bound,
sizeof(bound),
"----voicemail_%d%s%d%u", msgnum + 1, mailbox,
4743 (
int) getpid(), (
unsigned int)
ast_random());
4745 fprintf(p,
"Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
4746 fprintf(p,
ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
4747 fprintf(p,
"--%s" ENDL, bound);
4749 fprintf(p,
"Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
4754 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
4762 if ((next = strchr(line,
'\n'))) {
4765 fprintf(p,
"%s" ENDL, line);
4776 }
else if (msgnum > -1) {
4777 if (strcmp(vmu->
mailbox, mailbox)) {
4782 char fromdir[256], fromfile[256], origdate[80] =
"", origcallerid[80] =
"";
4786 make_file(fromfile,
sizeof(fromfile), fromdir, msgnum);
4787 if (strlen(fromfile) <
sizeof(fromfile) - 5) {
4788 strcat(fromfile,
".txt");
4797 if ((v =
ast_variable_retrieve(msg_cfg,
"message",
"origtime")) && sscanf(v,
"%30d", &inttime) == 1) {
4798 struct timeval tv = { inttime, };
4803 fprintf(p,
"Dear %s:" ENDL ENDL
"\tJust wanted to let you know you were just forwarded"
4804 " a %s long message (number %d)" ENDL
"in mailbox %s from %s, on %s" ENDL
4805 "(originally sent by %s on %s)" ENDL
"so you might want to check it when you get a"
4806 " chance. Thanks!" ENDL ENDL
"\t\t\t\t--Asterisk" ENDL ENDL, vmu->
fullname, dur,
4807 msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum :
"an unknown caller")),
4808 date, origcallerid, origdate);
4815 fprintf(p,
"Dear %s:" ENDL ENDL
"\tJust wanted to let you know you were just left a "
4816 "%s long message (number %d)" ENDL
"in mailbox %s from %s, on %s so you might" ENDL
4817 "want to check it when you get a chance. Thanks!" ENDL ENDL
"\t\t\t\t--Asterisk"
4818 ENDL ENDL, vmu->
fullname, dur, msgnum + 1, mailbox,
4819 (cidname ? cidname : (cidnum ? cidnum :
"an unknown caller")), date);
4822 fprintf(p,
"This message is to let you know that your greeting was changed on %s." ENDL
4823 "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL, date);
4826 if (imap || attach_user_voicemail) {
4828 snprintf(filename,
sizeof(filename),
"msg%04d.%s", msgnum, format);
4829 ast_debug(5,
"creating second attachment filename %s\n", filename);
4830 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 0, msgnum);
4831 snprintf(filename,
sizeof(filename),
"msgintro%04d.%s", msgnum, format);
4832 ast_debug(5,
"creating attachment filename %s\n", filename);
4833 add_email_attachment(p, vmu, format, attach2, greeting_attachment, mailbox, bound, filename, 1, msgnum);
4835 snprintf(filename,
sizeof(filename),
"msg%04d.%s", msgnum, format);
4836 ast_debug(5,
"creating attachment filename %s, no second attachment.\n", filename);
4837 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 1, msgnum);
4846 char tmpdir[256], newtmp[256];
4853 char *ctype = (!strcasecmp(format,
"ogg")) ?
"application/" :
"audio/x-";
4857 snprintf(newtmp,
sizeof(newtmp),
"%s/XXXXXX", tmpdir);
4858 tmpfd = mkstemp(newtmp);
4862 snprintf(tmpcmd,
sizeof(tmpcmd),
"sox -v %.4f %s.%s %s.%s", vmu->
volgain, attach, format, newtmp, format);
4865 ast_debug(3,
"VOLGAIN: Stored at: %s.%s - Level: %.4f - Mailbox: %s\n", attach, format, vmu->
volgain, mailbox);
4867 ast_log(
LOG_WARNING,
"Sox failed to re-encode %s.%s: %s (have you installed support for all sox file formats?)\n", attach, format,
4868 soxstatus == 1 ?
"Problem with command line options" :
"An error occurred during file processing");
4873 fprintf(p,
"--%s" ENDL, bound);
4875 fprintf(p,
"Content-Type: %s%s; name=\"%s\"" ENDL, ctype, format, filename);
4877 fprintf(p,
"Content-Type: %s%s; name=\"%s.%s\"" ENDL, ctype, format, greeting_attachment, format);
4878 fprintf(p,
"Content-Transfer-Encoding: base64" ENDL);
4879 fprintf(p,
"Content-Description: Voicemail sound attachment." ENDL);
4881 fprintf(p,
"Content-Disposition: attachment; filename=\"%s\"" ENDL ENDL, filename);
4883 fprintf(p,
"Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, format);
4884 snprintf(fname,
sizeof(fname),
"%s.%s", attach, format);
4887 fprintf(p, ENDL ENDL
"--%s--" ENDL
"." ENDL, bound);
4889 if (soxstatus == 0) {
4898 static int sendmail(
char *srcemail,
struct ast_vm_user *vmu,
int msgnum,
char *context,
char *mailbox,
const char *fromfolder,
char *cidnum,
char *cidname,
char *attach,
char *attach2,
char *format,
int duration,
int attach_user_voicemail,
struct ast_channel *chan,
const char *category,
const char *flag)
4901 char tmp[80] =
"/tmp/astmail-XXXXXX";
4915 if (!strcmp(format,
"wav49"))
4917 ast_debug(3,
"Attaching file '%s', format '%s', uservm is '%d', global is %u\n", attach, format, attach_user_voicemail,
ast_test_flag((&globalflags),
VM_ATTACH));
4924 make_email_file(p, srcemail, vmu, msgnum, context, mailbox, fromfolder, cidnum, cidname, attach, attach2, format, duration, attach_user_voicemail, chan, category, 0, flag);
4926 snprintf(tmp2,
sizeof(tmp2),
"( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
4928 ast_debug(1,
"Sent mail to %s with command '%s'\n", vmu->
email, mailcmd);
4933 static int sendpage(
char *srcemail,
char *pager,
int msgnum,
char *context,
char *mailbox,
const char *fromfolder,
char *cidnum,
char *cidname,
int duration,
struct ast_vm_user *vmu,
const char *category,
const char *flag)
4935 char enc_cidnum[256], enc_cidname[256];
4940 char tmp[80] =
"/tmp/astmail-XXXXXX";
4941 char tmp2[PATH_MAX];
4946 if (!str1 || !str2) {
4965 gethostname(host,
sizeof(host)-1);
4966 if (strchr(srcemail,
'@')) {
4969 snprintf(who,
sizeof(who),
"%s@%s", srcemail, host);
4971 snprintf(dur,
sizeof(dur),
"%d:%02d", duration / 60, duration % 60);
4973 fprintf(p,
"Date: %s\n", date);
4982 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
5004 fprintf(p,
"From: Asterisk PBX <%s>" ENDL, who);
5026 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
5049 fprintf(p,
"Subject: New VM\n\n");
5051 fprintf(p,
"Subject: New %s VM\n\n", flag);
5058 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
5066 fprintf(p,
"New %s long %s msg in box %s\n"
5067 "from %s, on %s", dur, flag, mailbox, (cidname ? cidname : (cidnum ? cidnum :
"unknown")), date);
5071 snprintf(tmp2,
sizeof(tmp2),
"( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
5073 ast_debug(1,
"Sent page to %s with command '%s'\n", pager, mailcmd);
5095 return ast_strftime(s, len,
"%a %b %e %r UTC %Y", &tm);
5102 char dest[PATH_MAX];
5104 snprintf(fn,
sizeof(fn),
"%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
5106 if ((res =
create_dirpath(dest,
sizeof(dest), context, ext,
""))) {
5138 static int inboxcount2(
const char *mailbox,
int *urgentmsgs,
int *newmsgs,
int *oldmsgs)
5142 SQLHSTMT stmt = NULL;
5145 char tmp[PATH_MAX] =
"";
5148 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
5163 if (strchr(mailbox,
' ') || strchr(mailbox,
',')) {
5165 char *next, *remaining = tmp;
5166 while ((next =
strsep(&remaining,
" ,"))) {
5167 if (
inboxcount2(next, urgentmsgs ? &u : NULL, &n, &o)) {
5183 context = strchr(tmp,
'@');
5188 context =
"default";
5193 snprintf(sql,
sizeof(sql),
"SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp,
"INBOX");
5198 res = SQLFetch(stmt);
5199 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
5203 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata,
sizeof(rowdata), NULL);
5204 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
5208 *newmsgs = atoi(rowdata);
5209 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
5213 snprintf(sql,
sizeof(sql),
"SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp,
"Old");
5218 res = SQLFetch(stmt);
5219 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
5223 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata,
sizeof(rowdata), NULL);
5224 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
5228 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
5229 *oldmsgs = atoi(rowdata);
5233 snprintf(sql,
sizeof(sql),
"SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, tmp,
"Urgent");
5238 res = SQLFetch(stmt);
5239 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
5243 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata,
sizeof(rowdata), NULL);
5244 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
5248 *urgentmsgs = atoi(rowdata);
5258 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
5275 static int messagecount(
const char *context,
const char *mailbox,
const char *folder)
5280 SQLHSTMT stmt = NULL;
5283 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
5292 if (!strcmp(folder,
"INBOX")) {
5293 snprintf(sql,
sizeof(sql),
"SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/INBOX' OR dir = '%s%s/%s/Urgent'", odbc_table, VM_SPOOL_DIR, context, mailbox, VM_SPOOL_DIR, context, mailbox);
5295 snprintf(sql,
sizeof(sql),
"SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'", odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
5302 res = SQLFetch(stmt);
5303 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
5305 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
5308 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata,
sizeof(rowdata), NULL);
5309 if ((res != SQL_SUCCESS) && (res != SQL_SUCCESS_WITH_INFO)) {
5311 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
5314 nummsgs = atoi(rowdata);
5315 SQLFreeHandle (SQL_HANDLE_STMT, stmt);
5333 static int has_voicemail(
const char *mailbox,
const char *folder)
5335 char tmp[256], *tmp2 = tmp, *box, *
context;
5337 while ((context = box =
strsep(&tmp2,
",&"))) {
5340 context =
"default";
5347 #ifndef IMAP_STORAGE
5366 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
5367 const char *frombox =
mbox(vmu, imbox);
5368 const char *userfolder;
5375 userfolder =
"Urgent";
5377 userfolder =
"INBOX";
5387 make_file(frompath,
sizeof(frompath), fromdir, msgnum);
5395 make_file(topath,
sizeof(topath), todir, recipmsgnum);
5396 #ifndef ODBC_STORAGE
5398 COPY(fromdir, msgnum, todir, recipmsgnum, recip->
mailbox, recip->
context, frompath, topath);
5405 STORE(todir, recip->
mailbox, recip->
context, recipmsgnum, chan, recip, fmt, duration, NULL, NULL);
5407 #ifndef ODBC_STORAGE
5423 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
5425 static int messagecount(
const char *context,
const char *mailbox,
const char *folder)
5430 static int __has_voicemail(
const char *context,
const char *mailbox,
const char *folder,
int shortcircuit)
5444 context =
"default";
5446 snprintf(fn,
sizeof(fn),
"%s%s/%s/%s", VM_SPOOL_DIR, context, mailbox, folder);
5448 if (!(dir = opendir(fn)))
5451 while ((de = readdir(dir))) {
5452 if (!strncasecmp(de->d_name,
"msg", 3)) {
5456 }
else if (!strncasecmp(de->d_name + 8,
"txt", 3)) {
5478 char tmp[256], *tmp2 = tmp, *box, *
context;
5483 while ((box =
strsep(&tmp2,
",&"))) {
5484 if ((context = strchr(box,
'@')))
5487 context =
"default";
5491 if (!strcmp(folder,
"INBOX") &&
__has_voicemail(context, box,
"Urgent", 1)) {
5499 static int inboxcount2(
const char *mailbox,
int *urgentmsgs,
int *newmsgs,
int *oldmsgs)
5515 if (strchr(mailbox,
',')) {
5516 int tmpnew, tmpold, tmpurgent;
5521 while ((cur =
strsep(&mb,
", "))) {
5523 if (
inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
5531 *urgentmsgs += tmpurgent;
5540 if ((context = strchr(tmp,
'@')))
5543 context =
"default";
5558 static int inboxcount(
const char *mailbox,
int *newmsgs,
int *oldmsgs)
5561 int res =
inboxcount2(mailbox, &urgentmsgs, newmsgs, oldmsgs);
5563 *newmsgs += urgentmsgs;
5570 char arguments[255];
5571 char ext_context[256] =
"";
5572 int newvoicemails = 0, oldvoicemails = 0, urgentvoicemails = 0;
5576 snprintf(ext_context,
sizeof(ext_context),
"%s@%s", extension, context);
5588 if (!strncmp(mwi_msg->
cause,
"INV", 3))
5590 else if (!strncmp(mwi_msg->
cause,
"BLK", 3))
5595 ast_debug(1,
"Successfully executed SMDI MWI change for %s\n", extension);
5600 if (
inboxcount2(ext_context, &urgentvoicemails, &newvoicemails, &oldvoicemails)) {
5601 ast_log(
AST_LOG_ERROR,
"Problem in calculating number of voicemail messages available for extension %s\n", extension);
5603 snprintf(arguments,
sizeof(arguments),
"%s %s %s %d %d %d &",
5604 externnotify,
S_OR(context,
"\"\""),
5605 extension, newvoicemails,
5606 oldvoicemails, urgentvoicemails);
5607 ast_debug(1,
"Executing %s\n", arguments);
5620 signed char record_gain;
5637 int newmsgs, oldmsgs;
5639 char urgdir[PATH_MAX];
5641 char txtfile[PATH_MAX];
5642 char tmptxtfile[PATH_MAX];
5651 int sound_duration = 0;
5659 char tmpdir[PATH_MAX];
5661 char prefile[PATH_MAX] =
"";
5662 char tempfile[PATH_MAX] =
"";
5663 char ext_context[256] =
"";
5666 char ecodes[17] =
"#";
5671 const char *category = NULL;
5673 const char *alldtmf =
"0123456789ABCD*#";
5682 if ((context = strchr(ext,
'@'))) {
5684 tmpptr = strchr(context,
'&');
5686 tmpptr = strchr(ext,
'&');
5707 if (!(vmu =
find_user(&svm, context, ext))) {
5714 if (strcmp(vmu->
context,
"default"))
5715 snprintf(ext_context,
sizeof(ext_context),
"%s@%s", ext, vmu->
context);
5725 snprintf(prefile,
sizeof(prefile),
"%s%s/%s/busy", VM_SPOOL_DIR, vmu->
context, ext);
5727 snprintf(prefile,
sizeof(prefile),
"%s%s/%s/unavail", VM_SPOOL_DIR, vmu->
context, ext);
5733 snprintf(tempfile,
sizeof(tempfile),
"%s%s/%s/temp", VM_SPOOL_DIR, vmu->
context, ext);
5745 #ifndef IMAP_STORAGE
5748 snprintf(dir,
sizeof(dir),
"%simap", VM_SPOOL_DIR);
5759 strncat(ecodes,
"0",
sizeof(ecodes) - strlen(ecodes) - 1);
5764 strncat(ecodes,
"0",
sizeof(ecodes) - strlen(ecodes) - 1);
5769 strncat(ecodes,
"0",
sizeof(ecodes) - strlen(ecodes) - 1);
5777 strncat(ecodes,
"*",
sizeof(ecodes) - strlen(ecodes) - 1);
5781 strncat(ecodes,
"*",
sizeof(ecodes) - strlen(ecodes) - 1);
5785 strncat(ecodes,
"*",
sizeof(ecodes) - strlen(ecodes) - 1);
5790 for (code = alldtmf; *code; code++) {
5793 if (strchr(ecodes, e[0]) == NULL
5797 strncat(ecodes, e,
sizeof(ecodes) - strlen(ecodes) - 1);
5807 RETRIEVE(prefile, -1, ext, context);
5812 if (success == -1) {
5814 ast_debug(1,
"Greeting not retrieved from database, but found in file storage. Inserting into database\n");
5819 ast_debug(1,
"%s doesn't exist, doing what we can\n", prefile);
5824 ast_debug(1,
"Hang up during prefile playback\n");
5839 ast_log(
LOG_DEBUG,
"Greetings only VM (maxmsg=0), Skipping voicemail recording\n");
5855 chan->
exten[0] =
'a';
5856 chan->
exten[1] =
'\0';
5872 if (ouseexten || ousemacro) {
5873 chan->
exten[0] =
'o';
5874 chan->
exten[1] =
'\0';
5914 res =
inboxcount(ext_context, &newmsgs, &oldmsgs);
5920 if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
5925 if (!(vms = create_vm_state_from_user(vmu))) {
5934 msgnum = newmsgs + oldmsgs;
5935 ast_debug(3,
"Messagecount set to %d\n", msgnum);
5936 snprintf(fn,
sizeof(fn),
"%simap/msg%s%04d", VM_SPOOL_DIR, vmu->
mailbox, msgnum);
5940 if ((res = imap_check_limits(chan, vms, vmu, msgnum))) {
5955 snprintf(tmptxtfile,
sizeof(tmptxtfile),
"%s/XXXXXX", tmpdir);
5956 txtdes = mkstemp(tmptxtfile);
5976 snprintf(priority,
sizeof(priority),
"%d", chan->
priority);
5977 snprintf(origtime,
sizeof(origtime),
"%ld", (
long) time(NULL));
5987 "exten", chan->
exten,
5988 "priority", priority,
5989 "callerchan", chan->
name,
5990 "callerid", callerid,
5992 "origtime", origtime,
5993 "category",
S_OR(category,
""),
5994 "filename", tmptxtfile,
5999 txt = fdopen(txtdes,
"w+");
6008 "; Message Information file\n"
6031 date, (
long) time(NULL),
6032 category ? category :
"");
6042 res =
play_record_review(chan, NULL, tmptxtfile, vmu->
maxsecs, fmt, 1, vmu, &duration, &sound_duration, NULL, options->
record_gain, vms, flag);
6045 fprintf(txt,
"flag=%s\n", flag);
6046 if (sound_duration < vmu->
minsecs) {
6048 ast_verb(3,
"Recording was %d seconds long but needs to be at least %d - abandoning\n", sound_duration, vmu->
minsecs);
6056 fprintf(txt,
"duration=%d\n", duration);
6065 ast_debug(1,
"The recorded media file is gone, so we should remove the .txt file too!\n");
6073 #ifndef IMAP_STORAGE
6079 #ifndef IMAP_STORAGE
6085 snprintf(txtfile,
sizeof(txtfile),
"%s.txt", fn);
6087 rename(tmptxtfile, txtfile);
6097 snprintf(tmpdur,
sizeof(tmpdur),
"%d", duration);
6112 exten =
strsep(&tmpptr,
"&");
6113 cntx = strchr(exten,
'@');
6118 if ((recip =
find_user(&recipu, cntx, exten))) {
6119 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag);
6123 #ifndef IMAP_STORAGE
6132 make_file(sfn,
sizeof(sfn), dir, msgnum);
6134 ast_debug(5,
"Created an Urgent message, moving file from %s to %s.\n", sfn, dfn);
6167 }
else if (res > 0 && res !=
't')
6170 if (sound_duration < vmu->
minsecs)
6182 ast_debug(3,
"*** Checking if we can expunge, expungeonhangup set to %d\n", expungeonhangup);
6183 if (expungeonhangup == 1) {
6185 #ifdef HAVE_IMAP_TK2006
6186 if (LEVELUIDPLUS (vms->mailstream)) {
6187 mail_expunge_full(vms->mailstream, NIL, EX_UID);
6190 mail_expunge(vms->mailstream);
6199 #if !defined(IMAP_STORAGE)
6212 for (x = 0, dest = 0; dest != stopcount && x < vmu->
maxmsg + 10; x++) {
6214 if (
EXISTS(dir, x, sfn, NULL)) {
6247 snprintf(sequence,
sizeof(sequence),
"%ld", vms->msgArray[msg]);
6249 ast_debug(3,
"Copying sequence %s to mailbox %s\n", sequence,
mbox(vmu, box));
6253 mail_setflag(vms->mailstream, sequence,
"\\Seen");
6254 mail_clearflag(vms->mailstream, sequence,
"\\Unseen");
6256 mail_setflag(vms->mailstream, sequence,
"\\Unseen");
6257 mail_clearflag(vms->mailstream, sequence,
"\\Seen");
6264 imap_mailbox_name(mailbox,
sizeof(mailbox), vms, box, 1);
6265 ast_debug(5,
"Checking if folder exists: %s\n", mailbox);
6266 if (mail_create(vms->mailstream, mailbox) == NIL)
6270 res = !mail_copy(vms->mailstream, sequence, (
char *)
mbox(vmu, box));
6279 char ddir[PATH_MAX];
6280 const char *dbox =
mbox(vmu, box);
6291 for (i = 1; i <= x; i++) {
6294 make_file(dfn,
sizeof(dfn), ddir, i - 1);
6295 if (
EXISTS(ddir, i, sfn, NULL)) {
6308 if (strcmp(sfn, dfn)) {
6309 COPY(dir, msg, ddir, x, username, context, sfn, dfn);
6326 unsigned char buf[256];
6358 bytes += ast_adsi_logo(buf);
6402 for (x = 0; x < 5; x++) {
6403 snprintf(num,
sizeof(num),
"%d", x);
6431 ast_debug(1,
"Done downloading scripts...\n");
6439 ast_debug(1,
"Restarting session...\n");
6472 unsigned char buf[256];
6474 unsigned char keys[8];
6479 for (x = 0; x < 8; x++)
6498 unsigned char buf[256];
6500 unsigned char keys[8];
6505 for (x = 0; x < 8; x++)
6520 unsigned char buf[256];
6522 unsigned char keys[8];
6528 for (x = 0; x < 5; x++) {
6550 unsigned char buf[256];
6557 char datetime[21] =
"";
6560 unsigned char keys[8];
6568 snprintf(fn2,
sizeof(fn2),
"%s.txt", vms->
fn);
6569 f = fopen(fn2,
"r");
6572 if (!fgets((
char *) buf,
sizeof(buf), f)) {
6576 char *stringp = NULL;
6577 stringp = (
char *) buf;
6579 val =
strsep(&stringp,
"=");
6581 if (!strcmp((
char *) buf,
"callerid"))
6583 if (!strcmp((
char *) buf,
"origdate"))
6591 for (x = 0; x < 5; x++)
6618 name =
"Unknown Caller";
6633 snprintf(buf1,
sizeof(buf1),
"%s%s", vms->
curbox,
6634 strcasecmp(vms->
curbox,
"INBOX") ?
" Messages" :
"");
6635 snprintf(buf2,
sizeof(buf2),
"Message %d of %d", vms->
curmsg + 1, vms->
lastmsg + 1);
6651 unsigned char buf[256];
6652 unsigned char keys[8];
6660 for (x = 0; x < 5; x++)
6702 unsigned char buf[256] =
"";
6703 char buf1[256] =
"",
buf2[256] =
"";
6705 unsigned char keys[8];
6708 char *newm = (vms->
newmessages == 1) ?
"message" :
"messages";
6709 char *oldm = (vms->
oldmessages == 1) ?
"message" :
"messages";
6713 snprintf(buf1,
sizeof(buf1),
"You have %d new", vms->
newmessages);
6715 strncat(buf1,
" and",
sizeof(buf1) - strlen(buf1) - 1);
6718 snprintf(
buf2,
sizeof(
buf2),
"%s.", newm);
6721 snprintf(buf1,
sizeof(buf1),
"You have %d old", vms->
oldmessages);
6722 snprintf(
buf2,
sizeof(
buf2),
"%s.", oldm);
6724 strcpy(buf1,
"You have no messages.");
6732 for (x = 0; x < 6; x++)
6749 unsigned char buf[256] =
"";
6750 char buf1[256] =
"",
buf2[256] =
"";
6752 unsigned char keys[8];
6755 char *mess = (vms->
lastmsg == 0) ?
"message" :
"messages";
6761 for (x = 0; x < 6; x++)
6770 snprintf(buf1,
sizeof(buf1),
"%s%s has", vms->
curbox,
6771 strcasecmp(vms->
curbox,
"INBOX") ?
" folder" :
"");
6776 strcpy(
buf2,
"no messages.");
6805 unsigned char buf[256];
6831 for (x = start; x < 5; x++) {
6837 snprintf(fn,
sizeof(fn),
"vm-%s",
mbox(NULL, x));
6846 ast_verb(1,
"failed to find %s\n", fn);
6886 while (((res <
'0') || (res >
'9')) &&
6887 (res !=
'#') && (res >= 0) &&
6919 char *context,
signed char record_gain,
long *duration,
struct vm_state *vms,
char *flag)
6922 int retries = 0, prepend_duration = 0, already_recorded = 0;
6923 char msgfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
6924 char textfile[PATH_MAX];
6927 #ifndef IMAP_STORAGE
6928 signed char zero_gain = 0;
6930 const char *duration_str;
6933 make_file(msgfile,
sizeof(msgfile), curdir, curmsg);
6934 strcpy(textfile, msgfile);
6935 strcpy(backup, msgfile);
6936 strcpy(backup_textfile, msgfile);
6937 strncat(textfile,
".txt",
sizeof(textfile) - strlen(textfile) - 1);
6938 strncat(backup,
"-bak",
sizeof(backup) - strlen(backup) - 1);
6939 strncat(backup_textfile,
"-bak.txt",
sizeof(backup_textfile) - strlen(backup_textfile) - 1);
6942 *duration = atoi(duration_str);
6947 while ((cmd >= 0) && (cmd !=
't') && (cmd !=
'*')) {
6955 make_file(vms->introfn,
sizeof(vms->introfn), curdir, curmsg);
6956 strncat(vms->introfn,
"intro",
sizeof(vms->introfn));
6959 cmd =
play_record_review(chan, NULL, vms->introfn, vmu->
maxsecs, vm_fmts, 1, vmu, (
int *) duration, NULL, NULL, record_gain, vms, flag);
6968 make_file(msgfile,
sizeof(msgfile), curdir, curmsg);
6969 strcpy(textfile, msgfile);
6970 strncat(textfile,
".txt",
sizeof(textfile) - 1);
6980 #ifndef IMAP_STORAGE
6981 if (already_recorded) {
6983 copy(backup_textfile, textfile);
6987 copy(textfile, backup_textfile);
6990 already_recorded = 1;
6995 cmd =
ast_play_and_prepend(chan, NULL, msgfile, 0, vm_fmts, &prepend_duration, NULL, 1, silencethreshold, maxsilence);
7008 *duration = atoi(duration_str);
7010 if (prepend_duration) {
7013 char duration_buf[12];
7015 *duration += prepend_duration;
7017 snprintf(duration_buf, 11,
"%ld", *duration);
7028 *vms->introfn =
'\0';
7037 already_recorded = 0;
7060 if (prepend_duration)
7061 *duration = prepend_duration;
7063 if (already_recorded && cmd == -1) {
7066 rename(backup_textfile, textfile);
7069 if (cmd ==
't' || cmd ==
'S')
7083 context =
"default";
7113 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
7114 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;
7115 const char *category;
7124 #ifndef IMAP_STORAGE
7127 snprintf(todir,
sizeof(todir),
"%simap", VM_SPOOL_DIR);
7129 make_file(fn,
sizeof(fn), todir, msgnum);
7130 snprintf(ext_context,
sizeof(ext_context),
"%s@%s", vmu->
mailbox, vmu->
context);
7150 if (attach_user_voicemail)
7154 sendmail(myserveremail, vmu, msgnum, vmu->
context, vmu->
mailbox,
mbox(vmu, 0), cidnum, cidname, fn, NULL, fmt, duration, attach_user_voicemail, chan, category, flag);
7156 if (attach_user_voicemail)
7161 sendpage(myserveremail, vmu->
pager, msgnum, vmu->
context, vmu->
mailbox,
mbox(vmu, 0), cidnum, cidname, duration, vmu, category, flag);
7165 DELETE(todir, msgnum, fn, vmu);
7179 vm_imap_delete(NULL, vms->
curmsg, vmu);
7222 char ecodes[16] =
"#";
7223 int res = 0, cmd = 0;
7228 int saved_messages = 0;
7229 int valid_extensions = 0;
7232 char urgent_str[7] =
"";
7233 int prompt_played = 0;
7234 #ifndef IMAP_STORAGE
7235 char msgfile[PATH_MAX], textfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
7238 ast_copy_string(urgent_str, urgent ?
"Urgent" :
"",
sizeof(urgent_str));
7241 if (vms == NULL)
return -1;
7246 while (!res && !valid_extensions) {
7247 int use_directory = 0;
7252 while ((cmd >= 0) && !done ){
7284 if (cmd < 0 || cmd ==
't')
7288 if (use_directory) {
7291 char old_context[
sizeof(chan->
context)];
7292 char old_exten[
sizeof(chan->
exten)];
7294 struct ast_app* directory_app;
7297 if (directory_app) {
7298 char vmcontext[256];
7301 memcpy(old_exten, chan->
exten,
sizeof(chan->
exten));
7305 snprintf(vmcontext,
sizeof(vmcontext),
"%s,,v", context ? context :
"default");
7306 res =
pbx_exec(chan, directory_app, vmcontext);
7312 memcpy(chan->
exten, old_exten,
sizeof(chan->
exten));
7322 if (res || prompt_played > 4)
7324 if ((res =
ast_readstring(chan, username,
sizeof(username) - 1, 2000, 10000,
"#") < 0))
7332 s =
strsep(&stringp,
"*");
7334 valid_extensions = 1;
7336 if ((is_new_message == 1 || strcmp(s, sender->
mailbox)) && (receiver =
find_user(NULL, context, s))) {
7341 ast_log(
LOG_ERROR,
"Problem in calculating number of voicemail messages available for extension %s\n", s);
7344 valid_extensions = 0;
7348 if ((newmsgs + oldmsgs) >= capacity) {
7349 ast_log(
LOG_NOTICE,
"Mailbox '%s' is full with capacity of %d, prompting for another extension.\n", s, capacity);
7351 valid_extensions = 0;
7372 valid_extensions = 0;
7377 snprintf(fn,
sizeof(fn),
"%s%s/%s/greet", VM_SPOOL_DIR, receiver->
context, s);
7390 s =
strsep(&stringp,
"*");
7393 if (valid_extensions)
7399 if (is_new_message == 1) {
7402 snprintf(mailbox,
sizeof(mailbox),
"%s@%s", username, context);
7405 memset(&leave_options, 0,
sizeof(leave_options));
7412 int copy_msg_result = 0;
7413 memcpy(&vmstmp, vms,
sizeof(vmstmp));
7417 cmd =
vm_forwardoptions(chan, sender, vmstmp.
curdir, curmsg, vmfmts,
S_OR(context,
"default"), record_gain, &duration, &vmstmp, urgent_str);
7421 int attach_user_voicemail;
7425 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
7427 dstvms = create_vm_state_from_user(vmtmp);
7430 init_mailstream(dstvms, 0);
7431 if (!dstvms->mailstream) {
7434 copy_msg_result =
STORE(vmstmp.
curdir, vmtmp->mailbox, vmtmp->context, dstvms->
curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str);
7441 myserveremail = vmtmp->serveremail;
7444 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox,
7448 vmstmp.
fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan,
7451 copy_msg_result =
copy_message(chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str);
7461 if (saved_messages > 0 && !copy_msg_result) {
7476 #ifndef IMAP_STORAGE
7482 make_file(msgfile,
sizeof(msgfile), dir, curmsg);
7483 strcpy(textfile, msgfile);
7484 strcpy(backup, msgfile);
7485 strcpy(backup_textfile, msgfile);
7486 strncat(textfile,
".txt",
sizeof(textfile) - strlen(textfile) - 1);
7487 strncat(backup,
"-bak",
sizeof(backup) - strlen(backup) - 1);
7488 strncat(backup_textfile,
"-bak.txt",
sizeof(backup_textfile) - strlen(backup_textfile) - 1);
7491 rename(backup_textfile, textfile);
7496 #ifndef IMAP_STORAGE
7498 make_file(msgfile,
sizeof(msgfile), dir, curmsg);
7499 strcpy(textfile, msgfile);
7500 strcpy(backup_textfile, msgfile);
7501 strncat(textfile,
".txt",
sizeof(textfile) - strlen(textfile) - 1);
7502 strncat(backup_textfile,
"-bak.txt",
sizeof(backup_textfile) - strlen(backup_textfile) - 1);
7503 rename(backup_textfile, textfile);
7513 return res ? res : cmd;
7527 return ast_control_streamfile(chan, file, listen_control_forward_key, listen_control_reverse_key, listen_control_stop_key, listen_control_pause_key, listen_control_restart_key, skipms, NULL);
7548 struct vm_zone *the_zone = NULL;
7578 if (time_now.tm_year == time_then.tm_year)
7579 snprintf(temp,
sizeof(temp),
"%d", time_now.tm_yday);
7581 snprintf(temp,
sizeof(temp),
"%d", (time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
7588 }
else if (!strncasecmp(chan->
language,
"de", 2)) {
7590 }
else if (!strncasecmp(chan->
language,
"gr", 2)) {
7592 }
else if (!strncasecmp(chan->
language,
"it", 2)) {
7594 }
else if (!strncasecmp(chan->
language,
"nl", 2)) {
7596 }
else if (!strncasecmp(chan->
language,
"no", 2)) {
7598 }
else if (!strncasecmp(chan->
language,
"pl", 2)) {
7600 }
else if (!strncasecmp(chan->
language,
"pt_BR", 5)) {
7602 }
else if (!strncasecmp(chan->
language,
"se", 2)) {
7604 }
else if (!strncasecmp(chan->
language,
"zh", 2)) {
7606 }
else if (!strncasecmp(chan->
language,
"vi", 2)) {
7623 char *callerid, *
name;
7624 char prefile[PATH_MAX] =
"";
7634 if ((cid == NULL)||(context == NULL))
7638 ast_debug(1,
"VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
7644 ast_debug(1,
"VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
7645 if ((strcmp(cidinternalcontexts[i], context) == 0))
7648 if (i != MAX_NUM_CID_CONTEXTS){
7650 snprintf(prefile,
sizeof(prefile),
"%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
7654 ast_verb(3,
"Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
7659 ast_verb(3,
"Playing envelope info: message from '%s'\n", callerid);
7662 res =
wait_file2(chan, vms,
"vm-from-extension");
7668 ast_debug(1,
"VM-CID: Numeric caller id: (%s)\n", callerid);
7671 res =
wait_file2(chan, vms,
"vm-from-phonenumber");
7676 ast_debug(1,
"VM-CID: From an unknown number\n");
7678 res =
wait_file2(chan, vms,
"vm-unknown-caller");
7689 if (duration == NULL)
7693 durations = atoi(duration);
7694 durationm = (durations / 60);
7696 ast_debug(1,
"VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
7698 if ((!res) && (durationm >= minduration)) {
7702 if (!strncasecmp(chan->
language,
"pl", 2)) {
7703 div_t num = div(durationm, 10);
7705 if (durationm == 1) {
7708 }
else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
7736 char filename[256], *cid;
7737 const char *origtime, *
context, *category, *duration, *flag;
7750 snprintf(filename,
sizeof(filename),
"%s.txt", vms->
fn);
7767 if (!strncasecmp(chan->
language,
"pl", 2)) {
7771 ten = (vms->
curmsg + 1) / 10;
7772 one = (vms->
curmsg + 1) % 10;
7775 snprintf(nextmsg,
sizeof(nextmsg),
"digits/n-%d", vms->
curmsg + 1);
7778 snprintf(nextmsg,
sizeof(nextmsg),
"digits/n-%d", ten * 10);
7782 snprintf(nextmsg,
sizeof(nextmsg),
"digits/n-%d", one);
7791 }
else if (!strncasecmp(chan->
language,
"he", 2)) {
7804 }
else if (!strncasecmp(chan->
language,
"vi", 2)) {
7817 if (!strncasecmp(chan->
language,
"se", 2)) {
7818 res =
wait_file2(chan, vms,
"vm-meddelandet");
7848 if (!strncasecmp(
"macro", context, 5))
7895 static int imap_remove_file(
char *dir,
int msgnum)
7898 char full_fn[PATH_MAX];
7899 char intro[PATH_MAX] = {0,};
7903 snprintf(intro,
sizeof(intro),
"%sintro", fn);
7907 if ((msgnum < 0 && imapgreetings) || msgnum > -1) {
7912 snprintf(full_fn,
sizeof(full_fn),
"%s.txt", fn);
7920 static int imap_delete_old_greeting (
char *dir,
struct vm_state *vms)
7922 char *file, *filename;
7932 ast_log(
AST_LOG_ERROR,
"Failed to procure file name from directory passed. You should never see this.\n");
7937 for (i = 0; i < vms->mailstream->nmsgs; i++) {
7938 mail_fetchstructure(vms->mailstream, i + 1, &body);
7940 if (body->nested.part->next && body->nested.part->next->body.parameter->value) {
7941 attachment =
ast_strdupa(body->nested.part->next->body.parameter->value);
7947 filename =
strsep(&attachment,
".");
7948 if (!strcmp(filename, file)) {
7949 sprintf(arg,
"%d", i + 1);
7950 mail_setflag(vms->mailstream, arg,
"\\DELETED");
7953 mail_expunge(vms->mailstream);
7958 #elif !defined(IMAP_STORAGE)
7961 int count_msg, last_msg;
7975 if (count_msg < 0) {
8001 if (last_msg < -1) {
8003 }
else if (vms->
lastmsg != last_msg) {
8004 ast_log(
LOG_NOTICE,
"Resequencing Mailbox: %s, expected %d but found %d message(s) in box with max threshold of %d.\n", vms->
curdir, last_msg + 1, vms->
lastmsg + 1, vmu->
maxmsg);
8015 int last_msg_idx = 0;
8017 #ifndef IMAP_STORAGE
8018 int res = 0, nummsg;
8027 #ifndef IMAP_STORAGE
8035 if (last_msg_idx != vms->
lastmsg) {
8040 for (x = 0; x < last_msg_idx + 1; x++) {
8049 if (strcmp(vms->
fn, fn2)) {
8083 for (x = vms->
curmsg + 1; x <= nummsg; x++) {
8096 for (x = last_msg_idx - 1; x >= 0; x--) {
8137 if (!strcasecmp(box,
"vm-INBOX") || !strcasecmp(box,
"vm-Old")){
8150 if (!strcasecmp(box,
"vm-INBOX") || !strcasecmp(box,
"vm-Old")) {
8151 if (!strcasecmp(box,
"vm-INBOX"))
8166 if (!strcasecmp(box,
"vm-Family") || !strcasecmp(box,
"vm-Friends") || !strcasecmp(box,
"vm-Work")){
8179 if ( !strncasecmp(chan->
language,
"it", 2) ||
8180 !strncasecmp(chan->
language,
"es", 2) ||
8181 !strncasecmp(chan->
language,
"pt", 2)) {
8184 }
else if (!strncasecmp(chan->
language,
"gr", 2)) {
8186 }
else if (!strncasecmp(chan->
language,
"he", 2)) {
8188 }
else if (!strncasecmp(chan->
language,
"pl", 2)) {
8190 }
else if (!strncasecmp(chan->
language,
"ua", 2)) {
8192 }
else if (!strncasecmp(chan->
language,
"vi", 2)) {
8525 }
else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
8552 }
else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
9103 snprintf(prefile,
sizeof(prefile),
"%s%s/%s/temp", VM_SPOOL_DIR, vmu->
context, vms->
username);
9115 }
else if (!strncasecmp(chan->
language,
"cs", 2)) {
9117 }
else if (!strncasecmp(chan->
language,
"cz", 2)) {
9118 static int deprecation_warning = 0;
9119 if (deprecation_warning++ % 10 == 0) {
9120 ast_log(
LOG_WARNING,
"cz is not a standard language code. Please switch to using cs instead.\n");
9123 }
else if (!strncasecmp(chan->
language,
"de", 2)) {
9125 }
else if (!strncasecmp(chan->
language,
"es", 2)) {
9127 }
else if (!strncasecmp(chan->
language,
"fr", 2)) {
9129 }
else if (!strncasecmp(chan->
language,
"gr", 2)) {
9131 }
else if (!strncasecmp(chan->
language,
"he", 2)) {
9133 }
else if (!strncasecmp(chan->
language,
"it", 2)) {
9135 }
else if (!strncasecmp(chan->
language,
"nl", 2)) {
9137 }
else if (!strncasecmp(chan->
language,
"no", 2)) {
9139 }
else if (!strncasecmp(chan->
language,
"pl", 2)) {
9141 }
else if (!strncasecmp(chan->
language,
"pt_BR", 5)) {
9143 }
else if (!strncasecmp(chan->
language,
"pt", 2)) {
9145 }
else if (!strncasecmp(chan->
language,
"ru", 2)) {
9147 }
else if (!strncasecmp(chan->
language,
"se", 2)) {
9149 }
else if (!strncasecmp(chan->
language,
"ua", 2)) {
9151 }
else if (!strncasecmp(chan->
language,
"vi", 2)) {
9153 }
else if (!strncasecmp(chan->
language,
"zh", 2)) {
9197 if (!res && !skipadvanced)
9220 if (!curmsg_deleted) {
9287 char newpassword[80] =
"";
9288 char newpassword2[80] =
"";
9289 char prefile[PATH_MAX] =
"";
9290 unsigned char buf[256];
9305 snprintf(prefile,
sizeof(prefile),
"%s%s/%s/greet", VM_SPOOL_DIR, vmu->
context, vms->
username);
9307 cmd =
play_record_review(chan,
"vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
9308 if (cmd < 0 || cmd ==
't' || cmd ==
'#')
9315 snprintf(prefile,
sizeof(prefile),
"%s%s/%s/unavail", VM_SPOOL_DIR, vmu->
context, vms->
username);
9317 cmd =
play_record_review(chan,
"vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
9318 if (cmd < 0 || cmd ==
't' || cmd ==
'#')
9322 snprintf(prefile,
sizeof(prefile),
"%s%s/%s/busy", VM_SPOOL_DIR, vmu->
context, vms->
username);
9324 cmd =
play_record_review(chan,
"vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
9325 if (cmd < 0 || cmd ==
't' || cmd ==
'#')
9335 newpassword[1] =
'\0';
9338 newpassword[0] =
'\0';
9339 if (cmd < 0 || cmd ==
't' || cmd ==
'#')
9341 cmd =
ast_readstring(chan, newpassword + strlen(newpassword),
sizeof(newpassword) - 1, 2000, 10000,
"#");
9342 if (cmd < 0 || cmd ==
't' || cmd ==
'#')
9349 newpassword2[1] =
'\0';
9352 newpassword2[0] =
'\0';
9353 if (cmd < 0 || cmd ==
't' || cmd ==
'#')
9355 cmd =
ast_readstring(chan, newpassword2 + strlen(newpassword2),
sizeof(newpassword2) - 1, 2000, 10000,
"#");
9356 if (cmd < 0 || cmd ==
't' || cmd ==
'#')
9358 if (!strcmp(newpassword, newpassword2))
9374 ast_debug(1,
"User %s set password to %s of length %d\n", vms->
username, newpassword, (
int) strlen(newpassword));
9385 char newpassword[80] =
"";
9386 char newpassword2[80] =
"";
9387 char prefile[PATH_MAX] =
"";
9388 unsigned char buf[256];
9400 while ((cmd >= 0) && (cmd !=
't')) {
9405 snprintf(prefile,
sizeof(prefile),
"%s%s/%s/unavail", VM_SPOOL_DIR, vmu->
context, vms->
username);
9406 cmd =
play_record_review(chan,
"vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
9409 snprintf(prefile,
sizeof(prefile),
"%s%s/%s/busy", VM_SPOOL_DIR, vmu->
context, vms->
username);
9410 cmd =
play_record_review(chan,
"vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
9413 snprintf(prefile,
sizeof(prefile),
"%s%s/%s/greet", VM_SPOOL_DIR, vmu->
context, vms->
username);
9414 cmd =
play_record_review(chan,
"vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
9424 newpassword[1] =
'\0';
9427 newpassword[0] =
'\0';
9431 if ((cmd =
ast_readstring(chan, newpassword + strlen(newpassword),
sizeof(newpassword) - 1, 2000, 10000,
"#")) < 0) {
9444 newpassword2[1] =
'\0';
9447 newpassword2[0] =
'\0';
9452 if ((cmd =
ast_readstring(chan, newpassword2 + strlen(newpassword2),
sizeof(newpassword2) - 1, 2000, 10000,
"#")) < 0) {
9456 if (strcmp(newpassword, newpassword2)) {
9472 ast_debug(1,
"User %s set password to %s of length %d\n",
9473 vms->
username, newpassword, (
int) strlen(newpassword));
9481 snprintf(prefile,
sizeof(prefile),
"%s%s/%s/temp", VM_SPOOL_DIR, vmu->
context, vms->
username);
9528 char prefile[PATH_MAX] =
"";
9529 unsigned char buf[256];
9542 snprintf(prefile,
sizeof(prefile),
"%s%s/%s/temp", VM_SPOOL_DIR, vmu->
context, vms->
username);
9543 while ((cmd >= 0) && (cmd !=
't')) {
9548 cmd =
play_record_review(chan,
"vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
9556 cmd =
play_record_review(chan,
"vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL);
9559 DELETE(prefile, -1, prefile, vmu);
9569 "vm-tempgreeting2" :
"vm-tempgreeting");
9598 if (!strcasecmp(vms->
fn,
"INBOX")) {
9626 snprintf(vms->
fn,
sizeof(vms->
fn),
"vm-%s", vms->
curbox);
9652 if (!strcasecmp(vms->
vmbox,
"vm-INBOX") ||!strcasecmp(vms->
vmbox,
"vm-Old")){
9654 snprintf(vms->
fn,
sizeof(vms->
fn),
"vm-%ss", vms->
curbox);
9663 snprintf(vms->
fn,
sizeof(vms->
fn),
"vm-%s", vms->
curbox);
9692 snprintf(vms->
fn,
sizeof(vms->
fn),
"vm-%s", vms->
curbox);
9716 snprintf(vms->
fn,
sizeof(vms->
fn),
"vm-%s", vms->
curbox);
9736 if (!strncasecmp(chan->
language,
"es", 2) ||
9737 !strncasecmp(chan->
language,
"it", 2) ||
9738 !strncasecmp(chan->
language,
"pt", 2) ||
9739 !strncasecmp(chan->
language,
"gr", 2)) {
9741 }
else if (!strncasecmp(chan->
language,
"he", 2)) {
9743 }
else if (!strncasecmp(chan->
language,
"vi", 2)) {
9745 }
else if (!strncasecmp(chan->
language,
"zh", 2)) {
9754 int skipuser,
int max_logins,
int silent)
9756 int useadsi = 0, valid = 0, logretries = 0;
9762 if (!skipuser && useadsi)
9771 while (!valid && (logretries < max_logins)) {
9773 if (!skipuser &&
ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000,
"#") < 0) {
9781 ast_verb(3,
"Username not entered\n");
9784 }
else if (mailbox[0] ==
'*') {
9786 ast_verb(4,
"Mailbox begins with '*', attempting jump to extension 'a'\n");
9791 ast_verb(4,
"Jump to extension 'a' failed; setting mailbox to NULL\n");
9799 char fullusername[80] =
"";
9801 strncat(fullusername, mailbox,
sizeof(fullusername) - 1 - strlen(fullusername));
9805 ast_debug(1,
"Before find user for mailbox %s\n", mailbox);
9806 vmu =
find_user(&vmus, context, mailbox);
9815 if (
ast_readstring(chan, password,
sizeof(password) - 1, 2000, 10000,
"#") < 0) {
9818 }
else if (password[0] ==
'*') {
9820 ast_verb(4,
"Password begins with '*', attempting jump to extension 'a'\n");
9826 ast_verb(4,
"Jump to extension 'a' failed; setting mailbox and user to NULL\n");
9835 if (passptr[0] ==
'-') passptr++;
9837 if (vmu && !strcmp(passptr, password))
9840 ast_verb(3,
"Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context :
"default");
9846 if (skipuser || logretries >= max_logins) {
9863 if (!valid && (logretries >= max_logins)) {
9868 if (vmu && !skipuser) {
9882 char prefixstr[80] =
"";
9883 char ext_context[256]=
"";
9889 char *context = NULL;
9892 signed char record_gain = 0;
9894 int play_folder = 0;
9901 memset(&vms, 0,
sizeof(vms));
9905 memset(&vmus, 0,
sizeof(vmus));
9925 if (
args.argc == 2) {
9931 if (sscanf(opts[OPT_ARG_RECORDGAIN],
"%30d", &gain) != 1) {
9932 ast_log(
AST_LOG_WARNING,
"Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
9935 record_gain = (
signed char) gain;
9945 if (isdigit(opts[OPT_ARG_PLAYFOLDER][0])) {
9946 if (sscanf(opts[OPT_ARG_PLAYFOLDER],
"%30d", &play_folder) != 1) {
9955 if (play_folder > 9 || play_folder < 0) {
9957 "Invalid value '%s' provided for folder autoplay option. Defaulting to 'INBOX'\n",
9958 opts[OPT_ARG_PLAYFOLDER]);
9964 while (*(
args.argv0)) {
9965 if (*(
args.argv0) ==
's')
9967 else if (*(
args.argv0) ==
'p')
9978 if ((context = strchr(
args.argv0,
'@')))
9995 ast_debug(1,
"After vm_authenticate\n");
10025 #ifdef IMAP_STORAGE
10026 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
10027 pthread_setspecific(ts_vmstate.key, &vms);
10029 vms.interactive = 1;
10033 vmstate_insert(&vms);
10034 init_vm_state(&vms);
10108 cmd =
vm_newuser(chan, vmu, &vms, vmfmts, record_gain);
10109 if ((cmd ==
't') || (cmd ==
'#')) {
10114 }
else if (cmd < 0) {
10121 #ifdef IMAP_STORAGE
10122 ast_debug(3,
"Checking quotas: comparing %u to %u\n", vms.quota_usage, vms.quota_limit);
10123 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
10124 ast_debug(1,
"*** QUOTA EXCEEDED!!\n");
10144 while ((cmd > -1) && (cmd !=
't') && (cmd !=
'#')) {
10163 }
else if (cmd > 0) {
10169 if (cmd != 11) in_urgent = 0;
10190 while ((cmd > -1) && (cmd !=
't') && (cmd !=
'#')) {
10206 ast_verb(3,
"Callback Requested\n");
10248 cmd =
forward_message(chan, context, &vms, vmu, vmfmts, 1, record_gain, 0);
10319 ast_debug(1,
"No more new messages, opened INBOX and got %d Urgent messages\n", vms.
lastmsg + 1);
10350 ast_debug(1,
"No more urgent messages, opened INBOX and got %d new messages\n", vms.
lastmsg + 1);
10369 if (play_folder == 0) {
10376 else if (play_folder == 1)
10380 if (play_folder == 0) {
10387 else if (play_folder == 1)
10403 if (in_urgent == 1) {
10412 ast_debug(1,
"No more urgent messages, opened INBOX and got %d new messages\n", vms.
lastmsg + 1);
10424 #ifdef IMAP_STORAGE
10431 cmd =
forward_message(chan, context, &vms, vmu, vmfmts, 0, record_gain, in_urgent);
10450 ast_debug(1,
"No more urgent messages, opened INBOX and got %d new messages\n", vms.
lastmsg + 1);
10475 }
else if (cmd > 0) {
10476 box = cmd = cmd -
'0';
10481 #ifndef IMAP_STORAGE
10493 snprintf(vms.
fn,
sizeof(vms.
fn),
"vm-%s",
mbox(vmu, box));
10526 ast_debug(1,
"No more urgent messages, opened INBOX and got %d new messages\n", vms.
lastmsg + 1);
10540 if (!strncasecmp(chan->
language,
"he", 2)) {
10553 cmd =
vm_options(chan, vmu, &vms, vmfmts, record_gain);
10563 if ((cmd ==
't') || (cmd ==
'#')) {
10590 int new = 0, old = 0, urgent = 0;
10591 snprintf(ext_context,
sizeof(ext_context),
"%s@%s", vms.
username, vmu->
context);
10598 #ifdef IMAP_STORAGE
10600 ast_debug(3,
"*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n", deleted, expungeonhangup);
10601 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL) {
10603 #ifdef HAVE_IMAP_TK2006
10604 if (LEVELUIDPLUS (vms.mailstream)) {
10605 mail_expunge_full(vms.mailstream, NIL, EX_UID);
10608 mail_expunge(vms.mailstream);
10614 vmstate_delete(&vms);
10620 #ifdef IMAP_STORAGE
10621 pthread_setspecific(ts_vmstate.key, NULL);
10638 memset(&leave_options, 0,
sizeof(leave_options));
10646 if (
args.argc == 2) {
10654 ast_log(
AST_LOG_WARNING,
"Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
10662 leave_options.
exitcontext = opts[OPT_ARG_DTMFEXIT];
10667 res =
ast_app_getdata(chan,
"vm-whichbox", temp,
sizeof(temp) - 1, 0);
10699 ast_log(
LOG_WARNING,
"Mailbox %s in context %s begins with '*' character. The '*' character,"
10700 "\n\twhen it is the first character in a mailbox or password, is used to jump to a"
10701 "\n\tpredefined extension 'a'. A mailbox or password beginning with '*' is not valid"
10702 "\n\tand will be ignored.\n", box, context);
10708 if (strcasecmp(vmu->
context, context)) {
10709 ast_log(
LOG_WARNING,
"\nIt has been detected that you have defined mailbox '%s' in separate\
10710 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
10711 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
10712 \n\tamend your voicemail.conf file to avoid this situation.\n", box);
10717 if (!strcasecmp(context, vmu->
context) && !strcasecmp(box, vmu->
mailbox)) {
10718 ast_log(
LOG_WARNING,
"Ignoring duplicated mailbox %s in context %s\n", box, context);
10741 char *mailbox_full;
10742 int new = 0, old = 0, urgent = 0;
10743 char secretfn[PATH_MAX] =
"";
10753 if ((s =
strsep(&stringp,
","))) {
10756 "\n\tmust be reset in voicemail.conf.\n", box);
10761 if (stringp && (s =
strsep(&stringp,
","))) {
10764 if (stringp && (s =
strsep(&stringp,
","))) {
10767 if (stringp && (s =
strsep(&stringp,
","))) {
10770 if (stringp && (s =
strsep(&stringp,
","))) {
10776 snprintf(secretfn,
sizeof(secretfn),
"%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->
context, vmu->
mailbox);
10780 mailbox_full =
ast_alloca(strlen(box) + strlen(context) + 1);
10781 strcpy(mailbox_full, box);
10782 strcat(mailbox_full,
"@");
10783 strcat(mailbox_full, context);
10796 static const char options_string[] =
"attach=yes|attachfmt=wav49|"
10797 "serveremail=someguy@digium.com|tz=central|delete=yes|saycid=yes|"
10798 "sendvoicemail=yes|review=yes|tempgreetwarn=yes|messagewrap=yes|operator=yes|"
10799 "envelope=yes|moveheard=yes|sayduration=yes|saydurationm=5|forcename=yes|"
10800 "forcegreetings=yes|callback=somecontext|dialout=somecontext2|"
10801 "exitcontext=somecontext3|minsecs=10|maxsecs=100|nextaftercmd=yes|"
10802 "backupdeleted=50|volgain=1.3|passwordlocation=spooldir|emailbody="
10803 "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message|emailsubject="
10804 "[PBX]: New message \\\\${VM_MSGNUM}\\\\ in mailbox ${VM_MAILBOX}";
10805 #ifdef IMAP_STORAGE
10806 static const char option_string2[] =
"imapuser=imapuser|imappassword=imappasswd|"
10807 "imapfolder=INBOX|imapvmshareid=6000";
10812 info->name =
"vmuser";
10813 info->category =
"/apps/app_voicemail/";
10814 info->summary =
"Vmuser unit test";
10815 info->description =
10816 "This tests passing all supported parameters to apply_options, the voicemail user config parser";
10834 if (strcasecmp(vmu->
attachfmt,
"wav49")) {
10838 if (strcasecmp(vmu->
serveremail,
"someguy@digium.com")) {
10842 if (!vmu->
emailsubject || strcasecmp(vmu->
emailsubject,
"[PBX]: New message \\${VM_MSGNUM}\\ in mailbox ${VM_MAILBOX}")) {
10846 if (!vmu->
emailbody || strcasecmp(vmu->
emailbody,
"Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message")) {
10850 if (strcasecmp(vmu->
zonetag,
"central")) {
10906 if (strcasecmp(vmu->
callback,
"somecontext")) {
10910 if (strcasecmp(vmu->
dialout,
"somecontext2")) {
10914 if (strcasecmp(vmu->
exit,
"somecontext3")) {
10942 #ifdef IMAP_STORAGE
10945 if (strcasecmp(vmu->imapuser,
"imapuser")) {
10949 if (strcasecmp(vmu->imappassword,
"imappasswd")) {
10953 if (strcasecmp(vmu->imapfolder,
"INBOX")) {
10957 if (strcasecmp(vmu->imapvmshareid,
"6000")) {
10975 static int dep_warning = 0;
10982 if (!dep_warning) {
10984 ast_log(
AST_LOG_WARNING,
"MailboxExists is deprecated. Please use ${MAILBOX_EXISTS(%s)} instead.\n", (
char *) data);
10991 if (
args.options) {
10994 if ((context = strchr(
args.mbox,
'@'))) {
11018 ast_log(
LOG_ERROR,
"MAILBOX_EXISTS requires an argument (<mailbox>[@<context>])\n");
11027 .
name =
"MAILBOX_EXISTS",
11035 char *options = NULL;
11036 int silent = 0, skipuser = 0;
11042 options =
strsep(&s,
",");
11046 context =
strsep(&s,
"");
11054 silent = (strchr(options,
's')) != NULL;
11057 if (!
vm_authenticate(chan, mailbox,
sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
11062 }
else if (mailbox[0] ==
'*') {
11075 const char *cat = NULL;
11084 "=============================================================\n"
11085 "=== Configured Voicemail Users ==============================\n"
11086 "=============================================================\n"
11092 "=== Mailbox ...\n"
11098 "=== ---------------------------------------------------------\n"
11103 "=============================================================\n"
11116 const char *context =
"";
11122 return (state == 0) ?
ast_strdup(
"for") : NULL;
11123 wordlen = strlen(word);
11125 if (!strncasecmp(word, vmu->
context, wordlen)) {
11126 if (context && strcmp(context, vmu->
context) && ++which > state)
11139 #define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
11140 const char *context = NULL;
11141 int users_counter = 0;
11145 e->
command =
"voicemail show users";
11147 "Usage: voicemail show users [for <context>]\n"
11148 " Lists all mailboxes currently set up\n";
11156 if (a->
argc == 5) {
11157 if (strcmp(a->
argv[3],
"for"))
11159 context = a->
argv[4];
11164 ast_cli(a->
fd,
"You must specify a specific context to show users from realtime!\n");
11172 ast_cli(a->
fd,
"There are no voicemail users currently defined\n");
11181 if (!strcmp(context, vmu->
context)) {
11189 ast_cli(a->
fd,
"No such voicemail context \"%s\"\n", context);
11195 int newmsgs = 0, oldmsgs = 0;
11196 char count[12], tmp[256] =
"";
11198 if (!context || !strcmp(context, vmu->
context)) {
11201 snprintf(count,
sizeof(count),
"%d", newmsgs);
11207 ast_cli(a->
fd,
"%d voicemail users configured.\n", users_counter);
11214 struct vm_zone *zone;
11215 #define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
11220 e->
command =
"voicemail show zones";
11222 "Usage: voicemail show zones\n"
11223 " Lists zone message formats\n";
11239 ast_cli(a->
fd,
"There are no voicemail zones currently defined\n");
11252 e->
command =
"voicemail reload";
11254 "Usage: voicemail reload\n"
11255 " Reload voicemail configuration\n";
11264 ast_cli(a->
fd,
"Reloading voicemail configuration...\n");
11276 #ifdef IMAP_STORAGE
11277 #define DATA_EXPORT_VM_USERS(USER) \
11278 USER(ast_vm_user, context, AST_DATA_STRING) \
11279 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11280 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11281 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11282 USER(ast_vm_user, email, AST_DATA_STRING) \
11283 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11284 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11285 USER(ast_vm_user, pager, AST_DATA_STRING) \
11286 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11287 USER(ast_vm_user, language, AST_DATA_STRING) \
11288 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11289 USER(ast_vm_user, callback, AST_DATA_STRING) \
11290 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11291 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11292 USER(ast_vm_user, exit, AST_DATA_STRING) \
11293 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11294 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11295 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11296 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11297 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11298 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11299 USER(ast_vm_user, imapuser, AST_DATA_STRING) \
11300 USER(ast_vm_user, imappassword, AST_DATA_STRING) \
11301 USER(ast_vm_user, imapvmshareid, AST_DATA_STRING) \
11302 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11304 #define DATA_EXPORT_VM_USERS(USER) \
11305 USER(ast_vm_user, context, AST_DATA_STRING) \
11306 USER(ast_vm_user, mailbox, AST_DATA_STRING) \
11307 USER(ast_vm_user, password, AST_DATA_PASSWORD) \
11308 USER(ast_vm_user, fullname, AST_DATA_STRING) \
11309 USER(ast_vm_user, email, AST_DATA_STRING) \
11310 USER(ast_vm_user, emailsubject, AST_DATA_STRING) \
11311 USER(ast_vm_user, emailbody, AST_DATA_STRING) \
11312 USER(ast_vm_user, pager, AST_DATA_STRING) \
11313 USER(ast_vm_user, serveremail, AST_DATA_STRING) \
11314 USER(ast_vm_user, language, AST_DATA_STRING) \
11315 USER(ast_vm_user, zonetag, AST_DATA_STRING) \
11316 USER(ast_vm_user, callback, AST_DATA_STRING) \
11317 USER(ast_vm_user, dialout, AST_DATA_STRING) \
11318 USER(ast_vm_user, uniqueid, AST_DATA_STRING) \
11319 USER(ast_vm_user, exit, AST_DATA_STRING) \
11320 USER(ast_vm_user, attachfmt, AST_DATA_STRING) \
11321 USER(ast_vm_user, flags, AST_DATA_UNSIGNED_INTEGER) \
11322 USER(ast_vm_user, saydurationm, AST_DATA_INTEGER) \
11323 USER(ast_vm_user, maxmsg, AST_DATA_INTEGER) \
11324 USER(ast_vm_user, maxdeletedmsg, AST_DATA_INTEGER) \
11325 USER(ast_vm_user, maxsecs, AST_DATA_INTEGER) \
11326 USER(ast_vm_user, volgain, AST_DATA_DOUBLE)
11331 #define DATA_EXPORT_VM_ZONES(ZONE) \
11332 ZONE(vm_zone, name, AST_DATA_STRING) \
11333 ZONE(vm_zone, timezone, AST_DATA_STRING) \
11334 ZONE(vm_zone, msg_format, AST_DATA_STRING)
11348 struct ast_data *data_user, *data_zone;
11350 struct vm_zone *zone = NULL;
11351 int urgentmsg = 0, newmsg = 0, oldmsg = 0;
11352 char ext_context[256] =
"";
11374 snprintf(ext_context,
sizeof(ext_context),
"%s@%s", user->
mailbox, user->
context);
11375 inboxcount2(ext_context, &urgentmsg, &newmsg, &oldmsg);
11412 AST_DATA_ENTRY(
"asterisk/application/voicemail/list", &vm_users_data_provider)
11417 int new = 0, old = 0, urgent = 0;
11419 inboxcount2(mwi_sub->mailbox, &urgent, &
new, &old);
11421 if (urgent != mwi_sub->old_urgent ||
new != mwi_sub->old_new || old != mwi_sub->old_old) {
11422 mwi_sub->old_urgent = urgent;
11423 mwi_sub->old_new =
new;
11424 mwi_sub->old_old = old;
11445 while (poll_thread_run) {
11446 struct timespec ts = { 0, };
11447 struct timeval wait;
11450 ts.tv_sec = wait.tv_sec;
11451 ts.tv_nsec = wait.tv_usec * 1000;
11457 if (!poll_thread_run)
11474 uint32_t *uniqueid = datap;
11478 if (mwi_sub->uniqueid == *uniqueid) {
11499 len =
sizeof(*mwi_sub);
11504 len += strlen(p->
context) + 1;
11511 strcpy(mwi_sub->mailbox, p->
mailbox);
11514 strcat(mwi_sub->mailbox,
"@");
11515 strcat(mwi_sub->mailbox, p->
context);
11564 if ((mwist =
ast_calloc(1, (
sizeof(*mwist)))) == NULL) {
11591 poll_thread_run = 1;
11600 poll_thread_run = 0;
11604 mwi_sub_sub = NULL;
11607 if (mwi_unsub_sub) {
11609 mwi_unsub_sub = NULL;
11616 pthread_join(poll_thread, NULL);
11626 char actionid[128] =
"";
11629 snprintf(actionid,
sizeof(actionid),
"ActionID: %s\r\n",
id);
11634 astman_send_ack(s, m,
"There are no voicemail users currently defined.");
11644 #ifdef IMAP_STORAGE
11652 "Event: VoicemailUserEntry\r\n"
11653 "VMContext: %s\r\n"
11654 "VoiceMailbox: %s\r\n"
11658 "ServerEmail: %s\r\n"
11659 "MailCommand: %s\r\n"
11665 "ExitContext: %s\r\n"
11666 "SayDurationMinimum: %d\r\n"
11667 "SayEnvelope: %s\r\n"
11669 "AttachMessage: %s\r\n"
11670 "AttachmentFormat: %s\r\n"
11671 "DeleteMessage: %s\r\n"
11672 "VolumeGain: %.2f\r\n"
11673 "CanReview: %s\r\n"
11674 "CallOperator: %s\r\n"
11675 "MaxMessageCount: %d\r\n"
11676 "MaxMessageLength: %d\r\n"
11677 "NewMessageCount: %d\r\n"
11678 #ifdef IMAP_STORAGE
11679 "OldMessageCount: %d\r\n"
11708 #ifdef IMAP_STORAGE
11709 new, old, vmu->imapuser
11715 astman_append(s,
"Event: VoicemailUserEntryComplete\r\n%s\r\n", actionid);
11737 struct vm_zone *zcur;
11754 for (current = (
char *) value; *current; current++) {
11755 if (*current ==
'\\') {
11761 switch (*current) {
11769 #ifdef IMAP_STORAGE
11770 if (!str->used || str->str[str->used - 1] !=
'\r') {
11804 ast_log(
LOG_ERROR,
"Config file users.conf is in an invalid format. Avoiding.\n");
11819 ast_log(
LOG_ERROR,
"Config file users.conf is in an invalid format. Avoiding.\n");
11832 #ifdef TEST_FRAMEWORK
11847 char *q, *stringp, *tmp;
11849 unsigned int tmpadsi[4];
11850 char secretfn[PATH_MAX] =
"";
11852 #ifdef IMAP_STORAGE
11870 memset(ext_pass_cmd, 0,
sizeof(ext_pass_cmd));
11871 memset(ext_pass_check_cmd, 0,
sizeof(ext_pass_check_cmd));
11890 sscanf(val,
"%30lf", &volgain);
11892 #ifdef ODBC_STORAGE
11893 strcpy(odbc_database,
"asterisk");
11897 strcpy(odbc_table,
"voicemessages");
11909 maxsilence = atoi(val);
11910 if (maxsilence > 0)
11911 maxsilence *= 1000;
11917 maxmsg = atoi(val);
11930 if (sscanf(val,
"%30d", &x) == 1)
11937 if (maxdeletedmsg < 0) {
11967 ast_copy_string(ext_pass_check_cmd, val,
sizeof(ext_pass_check_cmd));
11971 #ifdef IMAP_STORAGE
11999 expungeonhangup = 0;
12001 expungeonhangup = 1;
12003 expungeonhangup = 1;
12033 mail_parameters(NIL, SET_READTIMEOUT, (
void *) (atol(val)));
12035 mail_parameters(NIL, SET_READTIMEOUT, (
void *) 60L);
12039 mail_parameters(NIL, SET_WRITETIMEOUT, (
void *) (atol(val)));
12041 mail_parameters(NIL, SET_WRITETIMEOUT, (
void *) 60L);
12045 mail_parameters(NIL, SET_OPENTIMEOUT, (
void *) (atol(val)));
12047 mail_parameters(NIL, SET_OPENTIMEOUT, (
void *) 60L);
12051 mail_parameters(NIL, SET_CLOSETIMEOUT, (
void *) (atol(val)));
12053 mail_parameters(NIL, SET_CLOSETIMEOUT, (
void *) 60L);
12062 ast_debug(1,
"found externnotify: %s\n", externnotify);
12064 externnotify[0] =
'\0';
12069 ast_debug(1,
"Enabled SMDI voicemail notification\n");
12073 ast_debug(1,
"No SMDI interface set, trying default (/dev/ttyS0)\n");
12077 ast_log(
AST_LOG_ERROR,
"No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
12084 silencethreshold = atoi(val);
12092 if (sscanf(val,
"%30d", &x) == 1) {
12098 static int maxmessage_deprecate = 0;
12099 if (maxmessage_deprecate == 0) {
12100 maxmessage_deprecate = 1;
12103 if (sscanf(val,
"%30d", &x) == 1) {
12112 if (sscanf(val,
"%30d", &x) == 1) {
12114 if (maxsilence / 1000 >= vmminsecs) {
12121 static int maxmessage_deprecate = 0;
12122 if (maxmessage_deprecate == 0) {
12123 maxmessage_deprecate = 1;
12126 if (sscanf(val,
"%30d", &x) == 1) {
12128 if (maxsilence / 1000 >= vmminsecs) {
12143 ast_log(
LOG_ERROR,
"Error processing format string, defaulting to format 'wav'\n");
12151 if (sscanf(val,
"%30d", &x) == 1) {
12159 if (sscanf(val,
"%30d", &x) == 1) {
12168 if (sscanf(val,
"%30d", &x) == 1) {
12177 if (sscanf(val,
"%30d", &x) == 1) {
12195 ast_debug(1,
"VM_CID Internal context string: %s\n", val);
12199 q =
strsep(&stringp,
",");
12200 while ((*q ==
' ')||(*q ==
'\t'))
12202 ast_copy_string(cidinternalcontexts[x], q,
sizeof(cidinternalcontexts[x]));
12203 ast_debug(1,
"VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
12205 cidinternalcontexts[x][0] =
'\0';
12210 ast_debug(1,
"VM Review Option disabled globally\n");
12217 ast_debug(1,
"VM Temporary Greeting Reminder Option disabled globally\n");
12220 ast_debug(1,
"VM Temporary Greeting Reminder Option enabled globally\n");
12224 ast_debug(1,
"VM next message wrap disabled globally\n");
12230 ast_debug(1,
"VM Operator break disabled globally\n");
12236 ast_debug(1,
"VM CID Info before msg disabled globally\n");
12242 ast_debug(1,
"Send Voicemail msg disabled globally\n");
12248 ast_debug(1,
"ENVELOPE before msg enabled globally\n");
12254 ast_debug(1,
"Move Heard enabled globally\n");
12260 ast_debug(1,
"Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
12266 ast_debug(1,
"Duration info before msg enabled globally\n");
12271 saydurationminfo = 2;
12273 if (sscanf(val,
"%30d", &x) == 1) {
12274 saydurationminfo = x;
12281 ast_debug(1,
"We are not going to skip to the next msg after save/delete\n");
12288 ast_debug(1,
"found dialout context: %s\n", dialcontext);
12290 dialcontext[0] =
'\0';
12295 ast_debug(1,
"found callback context: %s\n", callcontext);
12297 callcontext[0] =
'\0';
12302 ast_debug(1,
"found operator context: %s\n", exitcontext);
12304 exitcontext[0] =
'\0';
12313 ast_copy_string(vm_invalid_password, val,
sizeof(vm_invalid_password));
12317 ast_copy_string(vm_reenterpassword, val,
sizeof(vm_reenterpassword));
12324 ast_copy_string(vm_prepend_timeout, val,
sizeof(vm_prepend_timeout));
12328 ast_copy_string(listen_control_forward_key, val,
sizeof(listen_control_forward_key));
12330 ast_copy_string(listen_control_reverse_key, val,
sizeof(listen_control_reverse_key));
12332 ast_copy_string(listen_control_pause_key, val,
sizeof(listen_control_pause_key));
12334 ast_copy_string(listen_control_restart_key, val,
sizeof(listen_control_restart_key));
12336 ast_copy_string(listen_control_stop_key, val,
sizeof(listen_control_stop_key));
12343 val =
"voicemail.conf";
12345 if (!(strcmp(val,
"spooldir"))) {
12353 if (sscanf(val,
"%30u", &poll_freq) != 1) {
12359 poll_mailboxes = 0;
12363 memset(fromstring, 0,
sizeof(fromstring));
12364 memset(pagerfromstring, 0,
sizeof(pagerfromstring));
12365 strcpy(charset,
"ISO-8859-1");
12370 if (emailsubject) {
12372 emailsubject = NULL;
12378 if (pagersubject) {
12380 pagersubject = NULL;
12391 sscanf(val,
"%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12392 for (x = 0; x < 4; x++) {
12393 memcpy(&adsifdn[x], &tmpadsi[x], 1);
12397 sscanf(val,
"%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
12398 for (x = 0; x < 4; x++) {
12399 memcpy(&adsisec[x], &tmpadsi[x], 1);
12404 adsiver = atoi(val);
12429 if (!strcasecmp(cat,
"general")) {
12444 snprintf(secretfn,
sizeof(secretfn),
"%s%s/%s/secret.conf", VM_SPOOL_DIR, current->
context, current->
mailbox);
12454 if (strcasecmp(cat,
"general")) {
12456 if (strcasecmp(cat,
"zonemessages")) {
12469 tzone =
strsep(&msg_format,
"|,");
12510 char dir[PATH_MAX];
12511 snprintf(dir,
sizeof(dir),
"%s%s/%s/greet", VM_SPOOL_DIR, context, mailbox);
12512 ast_debug(2,
"About to try retrieving name file %s\n", dir);
12513 RETRIEVE(dir, -1, mailbox, context);
12535 ast_log(
LOG_NOTICE,
"Failed reading voicemail password from %s, using secret from config file\n", secretfn);
12583 if ((context = strchr(args_copy,
'@'))) {
12586 context =
"default";
12589 if ((res =
sayname(chan, args_copy, context) < 0)) {
12590 ast_debug(3,
"Greeting not found for '%s@%s', falling back to mailbox number.\n", args_copy, context);
12600 #ifdef TEST_FRAMEWORK
12613 char dir[PATH_MAX];
12614 char dir2[PATH_MAX];
12615 static const char TEST_CONTEXT[] =
"very_long_unique_context_so_that_nobody_will_ever_have_the_same_one_configured_3141592653";
12616 static const char TEST_EXTENSION[] =
"1234";
12622 .
write = fake_write,
12628 info->name =
"vmsayname_exec";
12629 info->category =
"/apps/app_voicemail/";
12630 info->summary =
"Vmsayname unit test";
12631 info->description =
12632 "This tests passing various parameters to vmsayname";
12639 NULL, NULL, 0, 0,
"TestChannel1"))) {
12640 goto exit_vmsayname_test;
12649 test_channel1->
tech = &fake_tech;
12652 snprintf(dir,
sizeof(dir),
"%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12654 snprintf(dir,
sizeof(dir),
"%s%s/%s/greet", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12656 ast_test_status_update(test,
"This should not happen, most likely means clean up from previous test failed\n");
12658 goto exit_vmsayname_test;
12661 if ((res =
create_dirpath(dir,
sizeof(dir), TEST_CONTEXT, TEST_EXTENSION,
""))) {
12663 goto exit_vmsayname_test;
12666 snprintf(dir2,
sizeof(dir2),
"%s%s/%s/greet.gsm", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12668 if ((res = symlink(dir, dir2))) {
12670 goto exit_vmsayname_test;
12673 snprintf(dir,
sizeof(dir),
"%s@%s", TEST_EXTENSION, TEST_CONTEXT);
12678 snprintf(dir2,
sizeof(dir2),
"%s%s/%s", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
12680 snprintf(dir2,
sizeof(dir2),
"%s%s", VM_SPOOL_DIR, TEST_CONTEXT);
12685 exit_vmsayname_test:
12687 if (test_channel1) {
12700 #ifdef IMAP_STORAGE
12709 const char origweasels[] =
"tt-weasels";
12710 const char testcontext[] =
"test";
12711 const char testmailbox[] =
"00000000";
12712 const char testspec[] =
"00000000@test";
12714 int new, old, urgent;
12715 const char *folders[3] = {
"Old",
"Urgent",
"INBOX" };
12716 const int folder2mbox[3] = { 1, 11, 0 };
12717 const int expected_results[3][12] = {
12719 { 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 },
12720 { 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
12721 { 1, 1, 1, 1, 0, 2, 1, 1, 1, 1, 1, 2 },
12726 info->name =
"test_voicemail_msgcount";
12727 info->category =
"/apps/app_voicemail/";
12728 info->summary =
"Test Voicemail status checks";
12729 info->description =
12730 "Verify that message counts are correct when retrieved through the public API";
12737 snprintf(syscmd,
sizeof(syscmd),
"rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12740 syserr > 0 ? strerror(syserr) :
"unable to fork()");
12744 #ifdef IMAP_STORAGE
12751 if (!(vmu =
find_user(&svm, testcontext, testmailbox)) &&
12755 #ifdef IMAP_STORAGE
12762 memset(&vms, 0,
sizeof(vms));
12765 for (i = 0; i < 3; i++) {
12766 create_dirpath(tmp[i].dir,
sizeof(tmp[i].dir), testcontext, testmailbox, folders[i]);
12767 make_file(tmp[i].file,
sizeof(tmp[i].file), tmp[i].dir, 0);
12768 snprintf(tmp[i].txtfile,
sizeof(tmp[i].txtfile),
"%s.txt", tmp[i].file);
12771 snprintf(syscmd,
sizeof(syscmd),
"cp \"%s/sounds/en/%s.gsm\" \"%s/%s/%s/%s/msg0000.gsm\"",
ast_config_AST_DATA_DIR, origweasels,
12772 VM_SPOOL_DIR, testcontext, testmailbox, folders[i]);
12775 syserr > 0 ? strerror(syserr) :
"unable to fork()");
12777 #ifdef IMAP_STORAGE
12784 if ((txt = fopen(tmp[i].txtfile,
"w+"))) {
12785 fprintf(txt,
"; just a stub\n[message]\nflag=%s\n", strcmp(folders[i],
"Urgent") ?
"" :
"Urgent");
12793 STORE(tmp[i].dir, testmailbox, testcontext, 0, chan, vmu,
"gsm", 600, &vms, strcmp(folders[i],
"Urgent") ?
"" :
"Urgent");
12796 for (j = 0; j < 3; j++) {
12805 new = old = urgent = 0;
12809 }
else if (old != expected_results[i][3 + 0] ||
new != expected_results[i][3 + 2]) {
12811 testspec, old, expected_results[i][3 + 0],
new, expected_results[i][3 + 2]);
12815 new = old = urgent = 0;
12819 }
else if (old != expected_results[i][6 + 0] ||
12820 urgent != expected_results[i][6 + 1] ||
12821 new != expected_results[i][6 + 2] ) {
12822 ast_test_status_update(test,
"inboxcount2(%s) returned old=%d (expected %d), urgent=%d (expected %d), and new=%d (expected %d)\n",
12823 testspec, old, expected_results[i][6 + 0], urgent, expected_results[i][6 + 1],
new, expected_results[i][6 + 2]);
12827 new = old = urgent = 0;
12828 for (j = 0; j < 3; j++) {
12829 if (
ast_app_messagecount(testcontext, testmailbox, folders[j]) != expected_results[i][9 + j]) {
12831 testspec, folders[j],
ast_app_messagecount(testcontext, testmailbox, folders[j]), expected_results[i][9 + j]);
12837 for (i = 0; i < 3; i++) {
12841 DELETE(tmp[i].dir, 0, tmp[i].file, vmu);
12852 #ifdef IMAP_STORAGE
12857 snprintf(syscmd,
sizeof(syscmd),
"rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
12860 syserr > 0 ? strerror(syserr) :
"unable to fork()");
12869 char testcontext[] =
"test";
12870 char testmailbox[] =
"00000000";
12871 char from[] =
"test@example.net", cidnum[] =
"1234", cidname[] =
"Mark Spencer", format[] =
"gsm";
12872 char attach[256], attach2[256];
12873 char buf[256] =
"";
12881 enum { INT, FLAGVAL, STATIC, STRPTR }
type;
12888 {
"plain jane config", STATIC, vmus.
password, .u.strval =
"1234" },
12889 {
"emailsubject", STRPTR, vmus.
emailsubject, .u.strval =
"Oogly boogly\xf8koogly with what appears to be UTF-8" },
12890 {
"emailbody", STRPTR, vmus.
emailbody, .u.strval =
"This is a test\n\twith multiple\nlines\nwithin\n" },
12891 {
"serveremail", STATIC, vmus.
serveremail, .u.strval =
"\"\xf8Something\xe8that\xd8seems to have UTF-8 chars\" <test@example.net>" },
12892 {
"attachment flag", FLAGVAL, &vmus.
flags, .u.intval =
VM_ATTACH },
12893 {
"attach2", STRPTR, attach2, .u.strval =
"" },
12894 {
"attach", STRPTR, attach, .u.strval =
"" },
12900 info->name =
"test_voicemail_notify_endl";
12901 info->category =
"/apps/app_voicemail/";
12902 info->summary =
"Test Voicemail notification end-of-line";
12903 info->description =
12904 "Verify that notification emails use a consistent end-of-line character";
12913 if (!(vmu =
find_user(&vmus, testcontext, testmailbox)) &&
12919 if (vmu != &vmus && !(vmu =
find_user(&vmus, testcontext, testmailbox))) {
12926 #ifdef IMAP_STORAGE
12931 for (which = 0; which <
ARRAY_LEN(test_items); which++) {
12934 if (ftruncate(fileno(file), 0)) {
12941 if (test_items[which].
type == INT) {
12942 *((
int *) test_items[which].location) = test_items[which].u.intval;
12943 }
else if (test_items[which].
type == FLAGVAL) {
12949 }
else if (test_items[which].
type == STATIC) {
12950 strcpy(test_items[which].location, test_items[which].u.strval);
12951 }
else if (test_items[which].
type == STRPTR) {
12952 test_items[which].location = test_items[which].u.strval;
12955 make_email_file(file, from, vmu, 0, testcontext, testmailbox,
"INBOX", cidnum, cidname, attach, attach2, format, 999, 1, chan, NULL, 0, NULL);
12957 while (fgets(buf,
sizeof(buf), file)) {
12959 #ifdef IMAP_STORAGE
12960 buf[strlen(buf) - 2] !=
'\r'
12962 buf[strlen(buf) - 2] ==
'\r'
12964 || buf[strlen(buf) - 1] !=
'\n') {
12978 char config_filename[32] =
"/tmp/voicemail.conf.XXXXXX";
12985 info->name =
"test_voicemail_load_config";
12986 info->category =
"/apps/app_voicemail/";
12987 info->summary =
"Test loading Voicemail config";
12988 info->description =
12989 "Verify that configuration is loaded consistently. "
12990 "This is to test regressions of ASTERISK-18838 where it was noticed that "
12991 "some options were loaded after the mailboxes were instantiated, causing "
12992 "those options not to be set correctly.";
12999 if ((fd = mkstemp(config_filename)) < 0) {
13002 if (!(file = fdopen(fd,
"w"))) {
13004 unlink(config_filename);
13007 fputs(
"[general]\ncallback=somecontext\nlocale=de_DE.UTF-8\ntz=european\n[test]", file);
13008 fputs(
"00000001 => 9999,Mr. Test,,,callback=othercontext|locale=nl_NL.UTF-8|tz=central\n", file);
13009 fputs(
"00000002 => 9999,Mrs. Test\n", file);
13017 load_config_from_memory(1, cfg, NULL);
13020 #define CHECK(u, attr, value) else if (strcmp(u->attr, value)) { \
13021 ast_test_status_update(test, "mailbox %s should have %s '%s', but has '%s'\n", \
13022 u->mailbox, #attr, value, u->attr); res = AST_TEST_FAIL; break; }
13026 if (!strcmp(vmu->
mailbox,
"00000001")) {
13028 CHECK(vmu, callback,
"othercontext")
13029 CHECK(vmu, locale, "nl_NL.UTF-8")
13030 CHECK(vmu, zonetag, "central")
13031 }
else if (!strcmp(vmu->mailbox, "00000002")) {
13033 CHECK(vmu, callback,
"somecontext")
13034 CHECK(vmu, locale, "de_DE.UTF-8")
13035 CHECK(vmu, zonetag, "european")
13046 unlink(config_filename);
13069 #ifdef TEST_FRAMEWORK
13078 ao2_ref(inprocess_container, -1);
13095 my_umask = umask(0);
13119 #ifdef TEST_FRAMEWORK
13143 char destination[80] =
"";
13147 ast_verb(3,
"Destination number will be entered manually\n");
13148 while (retries < 3 && cmd !=
't') {
13149 destination[1] =
'\0';
13158 destination[0] = cmd;
13167 ast_verb(3,
"User hit '*' to cancel outgoing call\n");
13170 if ((cmd =
ast_readstring(chan, destination + strlen(destination),
sizeof(destination) - 1, 6000, 10000,
"#")) < 0)
13177 if (retries >= 3) {
13188 if (destination[strlen(destination) -1 ] ==
'*')
13216 char filename[PATH_MAX];
13218 const char *origtime, *
context;
13229 snprintf(filename,
sizeof(filename),
"%s.txt", vms->
fn);
13246 if (!strncasecmp(
"macro", context, 5))
13264 while ((res > -1) && (res !=
't')) {
13288 ast_verb(3,
"Caller can not specify callback number - no dialout context available\n");
13310 ast_verb(3,
"Confirm CID number '%s' is number to use for callback\n", num);
13346 else if (res ==
'*')
13358 ast_verb(3,
"No CID number available, no reply sent\n");
13368 snprintf(mailbox,
sizeof(mailbox),
"%s@%s", num, vmu->
context);
13370 ast_verb(3,
"Leaving voicemail for '%s' in context '%s'\n", num, vmu->
context);
13372 memset(&leave_options, 0,
sizeof(leave_options));
13381 ast_verb(3,
"No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->
context);
13395 #ifndef IMAP_STORAGE
13398 vms->
heard[msg] = 1;
13406 int outsidecaller,
struct ast_vm_user *vmu,
int *duration,
int *sound_duration,
const char *unlockdir,
13412 int max_attempts = 3;
13415 int msg_exists = 0;
13416 signed char zero_gain = 0;
13417 char tempfile[PATH_MAX];
13419 char *canceldtmf =
"";
13420 int canceleddtmf = 0;
13425 if (duration == NULL) {
13430 if (!outsidecaller)
13431 snprintf(tempfile,
sizeof(tempfile),
"%s.tmp", recordfile);
13437 while ((cmd >= 0) && (cmd !=
't')) {
13446 ast_verb(3,
"Saving message as is\n");
13447 if (!outsidecaller)
13450 if (!outsidecaller) {
13460 ast_verb(3,
"Reviewing the message\n");
13467 ast_verb(3,
"Re-recording the message\n");
13469 ast_verb(3,
"Recording the message\n");
13471 if (recorded && outsidecaller) {
13481 cmd =
ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, sound_duration, silencethreshold, maxsilence, unlockdir, acceptdtmf, canceldtmf);
13482 if (strchr(canceldtmf, cmd)) {
13490 if (!outsidecaller) {
13498 }
else if (cmd ==
'*') {
13501 }
else if (vmu->review && sound_duration && (*sound_duration < 5)) {
13503 ast_verb(3,
"Message too short\n");
13507 }
else if (vmu->review && (cmd == 2 && sound_duration && *sound_duration < (maxsilence + 3))) {
13509 ast_verb(3,
"Nothing recorded\n");
13523 if (outsidecaller) {
13528 strcpy(flag,
"Urgent");
13557 if (outsidecaller) {
13569 if (msg_exists || recorded) {
13577 }
else if (cmd ==
'4') {
13580 strcpy(flag,
"Urgent");
13586 DELETE(tempfile, -1, tempfile, vmu);
13599 if (!cmd && outsidecaller) {
13626 if (attempts > max_attempts) {
13631 if (!outsidecaller && (cmd == -1 || cmd ==
't')) {
13636 if (cmd !=
't' && outsidecaller)
13650 .nonoptreq =
"res_adsi,res_smdi",
static struct ast_vm_user * find_user_realtime(struct ast_vm_user *ivm, const char *context, const char *mailbox)
Finds a voicemail user from the realtime engine.
static char emaildateformat[32]
static int vm_intro_fr(struct ast_channel *chan, struct vm_state *vms)
int ast_filecopy(const char *oldname, const char *newname, const char *fmt)
Copies a file.
static int vm_instructions_en(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
static struct ast_cli_entry cli_voicemail[]
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
int ast_hangup(struct ast_channel *chan)
Hang up a channel.
#define ast_channel_lock(chan)
static char exten[AST_MAX_EXTENSION]
Main Channel structure associated with a channel.
int ast_adsi_voice_mode(unsigned char *buf, int when)
Puts CPE in voice mode.
static int vm_intro_vi(struct ast_channel *chan, struct vm_state *vms)
#define AST_CLI_DEFINE(fn, txt,...)
static void make_email_file(FILE *p, char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *attach, char *attach2, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, int imap, const char *flag)
Creates the email file to be sent to indicate a new voicemail exists for a user.
char * str
Subscriber phone number (Malloced)
static struct ast_event_sub * mwi_unsub_sub
#define AST_APP_OPTION_ARG(option, flagno, argno)
Declares an application option that accepts an argument.
int ast_store_realtime(const char *family,...) attribute_sentinel
Create realtime configuration.
static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
static void free_user(struct ast_vm_user *vmu)
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
#define AST_LIST_LOCK(head)
Locks a list.
static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
int ast_safe_system(const char *s)
Safely spawn an external program while closing file descriptors.
Asterisk locking-related definitions:
void astman_append(struct mansession *s, const char *fmt,...)
Asterisk main include file. File version handling, generic pbx functions.
#define ao2_link(arg1, arg2)
static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
const char * ast_variable_retrieve(const struct ast_config *config, const char *category, const char *variable)
Gets a variable.
int ast_adsi_begin_download(struct ast_channel *chan, char *service, unsigned char *fdn, unsigned char *sec, int version)
int ast_play_and_record_full(struct ast_channel *chan, const char *playfile, const char *recordfile, int maxtime_sec, const char *fmt, int *duration, int *sound_duration, int silencethreshold, int maxsilence_ms, const char *path, const char *acceptdtmf, const char *canceldtmf)
Record a file based on input from a channel This function will play "auth-thankyou" upon successful r...
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
The data tree to be returned by the callbacks and managed by functions local to this file...
static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
int ast_app_getdata(struct ast_channel *c, const char *prompt, char *s, int maxlen, int timeout)
Plays a stream and gets DTMF data from a channel.
struct ast_frame ast_null_frame
static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
struct ast_party_caller caller
Channel Caller ID information.
static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
char * strsep(char **str, const char *delims)
static int make_dir(char *dest, int len, const char *context, const char *ext, const char *folder)
Creates a file system path expression for a folder within the voicemail data folder and the appropria...
static void adsi_goodbye(struct ast_channel *chan)
struct ast_app * pbx_findapp(const char *app)
Look up an application.
static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
static int handle_unsubscribe(void *datap)
static void queue_mwi_event(const char *box, int urgent, int new, int old)
int ast_callerid_split(const char *src, char *name, int namelen, char *num, int numlen)
int ast_safe_fork(int stop_reaper)
Common routine to safely fork without a chance of a signal handler firing badly in the child...
#define HVSU_OUTPUT_FORMAT
#define AST_RWLIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a read/write list of specified type, statically initialized...
int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data)
Execute an application.
static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
Resets a user password to a specified password.
static void run_externnotify(char *context, char *extension, const char *flag)
enum ast_event_type ast_event_get_type(const struct ast_event *event)
Get the type for an event.
static int vm_play_folder_name(struct ast_channel *chan, char *mbox)
int ast_adsi_data_mode(unsigned char *buf)
Puts CPE in data mode.
static void rename_file(char *sfn, char *dfn)
Renames a message in a mailbox folder.
#define RETRIEVE(a, b, c, d)
#define EXISTS(a, b, c, d)
static int append_mailbox(const char *context, const char *box, const char *data)
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
static int make_file(char *dest, const int len, const char *dir, const int num)
Creates a file system path expression for a folder within the voicemail data folder and the appropria...
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
static const char *const mailbox_folders[]
static int say_and_wait(struct ast_channel *chan, int num, const char *language)
#define ast_channel_unref(c)
Decrease channel reference count.
static char * complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
int ast_control_streamfile(struct ast_channel *chan, const char *file, const char *fwd, const char *rev, const char *stop, const char *pause, const char *restart, int skipms, long *offsetms)
Stream a file with fast forward, pause, reverse, restart.
static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
The handler for the change password option.
static unsigned char adsisec[4]
#define ast_set2_flag(p, value, flag)
#define ast_test_flag(p, flag)
#define SMDI_MWI_WAIT_TIMEOUT
static void copy_plain_file(char *frompath, char *topath)
Copies a voicemail information (envelope) file.
static int inbuf(struct baseio *bio, FILE *fi)
utility used by inchar(), for base_encode()
int ast_unload_realtime(const char *family)
Release any resources cached for a realtime family.
Time-related functions and macros.
static int valid_config(const struct ast_config *cfg)
Check if configuration file is valid.
struct ast_party_name name
Subscriber name.
static int handle_subscribe(void *datap)
static int saydurationminfo
struct ast_party_id from
Who is redirecting the call (Sent to the party the call is redirected toward)
static unsigned char poll_thread_run
static int load_config(int reload)
#define DEFAULT_LISTEN_CONTROL_STOP_KEY
int ast_taskprocessor_push(struct ast_taskprocessor *tps, int(*task_exe)(void *datap), void *datap)
Push a task into the specified taskprocessor queue and signal the taskprocessor thread.
Convenient Signal Processing routines.
#define AST_RWLIST_WRLOCK(head)
Write locks a list.
char context[AST_MAX_CONTEXT]
static char * emailsubject
int ast_app_has_voicemail(const char *mailbox, const char *folder)
Determine if a given mailbox has any voicemail If folder is NULL, defaults to "INBOX". If folder is "INBOX", includes the number of messages in the "Urgent" folder.
#define ast_set_flag(p, flag)
static int actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg)
int ast_event_queue_and_cache(struct ast_event *event)
Queue and cache an event.
void ast_event_report_subs(const struct ast_event_sub *sub)
Report current subscriptions to a subscription subscriber.
descriptor for a cli entry.
int ast_update2_realtime(const char *family,...) attribute_sentinel
Update realtime configuration.
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
static char listen_control_restart_key[12]
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category)
Goes through variables.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
static char intro[ADSI_MAX_INTRO][20]
static void free_vm_users(void)
Free the users structure.
static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
static const char * substitute_escapes(const char *value)
static struct ast_custom_function mailbox_exists_acf
struct ast_taskprocessor * ast_taskprocessor_get(const char *name, enum ast_tps_options create)
Get a reference to a taskprocessor with the specified name and create the taskprocessor if necessary...
void ast_verbose(const char *fmt,...)
int ast_app_parse_options(const struct ast_app_option *options, struct ast_flags *flags, char **args, char *optstr)
Parses a string containing application options and sets flags/arguments.
struct ast_smdi_interface * ast_smdi_interface_find(const char *iface_name)
Find an SMDI interface with the specified name.
#define AST_RWLIST_UNLOCK(head)
Attempts to unlock a read/write based list.
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
static int acf_mailbox_exists(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
int ast_unlock_path(const char *path)
Unlock a path.
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
This entries are for multiple registers.
static int resequence_mailbox(struct ast_vm_user *vmu, char *dir, int stopcount)
static struct ast_vm_user * find_or_create(const char *context, const char *box)
Structure for variables, used for configurations and for channel variables.
static char * handle_voicemail_show_users(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Show a list of voicemail users in the CLI.
int ast_adsi_set_keys(unsigned char *buf, unsigned char *keys)
Set which soft keys should be displayed.
static int messagecount(const char *context, const char *mailbox, const char *folder)
static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
int ast_adsi_load_session(struct ast_channel *chan, unsigned char *app, int ver, int data)
Check if scripts for a given app are already loaded. Version may be -1, if any version is okay...
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
struct ast_party_redirecting redirecting
Redirecting/Diversion information.
int ast_say_digit_str(struct ast_channel *chan, const char *num, const char *ints, const char *lang)
says digits of a string
#define AST_TEST_REGISTER(cb)
#define DATA_EXPORT_VM_USERS(USER)
static FILE * vm_mkftemp(char *template)
static struct ast_data_handler vm_users_data_provider
Configuration File Parser.
int ast_adsi_download_disconnect(unsigned char *buf)
Disconnects (and hopefully saves) a downloaded script.
char * str
Subscriber name (Malloced)
int ast_config_text_file_save(const char *filename, const struct ast_config *cfg, const char *generator)
struct ast_variable * ast_load_realtime(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
static int leave_voicemail(struct ast_channel *chan, char *ext, struct leave_vm_options *options)
Prompts the user and records a voicemail to a mailbox.
static int vm_intro_pt(struct ast_channel *chan, struct vm_state *vms)
static struct ast_threadstorage buf2
static int last_message_index(struct ast_vm_user *vmu, char *dir)
Determines the highest message number in use for a given user and mailbox folder. ...
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
Number of new messages Used by: AST_EVENT_MWI Payload type: UINT.
struct ast_str * ast_str_create(size_t init_len)
Create a malloc'ed dynamic length string.
static int passwordlocation
Number of Used by: AST_EVENT_MWI Payload type: UINT.
static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
Manager list voicemail users command.
static char * show_users_realtime(int fd, const char *context)
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
#define ast_mutex_lock(a)
unsigned char iobuf[BASEMAXINLINE]
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
#define ast_copy_flags(dest, src, flagz)
#define ast_str_alloca(init_len)
static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
const char * ast_config_option(struct ast_config *cfg, const char *cat, const char *var)
Retrieve a configuration variable within the configuration set.
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
static char * pagersubject
Definitions to aid in the use of thread local storage.
static void poll_subscribed_mailboxes(void)
static char * handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Reload voicemail configuration from the CLI.
int ast_filedelete(const char *filename, const char *fmt)
Deletes a file.
void ast_cli(int fd, const char *fmt,...)
ADSI Support (built upon Caller*ID)
static int vm_newuser(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
static int input(yyscan_t yyscanner)
static int inprocess_cmp_fn(void *obj, void *arg, int flags)
#define AST_DATA_ENTRY(__path, __handler)
int ast_channel_setoption(struct ast_channel *channel, int option, void *data, int datalen, int block)
Sets an option on a channel.
list of users found in the config file
int ast_unregister_application(const char *app)
Unregister an application.
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
#define ast_cond_signal(cond)
static struct ast_taskprocessor * mwi_subscription_tps
static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box)
#define ast_verb(level,...)
static int copy(char *infile, char *outfile)
Utility function to copy a file.
void ast_config_destroy(struct ast_config *config)
Destroys a config.
static char VM_SPOOL_DIR[PATH_MAX]
void ast_unreplace_sigchld(void)
Restore the SIGCHLD handler.
static int vm_forwardoptions(struct ast_channel *chan, struct ast_vm_user *vmu, char *curdir, int curmsg, char *vm_fmts, char *context, signed char record_gain, long *duration, struct vm_state *vms, char *flag)
presents the option to prepend to an existing message when forwarding it.
static char pagerdateformat[32]
static struct ast_data_entry vm_data_providers[]
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return * the previous value of *p. This can be used to handle reference co...
static void stop_poll_thread(void)
#define ast_test_suite_assert(exp)
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
struct ast_channel * ast_channel_alloc(int needqueue, int state, const char *cid_num, const char *cid_name, const char *acctcode, const char *exten, const char *context, const char *linkedid, const int amaflag, const char *name_fmt,...)
int ast_canmatch_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Looks for a valid matching extension.
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
static ast_cond_t poll_cond
String fields in structures.
static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
static char userscontext[AST_MAX_EXTENSION]
const char * astman_get_header(const struct message *m, char *var)
Get header from mananger transaction.
pthread_cond_t ast_cond_t
static int vm_instructions(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
static void * mb_poll_thread(void *data)
char cause[SMDI_MWI_FAIL_CAUSE_LEN+1]
#define ast_manager_event(chan, category, event, contents,...)
static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
struct ast_category * ast_category_new(const char *name, const char *in_file, int lineno)
Create a category structure.
int ast_smdi_mwi_set(struct ast_smdi_interface *iface, const char *mailbox)
Set the MWI indicator for a mailbox.
static int adsi_logo(unsigned char *buf)
#define ADSI_DIR_FROM_LEFT
Custom localtime functions for multiple timezones.
static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
struct ast_party_id id
Caller party ID.
struct ast_category * ast_category_get(const struct ast_config *config, const char *category_name)
Retrieve a category if it exists.
static char listen_control_forward_key[12]
int ast_update_realtime(const char *family, const char *keyfield, const char *lookup,...) attribute_sentinel
Update realtime configuration.
static int vm_intro_zh(struct ast_channel *chan, struct vm_state *vms)
#define DEFAULT_LISTEN_CONTROL_FORWARD_KEY
#define AST_RWLIST_RDLOCK(head)
Read locks a list.
int ast_get_time_t(const char *src, time_t *dst, time_t _default, int *consumed)
get values from config variables.
#define ast_debug(level,...)
Log a DEBUG message.
int ast_adsi_set_line(unsigned char *buf, int page, int line)
Sets the current line and page.
int ast_play_and_wait(struct ast_channel *chan, const char *fn)
Play a stream and wait for a digit, returning the digit that was pressed.
enum AST_LOCK_RESULT ast_lock_path(const char *path)
Lock a filesystem path.
Context IE Used by AST_EVENT_MWI Payload type: str.
static int get_folder2(struct ast_channel *chan, char *fn, int start)
plays a prompt and waits for a keypress.
#define AST_DATA_HANDLER_VERSION
The Data API structures version.
void ast_category_destroy(struct ast_category *cat)
int ast_adsi_input_format(unsigned char *buf, int num, int dir, int wrap, char *format1, char *format2)
Set input format.
int ast_say_counted_noun(struct ast_channel *chan, int num, const char *noun)
int ast_build_string(char **buffer, size_t *space, const char *fmt,...)
Build a string in a buffer, designed to be called repeatedly.
static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback)
char * ast_callerid_merge(char *buf, int bufsiz, const char *name, const char *num, const char *unknown)
static char * handle_voicemail_show_zones(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Show a list of voicemail zones in the CLI.
General Asterisk PBX channel definitions.
int ast_destroy_realtime(const char *family, const char *keyfield, const char *lookup,...) attribute_sentinel
Destroy realtime configuration.
static char vm_mismatch[80]
static int get_folder_by_name(const char *name)
static void mwi_unsub_event_cb(const struct ast_event *event, void *userdata)
static int quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int count_messages(struct ast_vm_user *vmu, char *dir)
Find all .txt files - even if they are not in sequence from 0000.
#define VMSTATE_MAX_MSG_ARRAY
#define ast_test_status_update(a, b, c...)
#define ast_config_load(filename, flags)
Load a config file.
#define ast_manager_register_xml(a, b, c)
Register a manager callback using XML documentation to describe the manager.
static struct ast_event_sub * mwi_sub
static int vm_intro_pt_BR(struct ast_channel *chan, struct vm_state *vms)
#define AST_PTHREADT_NULL
static force_inline int attribute_pure ast_strlen_zero(const char *s)
struct sla_ringing_trunk * last
Data structure associated with a custom dialplan function.
struct ast_data * ast_data_add_node(struct ast_data *root, const char *childname)
Add a container child.
char mailbox[AST_MAX_EXTENSION]
#define AST_MAX_EXTENSION
#define AST_RWLIST_TRAVERSE
static int sendpage(char *srcemail, char *pager, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, int duration, struct ast_vm_user *vmu, const char *category, const char *flag)
#define ast_data_unregister(path)
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
char * ast_category_browse(struct ast_config *config, const char *prev)
Goes through categories.
#define ao2_ref(o, delta)
static int vmsayname_exec(struct ast_channel *chan, const char *data)
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
char context[AST_MAX_CONTEXT]
long int ast_random(void)
struct timeval ast_samp2tv(unsigned int _nsamp, unsigned int _rate)
Returns a timeval corresponding to the duration of n samples at rate r. Useful to convert samples to ...
static int vm_play_folder_name_ua(struct ast_channel *chan, char *box)
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, int *sound_duration, const char *unlockdir, signed char record_gain, struct vm_state *vms, char *flag)
static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
static struct ast_vm_user * find_user(struct ast_vm_user *ivm, const char *context, const char *mailbox)
Finds a voicemail user from the users file or the realtime engine.
static char ext_pass_check_cmd[128]
static int vmauthenticate(struct ast_channel *chan, const char *data)
static char language[MAX_LANGUAGE]
int ast_adsi_display(unsigned char *buf, int page, int line, int just, int wrap, char *col1, char *col2)
Loads a line of info into the display.
int ast_strftime_locale(char *buf, size_t len, const char *format, const struct ast_tm *tm, const char *locale)
char * ast_format_str_reduce(char *fmts)
static void adsi_login(struct ast_channel *chan)
static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
Loads the options specific to a voicemail user.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
int ast_app_inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
Determine number of new/old messages in a mailbox.
static int inprocess_hash_fn(const void *obj, const int flags)
static int check_password(struct ast_vm_user *vmu, char *password)
Check that password meets minimum required length.
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
#define ast_data_register_multiple(data_entries, entries)
Structure to describe a channel "technology", ie a channel driver See for examples: ...
static char vm_newpassword[80]
static char dialcontext[AST_MAX_CONTEXT]
static pthread_t poll_thread
Core PBX routines and definitions.
static int is_valid_dtmf(const char *key)
Determines if a DTMF key entered is valid.
static char callcontext[AST_MAX_CONTEXT]
#define AST_RWLIST_TRAVERSE_SAFE_BEGIN
#define ast_data_add_structure(structure_name, root, structure)
int ast_app_inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
Determine number of urgent/new/old messages in a mailbox.
Event type Used by: AST_EVENT_SUB, AST_EVENT_UNSUB Payload type: UINT.
The list of nodes with their search requirement.
#define ASTOBJ_UNREF(object, destructor)
Decrement the reference count on an object.
#define AST_LIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
#define ast_test_suite_event_notify(s, f,...)
static char vm_prepend_timeout[80]
static void apply_options(struct ast_vm_user *vmu, const char *options)
Destructively Parse options and apply.
const char * ast_config_AST_DATA_DIR
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define ast_strdupa(s)
duplicate a string in memory from the stack
int ast_adsi_transmit_message(struct ast_channel *chan, unsigned char *msg, int msglen, int msgtype)
#define DEFAULT_LISTEN_CONTROL_PAUSE_KEY
static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
#define ASTERISK_USERNAME
static unsigned char adsifdn[4]
static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
Performs a change of the voicemail passowrd in the realtime engine.
#define AST_LIST_HEAD_NOLOCK_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
static int vm_play_folder_name_gr(struct ast_channel *chan, char *box)
static void adsi_begin(struct ast_channel *chan, int *useadsi)
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
SQLHSTMT ast_odbc_direct_execute(struct odbc_obj *obj, SQLHSTMT(*exec_cb)(struct odbc_obj *obj, void *data), void *data)
Executes an non prepared statement and returns the resulting statement handle.
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
static int vm_exec(struct ast_channel *chan, const char *data)
The descriptor of a dynamic string XXX storage will be optimized later if needed We use the ts field ...
#define VOICEMAIL_FILE_MODE
void ast_data_remove_node(struct ast_data *root, struct ast_data *child)
Remove a node that was added using ast_data_add_.
#define AST_TEST_UNREGISTER(cb)
static unsigned int poll_freq
void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
static struct ast_event_sub * mwi_sub_sub
static char pagerfromstring[100]
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
static void prep_email_sub_vars(struct ast_channel *ast, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *dur, char *date, const char *category, const char *flag)
enum ast_channel_state _state
static int vm_intro_es(struct ast_channel *chan, struct vm_state *vms)
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
static int unload_module(void)
const ast_string_field name
void ast_log(int level, const char *file, int line, const char *function, const char *fmt,...)
Used for sending a log message This is the standard logger function. Probably the only way you will i...
static int vm_intro_no(struct ast_channel *chan, struct vm_state *vms)
#define ao2_alloc(data_size, destructor_fn)
int ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
static char * sayname_app
static int vm_browse_messages_vi(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
Vietnamese syntax for 'You have N messages' greeting.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
int ast_say_counted_adjective(struct ast_channel *chan, int num, const char *adjective, const char *gender)
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
#define DATA_EXPORT_VM_ZONES(ZONE)
static struct ast_threadstorage buf1
static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
#define ao2_find(arg1, arg2, arg3)
#define ast_channel_unlock(chan)
static int vm_execmain(struct ast_channel *chan, const char *data)
static void parse(struct mgcp_request *req)
#define ast_pthread_create(a, b, c, d)
char macrocontext[AST_MAX_CONTEXT]
static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
static int vm_intro_nl(struct ast_channel *chan, struct vm_state *vms)
static int advanced_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg, int option, signed char record_gain)
The advanced options within a message.
static int get_date(char *s, int len)
Gets the current date and time, as formatted string.
struct ast_config * ast_config_new(void)
Create a new base configuration structure.
int ast_adsi_end_download(struct ast_channel *chan)
static int get_folder(struct ast_channel *chan, int start)
get_folder: Folder menu Plays "press 1 for INBOX messages" etc. Should possibly be internationalized ...
int ast_stream_and_wait(struct ast_channel *chan, const char *file, const char *digits)
stream file until digit If the file name is non-empty, try to play it.
static int sendmail(char *srcemail, struct ast_vm_user *vmu, int msgnum, char *context, char *mailbox, const char *fromfolder, char *cidnum, char *cidname, char *attach, char *attach2, char *format, int duration, int attach_user_voicemail, struct ast_channel *chan, const char *category, const char *flag)
#define COPY(a, b, c, d, e, f, g, h)
int ast_say_character_str(struct ast_channel *chan, const char *num, const char *ints, const char *lang)
#define ast_odbc_request_obj(a, b)
static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
Sets a a specific property value.
void ast_close_fds_above_n(int n)
Common routine for child processes, to close all fds prior to exec(2)
#define VOICEMAIL_DIR_MODE
SMDI support for Asterisk.
static struct ast_flags globalflags
int ast_adsi_load_soft_key(unsigned char *buf, int key, const char *llabel, const char *slabel, char *ret, int data)
Creates "load soft key" parameters.
static struct ast_app_option vm_app_options[128]
const char * ast_config_AST_SPOOL_DIR
int ast_strftime(char *buf, size_t len, const char *format, const struct ast_tm *tm)
Special version of strftime(3) that handles fractions of a second. Takes the same arguments as strfti...
static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
#define ADSI_MSG_DOWNLOAD
static int vm_lock_path(const char *path)
Lock file path only return failure if ast_lock_path returns 'timeout', not if the path does not exist...
An API for managing task processing threads that can be shared across modules.
static void mwi_sub_destroy(struct mwi_sub *mwi_sub)
int ast_variable_update(struct ast_category *category, const char *variable, const char *value, const char *match, unsigned int object)
Update variable value within a config.
static char vm_reenterpassword[80]
char fwd_st[SMDI_MAX_STATION_NUM_LEN+1]
#define PWDCHANGE_EXTERNAL
static void adsi_password(struct ast_channel *chan)
static int inprocess_count(const char *context, const char *mailbox, int delta)
if(yyss+yystacksize-1<=yyssp)
structure to hold users read from users.conf
static void * cleanup(void *unused)
Structure used to handle boolean flags.
static int vm_browse_messages_latin(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
Common LATIN languages syntax for 'You have N messages' greeting.
int ast_realtime_require_field(const char *family,...) attribute_sentinel
Inform realtime what fields that may be stored.
static char listen_control_stop_key[12]
static char * strip_control_and_high(const char *input, char *buf, size_t buflen)
Strips control and non 7-bit clean characters from input string.
#define ast_clear_flag(p, flag)
#define DEFAULT_LISTEN_CONTROL_REVERSE_KEY
Support for logging to various files, console and syslog Configuration in file logger.conf.
void ast_install_vm_functions(int(*has_voicemail_func)(const char *mailbox, const char *folder), int(*inboxcount_func)(const char *mailbox, int *newmsgs, int *oldmsgs), int(*inboxcount2_func)(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs), int(*messagecount_func)(const char *context, const char *mailbox, const char *folder), int(*sayname_func)(struct ast_channel *chan, const char *mailbox, const char *context))
Set voicemail function callbacks.
static void mwi_sub_event_cb(const struct ast_event *event, void *userdata)
static unsigned int poll_mailboxes
static int vm_box_exists(struct ast_channel *chan, const char *data)
static int vm_browse_messages_zh(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
Chinese (Taiwan)syntax for 'You have N messages' greeting.
Options for leaving voicemail with the voicemail() application.
static char serveremail[80]
int pbx_builtin_setvar_helper(struct ast_channel *chan, const char *name, const char *value)
Add a variable to the channel variable stack, removing the most recently set value for the same name...
uint32_t ast_event_get_ie_uint(const struct ast_event *event, enum ast_event_ie_type ie_type)
Get the value of an information element that has an integer payload.
int(*const write)(struct ast_channel *chan, struct ast_frame *frame)
Write a frame, in standard format (see frame.h)
static void poll_subscribed_mailbox(struct mwi_sub *mwi_sub)
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
char language[MAX_LANGUAGE]
int ast_play_and_prepend(struct ast_channel *chan, char *playfile, char *recordfile, int maxtime_sec, char *fmt, int *duration, int *sound_duration, int beep, int silencethreshold, int maxsilence_ms)
Record a file based on input frm a channel. Recording is performed in 'prepend' mode which works a li...
static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
#define EVENT_FLAG_REPORTING
static int vm_users_data_provider_get(const struct ast_data_search *search, struct ast_data *data_root)
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
#define AST_RWLIST_INSERT_TAIL
SQLHSTMT ast_odbc_prepare_and_execute(struct odbc_obj *obj, SQLHSTMT(*prepare_cb)(struct odbc_obj *obj, void *data), void *data)
Prepares, executes, and returns the resulting statement handle.
static int has_voicemail(const char *mailbox, const char *folder)
Determines if the given folder has messages.
int ast_adsi_available(struct ast_channel *chan)
Returns non-zero if Channel does or might support ADSI.
A ast_taskprocessor structure is a singleton by name.
#define STORE(a, b, c, d, e, f, g, h, i, j)
static char vm_password[80]
static int ochar(struct baseio *bio, int c, FILE *so)
utility used by base_encode()
static int vm_allocate_dh(struct vm_state *vms, struct ast_vm_user *vmu, int count_msg)
int ast_say_number(struct ast_channel *chan, int num, const char *ints, const char *lang, const char *options)
says a number
Standard Command Line Interface.
struct ast_event * ast_event_new(enum ast_event_type event_type,...)
Create a new event.
struct ast_event_sub * ast_event_subscribe(enum ast_event_type event_type, ast_event_cb_t cb, const char *description, void *userdata,...)
Subscribe to events.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
static char listen_control_reverse_key[12]
#define ao2_container_alloc(arg1, arg2, arg3)
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
static ast_mutex_t poll_lock
ast_app: A registered application
static char externnotify[160]
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"...
int ast_cli_register_multiple(struct ast_cli_entry *e, int len)
Register multiple commands.
SAY_EXTERN int(* ast_say_date_with_format)(struct ast_channel *chan, time_t t, const char *ints, const char *lang, const char *format, const char *timezone) SAY_INIT(ast_say_date_with_format)
#define AST_OPTION_RXGAIN
#define ast_realloc(a, b)
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
static void adsi_folders(struct ast_channel *chan, int start, char *label)
int ast_answer(struct ast_channel *chan)
Answer a channel.
static char vm_invalid_password[80]
static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64]
static int vm_browse_messages_en(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
Default English syntax for 'You have N messages' greeting.
static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
basically mkdir -p $dest/$context/$ext/$folder
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
void ast_smdi_mwi_message_destroy(struct ast_smdi_mwi_message *msg)
ast_smdi_mwi_message destructor.
static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
static int vm_intro_de(struct ast_channel *chan, struct vm_state *vms)
static int vm_tempgreeting(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
The handler for 'record a temporary greeting'.
Data structure associated with a single frame of data.
#define AST_DATA_STRUCTURE(__struct, __name)
#define HVSZ_OUTPUT_FORMAT
static int silencethreshold
static void read_password_from_file(const char *secretfn, char *password, int passwordlen)
#define AST_TEST_DEFINE(hdr)
static int vm_browse_messages_he(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
static void free_vm_zones(void)
Free the zones structure.
static char * vm_check_password_shell(char *command, char *buf, size_t len)
Unique ID Used by: AST_EVENT_SUB, AST_EVENT_UNSUB Payload type: UINT.
#define DEFAULT_LISTEN_CONTROL_RESTART_KEY
#define DEFAULT_POLL_FREQ
int ast_filerename(const char *oldname, const char *newname, const char *fmt)
Renames a file.
#define PWDCHANGE_INTERNAL
#define RENAME(a, b, c, d, e, f, g, h)
static int vm_delete(char *file)
Removes the voicemail sound and information file.
static int vm_instructions_zh(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent)
#define AST_APP_ARG(name)
Define an application argument.
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
static struct ast_smdi_interface * smdi_iface
static int base_encode(char *filename, FILE *so)
Performs a base 64 encode algorithm on the contents of a File.
struct ast_variable * next
static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
static int play_message_category(struct ast_channel *chan, const char *category)
int ast_adsi_input_control(unsigned char *buf, int page, int line, int display, int format, int just)
Set input information.
static void populate_defaults(struct ast_vm_user *vmu)
Sets default voicemail system options to a voicemail user.
#define ast_mutex_init(pmutex)
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
unsigned char valid
TRUE if the name information is valid/present.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
void ast_category_append(struct ast_config *config, struct ast_category *cat)
#define CONFIG_STATUS_FILEINVALID
int ast_smdi_mwi_unset(struct ast_smdi_interface *iface, const char *mailbox)
Unset the MWI indicator for a mailbox.
static char context[AST_MAX_CONTEXT]
int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int rtimeout, char *enders)
Reads multiple digits.
#define ast_mutex_destroy(a)
static int forward_message(struct ast_channel *chan, char *context, struct vm_state *vms, struct ast_vm_user *sender, char *fmt, int is_new_message, signed char record_gain, int urgent)
Sends a voicemail message to a mailbox recipient.
static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
int ast_adsi_unload_session(struct ast_channel *chan)
static int load_module(void)
static int inchar(struct baseio *bio, FILE *fi)
utility used by base_encode()
const char * ast_event_get_ie_str(const struct ast_event *event, enum ast_event_ie_type ie_type)
Get the value of an information element that has a string payload.
#define AST_NONSTANDARD_APP_ARGS(args, parse, sep)
Performs the 'nonstandard' argument separation process for an application.
static struct ast_tm * vmu_tm(const struct ast_vm_user *vmu, struct ast_tm *tm)
fill in *tm for current time according to the proper timezone, if any.
struct ast_channel * ast_dummy_channel_alloc(void)
Create a fake channel structure.
#define DELETE(a, b, c, d)
void ast_odbc_release_obj(struct odbc_obj *obj)
Releases an ODBC object previously allocated by ast_odbc_request_obj()
static void start_poll_thread(void)
Say numbers and dates (maybe words one day too)
int ast_app_messagecount(const char *context, const char *mailbox, const char *folder)
Check number of messages in a given context, mailbox, and folder.
#define ASTERISK_GPL_KEY
The text the key() function should return.
static int check_mime(const char *str)
Check if the string would need encoding within the MIME standard, to avoid confusing certain mail sof...
struct ast_smdi_mwi_message * ast_smdi_mwi_message_wait_station(struct ast_smdi_interface *iface, int timeout, const char *station)
int ast_dsp_get_threshold_from_settings(enum threshold which)
Get silence threshold from dsp.conf.
Asterisk module definitions.
static int vm_browse_messages(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
Top level method to invoke the language variant vm_browse_messages_XX function.
const char * ast_config_AST_VAR_DIR
static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
static int write_password_to_file(const char *secretfn, const char *password)
static void delete_file(struct phoneprov_file *file)
static snd_pcm_format_t format
static int vm_authenticate(struct ast_channel *chan, char *mailbox, int mailbox_size, struct ast_vm_user *res_vmu, const char *context, const char *prefix, int skipuser, int max_logins, int silent)
static int vm_play_folder_name_pl(struct ast_channel *chan, char *box)
struct ast_channel_tech * tech
static char vm_pls_try_again[80]
struct ast_data * ast_data_add_int(struct ast_data *root, const char *childname, int value)
Add an integer node type.
static int vm_users_data_provider_get_helper(const struct ast_data_search *search, struct ast_data *data_root, struct ast_vm_user *user)
struct ast_event_sub * ast_event_unsubscribe(struct ast_event_sub *event_sub)
Un-subscribe from events.
static int add_email_attachment(FILE *p, struct ast_vm_user *vmu, char *format, char *attach, char *greeting_attachment, char *mailbox, char *bound, char *filename, int last, int msgnum)
static int vm_intro_cs(struct ast_channel *chan, struct vm_state *vms)
unsigned char valid
TRUE if the number information is valid/present.
static const char * ast_str_quote(struct ast_str **buf, ssize_t maxlen, const char *from)
Wraps a character sequence in double quotes, escaping occurences of quotes within the string...
static char vm_passchanged[80]
#define ast_cond_timedwait(cond, mutex, time)
int ast_data_search_match(const struct ast_data_search *search, struct ast_data *data)
Check the current generated node to know if it matches the search condition.
#define ast_custom_function_register(acf)
Register a custom function.
#define AST_RWLIST_TRAVERSE_SAFE_END
const ast_string_field language
uint32_t version
Structure version.
char exten[AST_MAX_EXTENSION]
#define AST_MUTEX_DEFINE_STATIC(mutex)
int ast_stopstream(struct ast_channel *c)
Stops a stream.
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
struct ast_variable * ast_variable_new(const char *name, const char *value, const char *filename)
static int vm_intro_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
Structure for mutex and tracking information.
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 *dir, const char *flag)
Copies a message from one mailbox to another.
An SMDI message waiting indicator message.
static char mailbox[AST_MAX_EXTENSION]
static char listen_control_pause_key[12]
static void free_zone(struct vm_zone *z)
The structure of the node handler.
static const char * mbox(struct ast_vm_user *vmu, int id)
int ast_manager_unregister(char *action)
Unregister a registered manager command.
#define ASTERISK_FILE_VERSION(file, version)
Register/unregister a source code file with the core.
static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
struct ast_config * ast_load_realtime_multientry(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
static int sayname(struct ast_channel *chan, const char *mailbox, const char *context)
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
#define CONFIG_STATUS_FILEUNCHANGED
struct ao2_container * inprocess_container
#define ast_mutex_unlock(a)
static char exitcontext[AST_MAX_CONTEXT]
static char fromstring[100]
static char prefix[MAX_PREFIX]
int ast_mkdir(const char *path, int mode)
Recursively create directory path.
int ast_callerid_parse(char *instr, char **name, char **location)
Destructively parse inbuf into name and location (or number)
static int notify_new_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msgnum, long duration, char *fmt, char *cidnum, char *cidname, const char *flag)
Sends email notification that a user has a new voicemail waiting for them.
void ast_uninstall_vm_functions(void)
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
static char ext_pass_cmd[128]
int ast_check_realtime(const char *family)
Check if realtime engine is configured for family.
struct ast_party_number number
Subscriber phone number.
#define MAX_NUM_CID_CONTEXTS
static const char * ast_str_encode_mime(struct ast_str **end, ssize_t maxlen, const char *start, size_t preamble, size_t postamble)
Encode a string according to the MIME rules for encoding strings that are not 7-bit clean or contain ...