56#include <imap/c-client.h>
57#include <imap/imap4r1.h>
58#include <imap/linkage.h>
59#elif defined (USE_SYSTEM_CCLIENT)
60#include <c-client/c-client.h>
61#include <c-client/imap4r1.h>
62#include <c-client/linkage.h>
76#if defined(__FreeBSD__) || defined(__OpenBSD__)
616static char imapserver[48] =
"localhost";
617static char imapport[8] =
"143";
618static char imapflags[128];
619static char imapfolder[64] =
"INBOX";
620static char imapparentfolder[64];
621static char greetingfolder[64] =
"INBOX";
622static char authuser[32];
623static char authpassword[42];
624static int imapversion = 1;
626static int expungeonhangup = 1;
627static int imapgreetings;
628static int imap_poll_logout;
629static char delimiter;
640static int init_mailstream(
struct vm_state *vms,
int box);
641static void write_file(
char *filename,
char *buffer,
unsigned long len);
642static char *get_header_by_tag(
char *
header,
char *tag,
char *
buf,
size_t len);
643static void vm_imap_delete(
char *
file,
int msgnum,
struct ast_vm_user *vmu);
644static char *get_user_by_mailbox(
char *
mailbox,
char *
buf,
size_t len);
645static struct vm_state *get_vm_state_by_imapuser(
const char *
user,
int interactive);
646static struct vm_state *get_vm_state_by_mailbox(
const char *
mailbox,
const char *
context,
int interactive);
648static void vmstate_insert(
struct vm_state *vms);
649static void vmstate_delete(
struct vm_state *vms);
650static void set_update(MAILSTREAM * stream);
651static void init_vm_state(
struct vm_state *vms);
652static int save_body(BODY *body,
struct vm_state *vms,
char *section,
char *format,
int is_intro);
653static void get_mailbox_delimiter(
struct vm_state *vms, MAILSTREAM *stream);
654static void mm_parsequota (MAILSTREAM *stream,
unsigned char *msg, QUOTALIST *pquota);
655static void imap_mailbox_name(
char *spec,
size_t len,
struct vm_state *vms,
int box,
int target);
656static 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,
const char *msg_id);
657static void vm_imap_update_msg_id(
char *dir,
int msgnum,
const char *msg_id,
struct ast_vm_user *vmu,
struct ast_config *msg_cfg,
int folder);
658static void update_messages_by_imapuser(
const char *
user,
unsigned long number);
661static int imap_remove_file (
char *dir,
int msgnum);
662static int imap_retrieve_file (
const char *dir,
const int msgnum,
const char *
mailbox,
const char *
context);
663static int imap_delete_old_greeting (
char *dir,
struct vm_state *vms);
666static void imap_logout(
const char *mailbox_id);
677#define SMDI_MWI_WAIT_TIMEOUT 1000
679#define COMMAND_TIMEOUT 5000
681#define VOICEMAIL_DIR_MODE 0777
682#define VOICEMAIL_FILE_MODE 0666
683#define CHUNKSIZE 65536
685#define VOICEMAIL_CONFIG "voicemail.conf"
686#define ASTERISK_USERNAME "asterisk"
691#define DEFAULT_LISTEN_CONTROL_FORWARD_KEY "#"
692#define DEFAULT_LISTEN_CONTROL_REVERSE_KEY "*"
693#define DEFAULT_LISTEN_CONTROL_PAUSE_KEY "0"
694#define DEFAULT_LISTEN_CONTROL_RESTART_KEY "2"
695#define DEFAULT_LISTEN_CONTROL_STOP_KEY "13456789"
696#define VALID_DTMF "1234567890*#"
700#define SENDMAIL "/usr/sbin/sendmail -t"
701#define INTRO "vm-intro"
703#define MAX_MAIL_BODY_CONTENT_SIZE 134217728L
706#define MAXMSGLIMIT 9999
716#define MAX_DATETIME_FORMAT 512
717#define MAX_NUM_CID_CONTEXTS 10
719#define VM_REVIEW (1 << 0)
720#define VM_OPERATOR (1 << 1)
721#define VM_SAYCID (1 << 2)
722#define VM_SVMAIL (1 << 3)
723#define VM_ENVELOPE (1 << 4)
724#define VM_SAYDURATION (1 << 5)
725#define VM_SKIPAFTERCMD (1 << 6)
726#define VM_FORCENAME (1 << 7)
727#define VM_FORCEGREET (1 << 8)
728#define VM_PBXSKIP (1 << 9)
729#define VM_DIRECTFORWARD (1 << 10)
730#define VM_ATTACH (1 << 11)
731#define VM_DELETE (1 << 12)
732#define VM_ALLOCED (1 << 13)
733#define VM_SEARCH (1 << 14)
734#define VM_TEMPGREETWARN (1 << 15)
735#define VM_MOVEHEARD (1 << 16)
736#define VM_MESSAGEWRAP (1 << 17)
737#define VM_FWDURGAUTO (1 << 18)
738#define VM_EMAIL_EXT_RECS (1 << 19)
739#define VM_MARK_URGENT (1 << 20)
740#define VM_ODBC_AUDIO_ON_DISK (1 << 21)
742#define ERROR_LOCK_PATH -100
743#define ERROR_MAX_MSGS -101
744#define OPERATOR_EXIT 300
746#define MSGFILE_LEN (7)
832#define force_reload_config() load_config_force(1, 1)
932#define MAX_VM_MBOX_ID_LEN (AST_MAX_EXTENSION)
933#define MAX_VM_CONTEXT_LEN (AST_MAX_CONTEXT)
935#define MAX_VM_MAILBOX_LEN (MAX_VM_MBOX_ID_LEN + MAX_VM_CONTEXT_LEN)
970 char imappassword[80];
972 char imapvmshareid[80];
987#define VMSTATE_MAX_MSG_ARRAY 256
1012 unsigned msg_array_max;
1013 MAILSTREAM *mailstream;
1016 char imapfolder[64];
1017 char imapserver[48];
1019 char imapflags[128];
1023 unsigned int quota_limit;
1024 unsigned int quota_usage;
1030static char odbc_database[80] =
"asterisk";
1031static char odbc_table[80] =
"voicemessages";
1032size_t odbc_table_len =
sizeof(odbc_table);
1033#define COUNT(a, b) odbc_count_messages(a,b)
1034#define LAST_MSG_INDEX(a) odbc_last_message_index(a)
1035#define RETRIEVE(a,b,c,d) odbc_retrieve_message(a,b)
1036#define DISPOSE(a,b) odbc_remove_files(a,b)
1037#define STORE(a,b,c,d,e,f,g,h,i,j,k) odbc_store_message(a,b,c,d)
1038#define EXISTS(a,b,c,d) (odbc_message_exists(a,b))
1039#define RENAME(a,b,c,d,e,f,g,h) (odbc_rename_message(a,b,c,d,e,f))
1040#define COPY(a,b,c,d,e,f,g,h) (odbc_copy_message(a,b,c,d,e,f))
1041#define DELETE(a,b,c,d) (odbc_delete_message(a,b))
1042#define UPDATE_MSG_ID(a, b, c, d, e, f) (odbc_update_msg_id((a), (b), (c)))
1045#define DISPOSE(a,b) (imap_remove_file(a,b))
1046#define STORE(a,b,c,d,e,f,g,h,i,j,k) (imap_store_file(a,b,c,d,e,f,g,h,i,j,k))
1047#define RETRIEVE(a,b,c,d) imap_retrieve_file(a,b,c,d)
1048#define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
1049#define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
1050#define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
1051#define DELETE(a,b,c,d) (vm_imap_delete(a,b,d))
1052#define UPDATE_MSG_ID(a, b, c, d, e, f) (vm_imap_update_msg_id((a), (b), (c), (d), (e), (f)))
1054#define COUNT(a, b) count_messages(a,b)
1055#define LAST_MSG_INDEX(a) last_message_index(a)
1056#define RETRIEVE(a,b,c,d)
1058#define STORE(a,b,c,d,e,f,g,h,i,j,k)
1059#define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
1060#define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
1061#define COPY(a,b,c,d,e,f,g,h) (copy_plain_file(g,h));
1062#define DELETE(a,b,c,d) (vm_delete(c))
1063#define UPDATE_MSG_ID(a, b, c, d, e, f)
1074#define PWDCHANGE_INTERNAL (1 << 1)
1075#define PWDCHANGE_EXTERNAL (1 << 2)
1079#define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
1082# define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
1084# define tdesc "Comedian Mail (Voicemail System)"
1130#define DEFAULT_POLL_FREQ 30
1153#define MAPPING_BUCKETS 511
1211static unsigned char adsifdn[4] =
"\x00\x00\x00\x0F";
1212static unsigned char adsisec[4] =
"\x9B\xDB\xF7\xAC";
1223 char *fmt,
int outsidecaller,
struct ast_vm_user *vmu,
int *duration,
int *sound_duration,
const char *unlockdir,
1224 signed char record_gain,
struct vm_state *vms,
char *
flag,
const char *msg_id,
int forwardintro);
1228static 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,
const char *msg_id);
1260static int vm_msg_forward(
const char *
from_mailbox,
const char *from_context,
const char *from_folder,
const char *to_mailbox,
const char *to_context,
const char *to_folder,
size_t num_msgs,
const char *msg_ids[],
int delete_old);
1261static int vm_msg_move(
const char *
mailbox,
const char *
context,
size_t num_msgs,
const char *oldfolder,
const char *old_msg_ids[],
const char *newfolder);
1265#ifdef TEST_FRAMEWORK
1266static int vm_test_destroy_user(
const char *
context,
const char *
mailbox);
1267static int vm_test_create_user(
const char *
context,
const char *
mailbox);
1315 if (strcmp(i->
mailbox, j->mailbox)) {
1323 int context_len = strlen(
context) + 1;
1324 int mailbox_len = strlen(
mailbox) + 1;
1339 if (!(i =
ao2_alloc(
sizeof(*i) + context_len + mailbox_len,
NULL))) {
1353#if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
1371 if (bufptr ==
buf + buflen - 1) {
1398static size_t get_msg_path_len(
const char *dir)
1412#define MAX_SOUND_EXTEN_LEN 12
1425static size_t get_msg_path_ext_len(
const char *dir)
1431 return strlen(dir) + 1 +
MSGFILE_LEN + MAX_SOUND_EXTEN_LEN + 1;
1455#define MAKE_FILE_PTRA(dir, msgnum) \
1457 size_t __len = get_msg_path_len(dir); \
1460 __var = ast_strdupa(dir); \
1462 __var = ast_alloca(__len); \
1463 snprintf(__var, __len, "%s/msg%04d", dir, msgnum); \
1497#define MAKE_FILE_EXT_PTRA(dir, msgnum, ext) \
1499 size_t __len = get_msg_path_ext_len(dir); \
1500 char *__var = ast_alloca(__len); \
1502 snprintf(__var, __len, "%s.%s", dir, ext); \
1504 snprintf(__var, __len, "%s/msg%04d.%s", dir, msgnum, ext); \
1555 ast_copy_string(vmu->imapfolder, imapfolder,
sizeof(vmu->imapfolder));
1556 ast_copy_string(vmu->imapserver, imapserver,
sizeof(vmu->imapserver));
1573 if (!strcasecmp(
var,
"attach")) {
1575 }
else if (!strcasecmp(
var,
"attachfmt")) {
1577 }
else if (!strcasecmp(
var,
"attachextrecs")) {
1579 }
else if (!strcasecmp(
var,
"serveremail")) {
1581 }
else if (!strcasecmp(
var,
"fromstring")) {
1583 }
else if (!strcasecmp(
var,
"emailbody")) {
1586 }
else if (!strcasecmp(
var,
"emailsubject")) {
1589 }
else if (!strcasecmp(
var,
"language")) {
1591 }
else if (!strcasecmp(
var,
"tz")) {
1593 }
else if (!strcasecmp(
var,
"locale")) {
1596 }
else if (!strcasecmp(
var,
"imapuser")) {
1598 vmu->imapversion = imapversion;
1599 }
else if (!strcasecmp(
var,
"imapserver")) {
1601 vmu->imapversion = imapversion;
1602 }
else if (!strcasecmp(
var,
"imapport")) {
1604 vmu->imapversion = imapversion;
1605 }
else if (!strcasecmp(
var,
"imapflags")) {
1607 vmu->imapversion = imapversion;
1608 }
else if (!strcasecmp(
var,
"imappassword") || !strcasecmp(
var,
"imapsecret")) {
1610 vmu->imapversion = imapversion;
1611 }
else if (!strcasecmp(
var,
"imapfolder")) {
1613 vmu->imapversion = imapversion;
1614 }
else if (!strcasecmp(
var,
"imapvmshareid")) {
1616 vmu->imapversion = imapversion;
1618 }
else if (!strcasecmp(
var,
"delete") || !strcasecmp(
var,
"deletevoicemail")) {
1620 }
else if (!strcasecmp(
var,
"saycid")){
1622 }
else if (!strcasecmp(
var,
"sendvoicemail")){
1624 }
else if (!strcasecmp(
var,
"review")){
1626 }
else if (!strcasecmp(
var,
"leaveurgent")){
1628 }
else if (!strcasecmp(
var,
"tempgreetwarn")){
1630 }
else if (!strcasecmp(
var,
"messagewrap")){
1632 }
else if (!strcasecmp(
var,
"operator")) {
1634 }
else if (!strcasecmp(
var,
"envelope")){
1636 }
else if (!strcasecmp(
var,
"moveheard")){
1638 }
else if (!strcasecmp(
var,
"sayduration")){
1640 }
else if (!strcasecmp(
var,
"saydurationm")){
1641 if (sscanf(
value,
"%30d", &x) == 1) {
1646 }
else if (!strcasecmp(
var,
"forcename")){
1648 }
else if (!strcasecmp(
var,
"forcegreetings")){
1650 }
else if (!strcasecmp(
var,
"callback")) {
1652 }
else if (!strcasecmp(
var,
"dialout")) {
1654 }
else if (!strcasecmp(
var,
"exitcontext")) {
1656 }
else if (!strcasecmp(
var,
"minsecs")) {
1657 if (sscanf(
value,
"%30d", &x) == 1 && x >= 0) {
1663 }
else if (!strcasecmp(
var,
"maxsecs")) {
1671 }
else if (!strcasecmp(
var,
"maxmsg")) {
1681 }
else if (!strcasecmp(
var,
"nextaftercmd")) {
1683 }
else if (!strcasecmp(
var,
"backupdeleted")) {
1684 if (sscanf(
value,
"%30d", &x) == 1)
1698 }
else if (!strcasecmp(
var,
"volgain")) {
1700 }
else if (!strcasecmp(
var,
"passwordlocation")) {
1701 if (!strcasecmp(
value,
"spooldir")) {
1706 }
else if (!strcasecmp(
var,
"options")) {
1713 int fds[2], pid = 0;
1718 snprintf(
buf,
len,
"FAILURE: Pipe failed: %s", strerror(
errno));
1727 snprintf(
buf,
len,
"FAILURE: Fork failed");
1731 if (read(fds[0],
buf,
len) < 0) {
1743 dup2(fds[1], STDOUT_FILENO);
1749 execv(arg.v[0], arg.v);
1750 printf(
"FAILURE: %s", strerror(
errno));
1773 char cmd[255],
buf[255];
1775 ast_debug(1,
"Verify password policies for %s\n", password);
1780 if (!strncasecmp(
buf,
"VALID", 5)) {
1783 }
else if (!strncasecmp(
buf,
"FAILURE", 7)) {
1808 if (!strcmp(vmu->
password, password)) {
1813 if (strlen(password) > 10) {
1833 while ((s =
strsep(&stringp,
"|"))) {
1849 if (!strcasecmp(
var->name,
"vmsecret")) {
1851 }
else if (!strcasecmp(
var->name,
"secret") || !strcasecmp(
var->name,
"password")) {
1855 "\n\tmust be reset in voicemail.conf.\n", retval->
mailbox);
1860 }
else if (!strcasecmp(
var->name,
"uniqueid")) {
1862 }
else if (!strcasecmp(
var->name,
"pager")) {
1864 }
else if (!strcasecmp(
var->name,
"email")) {
1867 }
else if (!strcasecmp(
var->name,
"fullname")) {
1869 }
else if (!strcasecmp(
var->name,
"context")) {
1871 }
else if (!strcasecmp(
var->name,
"emailsubject")) {
1874 }
else if (!strcasecmp(
var->name,
"emailbody")) {
1878 }
else if (!strcasecmp(
var->name,
"imapuser")) {
1880 retval->imapversion = imapversion;
1881 }
else if (!strcasecmp(
var->name,
"imapserver")) {
1883 retval->imapversion = imapversion;
1884 }
else if (!strcasecmp(
var->name,
"imapport")) {
1886 retval->imapversion = imapversion;
1887 }
else if (!strcasecmp(
var->name,
"imapflags")) {
1889 retval->imapversion = imapversion;
1890 }
else if (!strcasecmp(
var->name,
"imappassword") || !strcasecmp(
var->name,
"imapsecret")) {
1892 retval->imapversion = imapversion;
1893 }
else if (!strcasecmp(
var->name,
"imapfolder")) {
1895 retval->imapversion = imapversion;
1896 }
else if (!strcasecmp(
var->name,
"imapvmshareid")) {
1898 retval->imapversion = imapversion;
1917 for (i = 0; i < strlen(key); ++i) {
1942 if ((retval = (ivm ? ivm :
ast_calloc(1,
sizeof(*retval))))) {
1944 memset(retval, 0,
sizeof(*retval));
1989 if (cur->imapversion != imapversion) {
2000 if ((vmu = (ivm ? ivm :
ast_calloc(1,
sizeof(*vmu))))) {
2027 char *search_mailbox =
NULL;
2028 char *search_context =
NULL;
2032 vmu =
find_user(ivm, search_mailbox, search_context);
2071 "NewPassword", newpass);
2097 char *category =
NULL;
2098 const char *tmp =
NULL;
2112 ast_verb(4,
"Writing voicemail password to file %s succeeded\n", secretfn);
2117 ast_log(
LOG_WARNING,
"Writing voicemail password to file %s failed, falling back to config file\n", secretfn);
2123 if (!strcasecmp(category, vmu->
context)) {
2130 value = strstr(tmp,
",");
2133 sprintf(
new,
"%s", newpassword);
2136 sprintf(
new,
"%s%s", newpassword,
value);
2150 ast_test_suite_event_notify(
"PASSWORDCHANGED",
"Message: voicemail.conf updated with new password\r\nPasswordSource: voicemail.conf");
2207static int make_file(
char *dest,
const int len,
const char *dir,
const int num)
2209 return snprintf(dest,
len,
"%s/msg%04d", dir, num);
2236 if (vmu &&
id == 0) {
2237 return vmu->imapfolder;
2295 int arraysize = (vmu->
maxmsg > count_msg ? vmu->
maxmsg : count_msg);
2308 if (arraysize > 0) {
2326static void vm_imap_delete(
char *
file,
int msgnum,
struct ast_vm_user *vmu)
2330 unsigned long messageNum;
2333 if (msgnum < 0 && !imapgreetings) {
2338 if (!(vms = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 0))) {
2339 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);
2344 imap_delete_old_greeting(
file, vms);
2350 messageNum = vms->msgArray[msgnum];
2351 if (messageNum == 0) {
2352 ast_log(
LOG_WARNING,
"msgnum %d, mailbox message %lu is zero.\n", msgnum, messageNum);
2355 ast_debug(3,
"deleting msgnum %d, which is mailbox message %lu\n", msgnum, messageNum);
2357 snprintf (arg,
sizeof(arg),
"%lu", messageNum);
2359 mail_setflag (vms->mailstream, arg,
"\\DELETED");
2360 mail_expunge(vms->mailstream);
2364static void vm_imap_update_msg_id(
char *dir,
int msgnum,
const char *msg_id,
struct ast_vm_user *vmu,
struct ast_config *msg_cfg,
int folder)
2371 const char *duration_str;
2415 sscanf(duration_str,
"%30d", &duration);
2431 vm_imap_delete(dir, msgnum, vmu);
2437static int imap_retrieve_greeting(
const char *dir,
const int msgnum,
struct ast_vm_user *vmu)
2440 char *
file, *filename;
2450 if (msgnum > -1 || !imapgreetings) {
2457 ast_debug(1,
"Failed to procure file name from directory passed.\n");
2463 if (!(vms_p = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 1)) &&
2464 !(vms_p = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 0))) {
2469 if (!(vms_p = create_vm_state_from_user(vmu))) {
2476 *vms_p->introfn =
'\0';
2490 for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
2491 mail_fetchstructure(vms_p->mailstream, i + 1, &body);
2493 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
2494 char *attachment = body->nested.part->next->body.parameter->value;
2495 char copy[strlen(attachment) + 1];
2497 strcpy(
copy, attachment);
2500 filename =
strsep(&attachment,
".");
2501 if (!strcmp(filename,
file)) {
2503 vms_p->msgArray[vms_p->
curmsg] = i + 1;
2505 save_body(body, vms_p,
"2", attachment, 0);
2516 if (curr_mbox != -1) {
2518 if (init_mailstream(vms_p, curr_mbox) || !vms_p->mailstream) {
2527static int imap_retrieve_file(
const char *dir,
const int msgnum,
const char *
mailbox,
const char *
context)
2530 char *header_content;
2531 char *attachedfilefmt;
2535 FILE *text_file_ptr;
2546 if (imapgreetings) {
2547 res = imap_retrieve_greeting(dir, msgnum, vmu);
2558 if (!(vms = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 0))) {
2573 if (curr_mbox < 0) {
2574 ast_debug(3,
"Mailbox folder curbox not set, defaulting to Inbox\n");
2577 init_mailstream(vms, curr_mbox);
2578 if (!vms->mailstream) {
2585 snprintf(vms->introfn,
sizeof(vms->introfn),
"%sintro", vms->
fn);
2593 ast_debug(3,
"Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
2594 if (vms->msgArray[msgnum] == 0) {
2602 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
2606 ast_log(
LOG_ERROR,
"Could not fetch header for message number %ld\n", vms->msgArray[msgnum]);
2612 mail_fetchstructure(vms->mailstream, vms->msgArray[msgnum], &body);
2616 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
2617 attachedfilefmt =
ast_strdupa(body->nested.part->next->body.parameter->value);
2626 strsep(&attachedfilefmt,
".");
2627 if (!attachedfilefmt) {
2628 ast_log(
LOG_ERROR,
"File format could not be obtained from IMAP message attachment\n");
2633 save_body(body, vms,
"2", attachedfilefmt, 0);
2634 if (save_body(body, vms,
"3", attachedfilefmt, 1)) {
2635 *vms->introfn =
'\0';
2639 snprintf(text_file,
sizeof(text_file),
"%s.%s", vms->
fn,
"txt");
2641 if (!(text_file_ptr = fopen(text_file,
"w"))) {
2646 fprintf(text_file_ptr,
"%s\n",
"[message]");
2648 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Caller-ID-Name:",
buf,
sizeof(
buf))) {
2649 fprintf(text_file_ptr,
"callerid=\"%s\" ",
S_OR(
buf,
""));
2651 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Caller-ID-Num:",
buf,
sizeof(
buf))) {
2652 fprintf(text_file_ptr,
"<%s>\n",
S_OR(
buf,
""));
2654 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Context:",
buf,
sizeof(
buf))) {
2655 fprintf(text_file_ptr,
"context=%s\n",
S_OR(
buf,
""));
2657 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Orig-time:",
buf,
sizeof(
buf))) {
2658 fprintf(text_file_ptr,
"origtime=%s\n",
S_OR(
buf,
""));
2660 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Duration:",
buf,
sizeof(
buf))) {
2661 fprintf(text_file_ptr,
"duration=%s\n",
S_OR(
buf,
""));
2663 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Category:",
buf,
sizeof(
buf))) {
2664 fprintf(text_file_ptr,
"category=%s\n",
S_OR(
buf,
""));
2666 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Flag:",
buf,
sizeof(
buf))) {
2667 fprintf(text_file_ptr,
"flag=%s\n",
S_OR(
buf,
""));
2669 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Message-ID:",
buf,
sizeof(
buf))) {
2670 fprintf(text_file_ptr,
"msg_id=%s\n",
S_OR(
buf,
""));
2672 fclose(text_file_ptr);
2679static int folder_int(
const char *folder)
2685 if (!strcasecmp(folder, imapfolder)) {
2687 }
else if (!strcasecmp(folder,
"Old")) {
2689 }
else if (!strcasecmp(folder,
"Work")) {
2691 }
else if (!strcasecmp(folder,
"Family")) {
2693 }
else if (!strcasecmp(folder,
"Friends")) {
2695 }
else if (!strcasecmp(folder,
"Cust1")) {
2697 }
else if (!strcasecmp(folder,
"Cust2")) {
2699 }
else if (!strcasecmp(folder,
"Cust3")) {
2701 }
else if (!strcasecmp(folder,
"Cust4")) {
2703 }
else if (!strcasecmp(folder,
"Cust5")) {
2705 }
else if (!strcasecmp(folder,
"Urgent")) {
2712static int __messagecount(
const char *
context,
const char *
mailbox,
const char *folder)
2720 int fold = folder_int(folder);
2733 memset(&vmus, 0,
sizeof(vmus));
2741 if (vmu->imapuser[0] ==
'\0') {
2749 if (vmu->imapuser[0] ==
'\0') {
2756 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1);
2761 ast_debug(3,
"Returning before search - user is logged in\n");
2773 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 0);
2779 vms_p = create_vm_state_from_user(vmu);
2781 ret = init_mailstream(vms_p, fold);
2782 if (!vms_p->mailstream) {
2789 pgm = mail_newsearchpgm ();
2790 hdr = mail_newsearchheader (
"X-Asterisk-VM-Extension", (
char *)(!
ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid :
mailbox));
2791 hdr->next = mail_newsearchheader(
"X-Asterisk-VM-Context", (
char *)
S_OR(
context,
"default"));
2817 vms_p->vmArrayIndex = 0;
2818 mail_search_full (vms_p->mailstream,
NULL, pgm, NIL);
2819 if (fold == 0 && urgent == 0)
2823 if (fold == 0 && urgent == 1)
2826 mail_free_searchpgm(&pgm);
2830 return vms_p->vmArrayIndex;
2833 mail_ping(vms_p->mailstream);
2843 check_quota(vms, vmu->imapfolder);
2844 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
2845 ast_debug(1,
"*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
2855 ast_log(
LOG_WARNING,
"Unable to leave message since we will exceed the maximum number of messages allowed (%u >= %u)\n", msgnum, vmu->
maxmsg);
2874static int messagecount(
const char *mailbox_id,
const char *folder)
2890 return count < 0 ? 0 : count;
2893static 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,
const char *msg_id)
2901 char tmp[80] =
"/tmp/astmail-XXXXXX";
2907 char *imap_flags = NIL;
2916 if(!imapgreetings) {
2923 if (imap_check_limits(chan, vms, vmu, msgcount)) {
2929 ast_debug(3,
"Setting message flag \\\\FLAGGED.\n");
2930 imap_flags =
"\\FLAGGED";
2946 snprintf(introfn,
sizeof(introfn),
"%sintro",
fn);
2961 if (!strcmp(fmt,
"wav49"))
2963 ast_debug(3,
"Storing file '%s', format '%s'\n",
fn, fmt);
2976 if (msgnum < 0 && imapgreetings) {
2981 imap_delete_old_greeting(
fn, vms);
2987 fn, introfn, fmt, duration, 1, chan,
NULL, 1,
flag, msg_id);
2995 *(vmu->
email) =
'\0';
3004 ((
char *)
buf)[
len] =
'\0';
3006 ret = init_mailstream(vms, box);
3010 if(!mail_append_full(vms->mailstream,
mailbox, imap_flags, NIL, &
str))
3026 *(vmu->
email) =
'\0';
3045static int inboxcount2(
const char *mailbox_context,
int *urgentmsgs,
int *newmsgs,
int *oldmsgs)
3060 ast_debug(3,
"Mailbox is set to %s\n", mailbox_context);
3067 if (strchr(mailbox_context,
',')) {
3068 int tmpnew, tmpold, tmpurgent;
3071 while ((cur =
strsep(&mb,
", "))) {
3081 *urgentmsgs += tmpurgent;
3093 mailboxnc = (
char *) mailbox_context;
3102 if ((count = __messagecount(
context, mailboxnc, vmu->imapfolder)) < 0) {
3110 if ((count = __messagecount(
context, mailboxnc,
"Old")) < 0) {
3116 if ((count = __messagecount(
context, mailboxnc,
"Urgent")) < 0) {
3119 *urgentmsgs = count;
3136 char tmp[256], *tmp2, *box, *
context;
3139 if (strchr(tmp2,
',') || strchr(tmp2,
'&')) {
3140 while ((box =
strsep(&tmp2,
",&"))) {
3148 if ((
context = strchr(tmp,
'@'))) {
3153 return __messagecount(
context, tmp, folder) > 0 ? 1 : 0;
3175 char messagestring[10];
3176 if (msgnum >= recip->
maxmsg) {
3180 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
3184 if (!get_vm_state_by_imapuser(recip->imapuser, 0)) {
3188 snprintf(messagestring,
sizeof(messagestring),
"%ld", sendvms->msgArray[msgnum]);
3190 if ((mail_copy(sendvms->mailstream, messagestring, (
char *)
mbox(vmu, imbox)) == T)) {
3199static void imap_mailbox_name(
char *spec,
size_t len,
struct vm_state *vms,
int box,
int use_folder)
3201 char tmp[256], *t = tmp;
3202 size_t left =
sizeof(tmp);
3235 snprintf(spec,
len,
"%s%s", tmp, use_folder? vms->imapfolder:
"INBOX");
3237 snprintf(spec,
len,
"%s%s", tmp, greetingfolder);
3241 snprintf(spec,
len,
"%s%s%c%s", tmp, imapparentfolder, delimiter,
mbox(
NULL, box));
3243 snprintf(spec,
len,
"%s%s", tmp,
mbox(
NULL, box));
3248static int init_mailstream(
struct vm_state *vms,
int box)
3250 MAILSTREAM *stream = NIL;
3258 ast_debug(3,
"vm_state user is:%s\n", vms->imapuser);
3259 if (vms->mailstream == NIL || !vms->mailstream) {
3262 stream = vms->mailstream;
3267 if (delimiter ==
'\0') {
3269#ifdef USE_SYSTEM_IMAP
3270#include <imap/linkage.c>
3271#elif defined(USE_SYSTEM_CCLIENT)
3272#include <c-client/linkage.c>
3277 imap_mailbox_name(tmp,
sizeof(tmp), vms, 0, 1);
3280 stream = mail_open (stream, tmp,
debug ? OP_DEBUG : NIL);
3283 if (stream == NIL) {
3287 get_mailbox_delimiter(vms, stream);
3289 for (cp = vms->imapfolder; *cp; cp++)
3294 imap_mailbox_name(tmp,
sizeof(tmp), vms, box, 1);
3295 ast_debug(3,
"Before mail_open, server: %s, box:%d\n", tmp, box);
3298 vms->mailstream = mail_open (stream, tmp,
debug ? OP_DEBUG : NIL);
3300 if (vms->mailstream && !mail_status(vms->mailstream, tmp, SA_UIDNEXT)) {
3301 mail_create(vms->mailstream, tmp);
3305 if (vms->mailstream == NIL) {
3325 ast_copy_string(vms->imapfolder, vmu->imapfolder,
sizeof(vms->imapfolder));
3326 ast_copy_string(vms->imapserver, vmu->imapserver,
sizeof(vms->imapserver));
3328 ast_copy_string(vms->imapflags, vmu->imapflags,
sizeof(vms->imapflags));
3329 vms->imapversion = vmu->imapversion;
3330 ast_debug(3,
"Before init_mailstream, user is %s\n", vmu->imapuser);
3332 if (init_mailstream(vms, box) || !vms->mailstream) {
3341 ast_debug(3,
"Mailbox name set to: %s, about to check quotas\n",
mbox(vmu, box));
3342 check_quota(vms, (
char *)
mbox(vmu, box));
3346 pgm = mail_newsearchpgm();
3349 hdr = mail_newsearchheader(
"X-Asterisk-VM-Extension", (!
ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->
mailbox));
3350 hdr->next = mail_newsearchheader(
"X-Asterisk-VM-Context", vmu->
context);
3361 }
else if (box ==
NEW_FOLDER && urgent == 0) {
3371 ast_debug(3,
"Before mail_search_full, user is %s\n", vmu->imapuser);
3373 vms->vmArrayIndex = 0;
3374 mail_search_full (vms->mailstream,
NULL, pgm, NIL);
3375 vms->
lastmsg = vms->vmArrayIndex - 1;
3376 mail_free_searchpgm(&pgm);
3382 ast_log(
LOG_WARNING,
"The code expects the old messages to be checked first, fix the code.\n");
3393static void write_file(
char *filename,
char *buffer,
unsigned long len)
3397 if (!filename || !buffer) {
3401 if (!(output = fopen(filename,
"w"))) {
3406 if (fwrite(buffer,
len, 1, output) != 1) {
3407 if (ferror(output)) {
3414static void update_messages_by_imapuser(
const char *
user,
unsigned long number)
3416 struct vm_state *vms = get_vm_state_by_imapuser(
user, 1);
3418 if (!vms && !(vms = get_vm_state_by_imapuser(
user, 0))) {
3422 ast_debug(3,
"saving mailbox message number %lu as message %d. Interactive set to %d\n",
number, vms->vmArrayIndex, vms->interactive);
3425 if (vms->vmArrayIndex >= vms->msg_array_max) {
3426 long *new_mem =
ast_realloc(vms->msgArray, 2 * vms->msg_array_max *
sizeof(
long));
3430 vms->msgArray = new_mem;
3431 vms->msg_array_max *= 2;
3434 vms->msgArray[vms->vmArrayIndex++] =
number;
3437void mm_searched(MAILSTREAM *stream,
unsigned long number)
3447static struct ast_vm_user *find_user_realtime_imapuser(
const char *imapuser)
3472void mm_exists(MAILSTREAM * stream,
unsigned long number)
3481void mm_expunged(MAILSTREAM * stream,
unsigned long number)
3490void mm_flags(MAILSTREAM * stream,
unsigned long number)
3499void mm_notify(MAILSTREAM * stream,
char *
string,
long errflg)
3501 ast_debug(5,
"Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg,
string);
3502 mm_log (
string, errflg);
3506void mm_list(MAILSTREAM * stream,
int delim,
char *
mailbox,
long attributes)
3508 if (delimiter ==
'\0') {
3513 if (attributes & LATT_NOINFERIORS)
3515 if (attributes & LATT_NOSELECT)
3517 if (attributes & LATT_MARKED)
3519 if (attributes & LATT_UNMARKED)
3524void mm_lsub(MAILSTREAM * stream,
int delim,
char *
mailbox,
long attributes)
3527 if (attributes & LATT_NOINFERIORS)
3529 if (attributes & LATT_NOSELECT)
3531 if (attributes & LATT_MARKED)
3533 if (attributes & LATT_UNMARKED)
3538void mm_status(MAILSTREAM * stream,
char *
mailbox, MAILSTATUS *
status)
3547 if (
status->flags & SA_MESSAGES) {
3550 if (
status->flags & SA_RECENT) {
3553 if (
status->flags & SA_UNSEEN) {
3556 if (
status->flags & SA_UIDVALIDITY) {
3559 if (
status->flags & SA_UIDNEXT) {
3568void mm_log(
char *
string,
long errflg)
3570 switch ((
short) errflg) {
3572 ast_debug(1,
"IMAP Info: %s\n",
string);
3585void mm_dlog(
char *
string)
3591void mm_login(NETMBX * mb,
char *
user,
char *pwd,
long trial)
3595 ast_debug(4,
"Entering callback mm_login\n");
3604 if (!strcasecmp(mb->user, vmu->imapuser)) {
3610 if ((vmu = find_user_realtime_imapuser(mb->user))) {
3619void mm_critical(MAILSTREAM * stream)
3624void mm_nocritical(MAILSTREAM * stream)
3629long mm_diskerror(MAILSTREAM * stream,
long errcode,
long serious)
3631 kill (getpid (), SIGSTOP);
3636void mm_fatal(
char *
string)
3642static void mm_parsequota(MAILSTREAM *stream,
unsigned char *msg, QUOTALIST *pquota)
3646 char buf[1024] =
"";
3647 unsigned long usage = 0, limit = 0;
3650 usage = pquota->usage;
3651 limit = pquota->limit;
3652 pquota = pquota->next;
3655 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)))) {
3662 vms->quota_usage =
usage;
3663 vms->quota_limit = limit;
3666static char *get_header_by_tag(
char *
header,
char *tag,
char *
buf,
size_t len)
3668 char *start, *eol_pnt;
3674 taglen = strlen(tag) + 1;
3685 if ((eol_pnt = strchr(
buf,
'\r')) || (eol_pnt = strchr(
buf,
'\n')))
3690static char *get_user_by_mailbox(
char *
mailbox,
char *
buf,
size_t len)
3692 char *start, *eol_pnt, *
quote;
3697 if (!(start = strstr(
mailbox,
"/user=")))
3703 if ((eol_pnt = strchr(
buf,
'/')) || (eol_pnt = strchr(
buf,
'}'))) {
3708 if ((eol_pnt = strchr(
quote + 1,
'"'))) {
3719 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
3720 if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->
username, vmu->
mailbox)) {
3723 ast_debug(5,
"Adding new vmstate for %s\n", vmu->imapuser);
3725 if (!(vms_p =
ast_calloc(1,
sizeof(*vms_p))))
3727 ast_copy_string(vms_p->imapuser, vmu->imapuser,
sizeof(vms_p->imapuser));
3728 ast_copy_string(vms_p->imapfolder, vmu->imapfolder,
sizeof(vms_p->imapfolder));
3729 ast_copy_string(vms_p->imapserver, vmu->imapserver,
sizeof(vms_p->imapserver));
3730 ast_copy_string(vms_p->imapport, vmu->imapport,
sizeof(vms_p->imapport));
3731 ast_copy_string(vms_p->imapflags, vmu->imapflags,
sizeof(vms_p->imapflags));
3734 vms_p->mailstream = NIL;
3735 vms_p->imapversion = vmu->imapversion;
3736 ast_debug(5,
"Copied %s to %s\n", vmu->imapuser, vms_p->imapuser);
3740 init_vm_state(vms_p);
3741 vmstate_insert(vms_p);
3745static struct vm_state *get_vm_state_by_imapuser(
const char *
user,
int interactive)
3747 struct vmstate *vlist =
NULL;
3751 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
3752 if ((vms = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms->imapuser,
user)) {
3763 if (vlist->vms->imapversion != imapversion) {
3767 if (!strcmp(vlist->vms->imapuser,
user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
3779static struct vm_state *get_vm_state_by_mailbox(
const char *
mailbox,
const char *
context,
int interactive)
3782 struct vmstate *vlist =
NULL;
3783 const char *local_context =
S_OR(
context,
"default");
3787 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
3788 if ((vms = pthread_getspecific(ts_vmstate.key)) &&
3800 if (vlist->vms->imapversion != imapversion) {
3804 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);
3806 if (!strcmp(vlist->vms->username,
mailbox) && !strcmp(vlist->vms->context, local_context) && vlist->vms->interactive == interactive) {
3819static void vmstate_insert(
struct vm_state *vms)
3827 if (vms->interactive == 1) {
3833 vms->vmArrayIndex = altvms->vmArrayIndex;
3838 vms->persist_vms = altvms;
3840#ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
3841 vms->mailstream = altvms->mailstream;
3843 vms->mailstream = NIL;
3854 ast_debug(3,
"Inserting vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->
username);
3861static void vmstate_delete(
struct vm_state *vms)
3863 struct vmstate *vc =
NULL;
3868 if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
3872 altvms->updated = 1;
3873 vms->mailstream = mail_close(vms->mailstream);
3879 ast_debug(3,
"Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->
username);
3883 if (vc->vms == vms) {
3894 vc->vms->msgArray =
NULL;
3895 vc->vms->msg_array_max = 0;
3903static void set_update(MAILSTREAM * stream)
3907 char buf[1024] =
"";
3909 if (!(
user = get_user_by_mailbox(
mailbox,
buf,
sizeof(
buf))) || !(vms = get_vm_state_by_imapuser(
user, 0))) {
3920static void init_vm_state(
struct vm_state *vms)
3923 vms->msgArray =
ast_calloc(vms->msg_array_max,
sizeof(
long));
3924 if (!vms->msgArray) {
3926 vms->msg_array_max = 0;
3928 vms->vmArrayIndex = 0;
3932static int save_body(BODY *body,
struct vm_state *vms,
char *section,
char *format,
int is_intro)
3936 char *
fn = is_intro ? vms->introfn : vms->
fn;
3937 unsigned long len = 0;
3938 unsigned long newlen = 0;
3941 if (!body || body == NIL)
3945 body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->
curmsg], section, &
len);
3949 "Msgno %ld, section %s. The body's content size %ld is huge (max %ld). User:%s, mailbox %s\n",
3953 if (body_content != NIL &&
len) {
3954 snprintf(filename,
sizeof(filename),
"%s.%s",
fn, format);
3956 body_decoded = rfc822_base64((
unsigned char *) body_content,
len, &newlen);
3958 if (!newlen || !body_decoded) {
3961 write_file(filename, (
char *) body_decoded, newlen);
3963 ast_debug(5,
"Body of message is NULL.\n");
3977static void get_mailbox_delimiter(
struct vm_state *vms, MAILSTREAM *stream) {
3979 snprintf(tmp,
sizeof(tmp),
"{%s}",
S_OR(vms->imapserver, imapserver));
3980 mail_list(stream, tmp,
"*");
3992 mail_parameters(
NULL, SET_QUOTA, (
void *) mm_parsequota);
3994 if (vms && vms->mailstream !=
NULL) {
3995 imap_getquotaroot(vms->mailstream,
mailbox);
4018#define MSG_ID_LEN 256
4041#define MAKE_SQL_PTRA(__sql_fmt) \
4044 char *__sql = ast_alloca(strlen(__sql_fmt) + odbc_table_len); \
4045 sprintf(__sql, __sql_fmt, odbc_table); \
4059#define MAKE_SQL_PTRA2(__sql_fmt) \
4062 char *__sql = ast_alloca(strlen(__sql_fmt) + (odbc_table_len * 2)); \
4063 sprintf(__sql, __sql_fmt, odbc_table, odbc_table); \
4067struct generic_prepare_struct {
4075 struct generic_prepare_struct *gps = data;
4079 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->
con, &stmt);
4080 if (!SQL_SUCCEEDED(res)) {
4085 if (!SQL_SUCCEEDED(res)) {
4087 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4090 for (i = 0; i < gps->argc; i++)
4091 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0,
NULL);
4096static void odbc_update_msg_id(
char *dir,
int msg_num,
char *msg_id)
4099 char *sql = MAKE_SQL_PTRA(
"UPDATE %s SET msg_id=? WHERE dir=? AND msgnum=?");
4101 char msg_num_str[20];
4102 char *argv[] = { msg_id, dir, msg_num_str };
4103 struct generic_prepare_struct gps = { .sql = sql, .argc = 3, .argv = argv };
4104 SCOPE_ENTER(3,
"dir: %s msg_num: %d msg_id: %s\n", dir, msg_num, msg_id);
4111 snprintf(msg_num_str,
sizeof(msg_num_str),
"%d", msg_num);
4116 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4122#define AUDIO_ON_DISK_MAGIC "AUDMAGIC"
4123#define AUDIO_ON_DISK_MAGIC_LEN 8
4125static void odbc_update_set_audmagic(
char *dir,
int msg_num)
4128 char *sql = MAKE_SQL_PTRA(
"UPDATE %s SET recording=? WHERE dir=? AND msgnum=?");
4130 SQLLEN datalen = AUDIO_ON_DISK_MAGIC_LEN;
4131 SQLLEN indlen = datalen;
4133 char msg_num_str[20];
4134 SCOPE_ENTER(3,
"dir: %s msg_num: %d\n", dir, msg_num);
4141 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->
con, &stmt);
4142 if (!SQL_SUCCEEDED(res)) {
4147 snprintf(msg_num_str,
sizeof(msg_num_str),
"%d", msg_num);
4149 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY,
4150 datalen, 0, (
void *) AUDIO_ON_DISK_MAGIC,
4153 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR,
4154 strlen(dir), 0, (
void *) dir, 0,
NULL);
4156 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR,
4157 strlen(msg_num_str), 0, (
void *) msg_num_str, 0,
NULL);
4160 if (!SQL_SUCCEEDED(res)) {
4164 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4171static int odbc_store_message(
const char *dir,
const char *mailboxuser,
const char *mailboxcontext,
int msgnum);
4187static int odbc_retrieve_message(
char *dir,
int msgnum)
4193 void *fdm = MAP_FAILED;
4194 SQLSMALLINT colcount = 0;
4196 char *sql = MAKE_SQL_PTRA(
"SELECT * FROM %s WHERE dir=? AND msgnum=?");
4201 SQLSMALLINT datatype;
4202 SQLSMALLINT decimaldigits;
4203 SQLSMALLINT nullable;
4208 char *fn = MAKE_FILE_PTRA(dir, msgnum);
4209 char *full_fn = MAKE_FILE_EXT_PTRA(dir, msgnum,
"txt");
4211 char *mailboxuser =
NULL;
4212 char *mailboxcontext =
NULL;
4214 char *argv[] = { dir, msgnums };
4215 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
4217 int storage_conversion_to_disk = 0;
4218 int storage_conversion_to_odbc = 0;
4219 SCOPE_ENTER(3,
"dir: %s msgnum: %d msgtype: %s\n", dir, msgnum, msgnum < 0 ?
"Greeting" :
"Message");
4227 c = strchr(fmt,
'|');
4230 if (!strcasecmp(fmt,
"wav49"))
4233 snprintf(msgnums,
sizeof(msgnums),
"%d", msgnum);
4235 ast_trace(-1,
"Opening '%s' for writing\n", full_fn);
4236 if (!(f = fopen(full_fn,
"w+"))) {
4241 sprintf(full_fn,
"%s.%s", fn, fmt);
4249 res = SQLFetch(stmt);
4250 if (!SQL_SUCCEEDED(res)) {
4251 if (res != SQL_NO_DATA) {
4254 goto bail_with_handle;
4257 res = SQLNumResultCols(stmt, &colcount);
4258 if (!SQL_SUCCEEDED(res)) {
4260 goto bail_with_handle;
4263 fprintf(f,
"[message]\n");
4264 for (x = 0; x < colcount; x++) {
4267 collen =
sizeof(coltitle);
4268 res = SQLDescribeCol(stmt, x + 1, (
unsigned char *) coltitle,
sizeof(coltitle), &collen,
4269 &datatype, &colsize, &decimaldigits, &nullable);
4270 if (!SQL_SUCCEEDED(res)) {
4272 goto bail_with_handle;
4275 if (!strcasecmp(coltitle,
"recording")) {
4279 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
4281 ast_trace(-1,
"Audio size: %ld\n", colsize2);
4282 if (colsize2 == AUDIO_ON_DISK_MAGIC_LEN) {
4283 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, AUDIO_ON_DISK_MAGIC_LEN,
NULL);
4284 if (memcmp(rowdata, AUDIO_ON_DISK_MAGIC, AUDIO_ON_DISK_MAGIC_LEN) != 0) {
4286 rowdata[0], rowdata[1], rowdata[2], rowdata[3], rowdata[4], rowdata[5], rowdata[6],
4287 rowdata[7], full_fn);
4288 goto bail_with_handle;
4290 ast_trace(-1,
"Audio is stored on disk. No need to write '%s'\n", full_fn);
4292 storage_conversion_to_odbc = 1;
4298 ast_trace(-1,
"Opening '%s' for writing\n", full_fn);
4302 goto bail_with_handle;
4305 storage_conversion_to_disk = 1;
4308 lseek(fd, fdlen - 1, SEEK_SET);
4309 if (write(fd, tmp, 1) != 1) {
4315 for (offset = 0; offset < colsize2; offset +=
CHUNKSIZE) {
4316 if ((fdm = mmap(
NULL,
CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
4318 goto bail_with_handle;
4320 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm,
CHUNKSIZE,
NULL);
4322 if (!SQL_SUCCEEDED(res)) {
4325 goto bail_with_handle;
4328 if (truncate(full_fn, fdlen) < 0) {
4331 ast_trace(-1,
"Wrote %d bytes to '%s'\n", (
int)fdlen, full_fn);
4333 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata,
sizeof(rowdata),
NULL);
4334 if (res == SQL_NULL_DATA && !strcasecmp(coltitle,
"msg_id")) {
4340 ast_trace(-1,
"msg_id was NULL. Generating new one: %s\n", msg_id);
4341 snprintf(rowdata,
sizeof(rowdata),
"%s", msg_id);
4342 }
else if (!strcasecmp(coltitle,
"mailboxuser")) {
4344 }
else if (!strcasecmp(coltitle,
"mailboxcontext")) {
4346 }
else if (res == SQL_NULL_DATA && !strcasecmp(coltitle,
"category")) {
4348 ast_trace(-1,
"Ignoring null category column in ODBC voicemail retrieve_file.\n");
4350 }
else if (!SQL_SUCCEEDED(res)) {
4352 goto bail_with_handle;
4354 if (strcasecmp(coltitle,
"msgnum") && strcasecmp(coltitle,
"dir")) {
4355 fprintf(f,
"%s=%s\n", coltitle, rowdata);
4361 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4375 odbc_update_msg_id(dir, msgnum, msg_id);
4378 if (SQL_SUCCEEDED(res)) {
4379 if (storage_conversion_to_disk) {
4385 SCOPE_CALL(-1, odbc_update_set_audmagic, dir, msgnum);
4387 if (storage_conversion_to_odbc) {
4394 SCOPE_CALL(-1, odbc_store_message, dir, mailboxuser, mailboxcontext, msgnum);
4410static int odbc_last_message_index(
char *dir)
4415 char *sql = MAKE_SQL_PTRA(
"SELECT msgnum FROM %s WHERE dir=? order by msgnum desc");
4417 char *argv[] = { dir };
4418 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
4433 res = SQLFetch(stmt);
4434 if (!SQL_SUCCEEDED(res)) {
4435 if (res == SQL_NO_DATA) {
4436 ast_trace(-1,
"Directory '%s' has no messages and therefore no index was retrieved.\n", dir);
4440 goto bail_with_handle;
4443 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata,
sizeof(rowdata),
NULL);
4444 if (!SQL_SUCCEEDED(res)) {
4446 goto bail_with_handle;
4449 if (sscanf(rowdata,
"%30d", &x) != 1) {
4454 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4471static int odbc_message_exists(
char *dir,
int msgnum)
4476 char *sql = MAKE_SQL_PTRA(
"SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?");
4479 char *argv[] = { dir, msgnums };
4480 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
4482 SCOPE_ENTER(3,
"dir: %s msgnum: %d\n", dir, msgnum);
4489 snprintf(msgnums,
sizeof(msgnums),
"%d", msgnum);
4496 res = SQLFetch(stmt);
4497 if (!SQL_SUCCEEDED(res)) {
4499 goto bail_with_handle;
4502 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata,
sizeof(rowdata),
NULL);
4503 if (!SQL_SUCCEEDED(res)) {
4505 goto bail_with_handle;
4508 if (sscanf(rowdata,
"%30d", &x) != 1) {
4513 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4529static int odbc_count_messages(
struct ast_vm_user *vmu,
char *dir)
4534 char *sql = MAKE_SQL_PTRA(
"SELECT COUNT(*) FROM %s WHERE dir=?");
4536 char *argv[] = { dir };
4537 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
4552 res = SQLFetch(stmt);
4553 if (!SQL_SUCCEEDED(res)) {
4555 goto bail_with_handle;
4558 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata,
sizeof(rowdata),
NULL);
4559 if (!SQL_SUCCEEDED(res)) {
4561 goto bail_with_handle;
4564 if (sscanf(rowdata,
"%30d", &x) != 1) {
4569 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4584#define DELETE_SQL_FMT "DELETE FROM %s WHERE dir=? AND msgnum=?"
4585static void odbc_delete_message(
const char *sdir,
int smsg)
4588 char *sql = MAKE_SQL_PTRA(DELETE_SQL_FMT);
4590 char *argv[] = {
NULL, msgnums };
4591 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
4593 SCOPE_ENTER(3,
"sdir: %s smsg: %d\n", sdir, smsg);
4602 snprintf(msgnums,
sizeof(msgnums),
"%d", smsg);
4607 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4612 char *src_fn = MAKE_FILE_PTRA(sdir, smsg);
4613 ast_trace(-1,
"Audio stored on disk. Deleting '%s'\n", src_fn);
4631#define COPY_SQL_FMT "INSERT INTO %s (dir, msgnum, msg_id, context, callerid, origtime, " \
4632 "duration, recording, flag, mailboxuser, mailboxcontext) " \
4633 "SELECT ?,?,msg_id,context,callerid,origtime,duration,recording,flag,?,? " \
4634 "FROM %s WHERE dir=? AND msgnum=?"
4635static void odbc_copy_message(
char *sdir,
int smsg,
char *ddir,
int dmsg,
char *dmailboxuser,
char *dmailboxcontext)
4638 char *sql = MAKE_SQL_PTRA2(COPY_SQL_FMT);
4642 char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums };
4643 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
4644 SCOPE_ENTER(3,
"sdir: %s smsg: %d duser: %s dcontext: %s ddir: %s dmsg: %d\n",
4645 sdir, smsg, dmailboxuser, dmailboxcontext, ddir, dmsg);
4647 SCOPE_CALL(-1, odbc_delete_message, ddir, dmsg);
4654 snprintf(msgnums,
sizeof(msgnums),
"%d", smsg);
4655 snprintf(msgnumd,
sizeof(msgnumd),
"%d", dmsg);
4659 ast_log(
AST_LOG_WARNING,
"SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
4661 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4665 char *src_fn = MAKE_FILE_PTRA(sdir, smsg);
4666 char *dst_fn = MAKE_FILE_PTRA(ddir, dmsg);
4668 ast_trace(-1,
"Audio stored on disk. Copying '%s' to '%s'\n", src_fn, dst_fn);
4678 const char *msgnums;
4683 const char *callerid;
4684 const char *origtime;
4685 const char *duration;
4686 const char *mailboxuser;
4687 const char *mailboxcontext;
4688 const char *category;
4693#define STORE_SQL_FMT_CAT "INSERT INTO %s (dir, msgnum, recording, context, callerid, " \
4694 "origtime, duration, mailboxuser, mailboxcontext, flag, msg_id, category) " \
4695 "VALUES (?,?,?,?,?,?,?,?,?,?,?,?)"
4696#define STORE_SQL_FMT "INSERT INTO %s (dir, msgnum, recording, context, callerid, "\
4697 "origtime, duration, mailboxuser, mailboxcontext, flag, msg_id) "\
4698 "VALUES (?,?,?,?,?,?,?,?,?,?,?)"
4700static SQLHSTMT odbc_insert_data_cb(
struct odbc_obj *obj,
void *vdata)
4702 struct insert_data *data = vdata;
4707 SCOPE_ENTER(3,
"dir: %s msgnums: %s msg_id: %s\n", data->dir, data->msgnums,
4710 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->
con, &stmt);
4711 if (!SQL_SUCCEEDED(res)) {
4716 delete_sql = MAKE_SQL_PTRA(DELETE_SQL_FMT);
4717 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->dir), 0, (
void *) data->dir, 0,
NULL);
4718 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msgnums), 0, (
void *) data->msgnums, 0,
NULL);
4720 if (!SQL_SUCCEEDED(res)) {
4721 ast_trace(-1,
"There wasn't an existing row. Good.\n");
4723 ast_trace(-1,
"There WAS an existing row. This is OK if we're replacing a message.\n");
4725 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4728 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->
con, &stmt);
4729 if (!SQL_SUCCEEDED(res)) {
4733 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->dir), 0, (
void *) data->dir, 0,
NULL);
4734 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msgnums), 0, (
void *) data->msgnums, 0,
NULL);
4735 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, data->datalen, 0, (
void *) data->data, data->datalen, &data->indlen);
4736 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->context), 0, (
void *) data->context, 0,
NULL);
4737 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->callerid), 0, (
void *) data->callerid, 0,
NULL);
4738 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->origtime), 0, (
void *) data->origtime, 0,
NULL);
4739 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->duration), 0, (
void *) data->duration, 0,
NULL);
4740 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxuser), 0, (
void *) data->mailboxuser, 0,
NULL);
4741 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxcontext), 0, (
void *) data->mailboxcontext, 0,
NULL);
4742 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->flag), 0, (
void *) data->flag, 0,
NULL);
4743 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msg_id), 0, (
void *) data->msg_id, 0,
NULL);
4745 insert_sql = MAKE_SQL_PTRA(STORE_SQL_FMT_CAT);
4746 SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (
void *) data->category, 0,
NULL);
4748 insert_sql = MAKE_SQL_PTRA(STORE_SQL_FMT);
4751 if (!SQL_SUCCEEDED(res)) {
4754 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4774static int odbc_store_message(
const char *dir,
const char *mailboxuser,
const char *mailboxcontext,
int msgnum)
4778 void *fdm = MAP_FAILED;
4782 char *fn = MAKE_FILE_PTRA(dir, msgnum);
4783 char *full_fn = MAKE_FILE_EXT_PTRA(dir, msgnum,
"txt");
4788 struct insert_data idata = { .msgnums = msgnums, .dir = dir, .mailboxuser = mailboxuser, .mailboxcontext = mailboxcontext,
4789 .context =
"", .callerid =
"", .origtime =
"", .duration =
"", .category =
"", .flag =
"", .msg_id =
"" };
4791 SCOPE_ENTER(3,
"dir: %s user: %s context: %s msgnum: %d msgtype: %s\n",
4792 dir, mailboxuser, mailboxcontext, msgnum, msgnum < 0 ?
"Greeting" :
"Message");
4801 c = strchr(fmt,
'|');
4804 if (!strcasecmp(fmt,
"wav49"))
4808 snprintf(msgnums,
sizeof(msgnums),
"%d", msgnum);
4811 ast_trace(-1,
"Opening '%s'\n", full_fn);
4815 ast_trace(-1,
"No information file found for '%s'. This is a greeting so this is OK.\n", full_fn);
4823 sprintf(full_fn,
"%s.%s", fn, fmt);
4825 ast_trace(-1,
"Audio stored on disk. No need to open '%s'\n", full_fn);
4827 ast_trace(-1,
"Opening '%s'\n", full_fn);
4828 fd = open(full_fn, O_RDWR);
4837 ast_trace(-1,
"Using information file '%s'\n", fn);
4842 idata.callerid =
"";
4845 idata.origtime =
"";
4848 idata.duration =
"";
4851 idata.category =
"";
4862 ast_trace(-1,
"Audio stored on disk. Not reading sound file '%s' but setting magic number.\n", full_fn);
4863 idata.data = AUDIO_ON_DISK_MAGIC;
4864 idata.datalen = idata.indlen = AUDIO_ON_DISK_MAGIC_LEN;
4866 ast_trace(-1,
"Reading sound file '%s'\n", full_fn);
4867 fdlen = lseek(fd, 0, SEEK_END);
4868 if (fdlen < 0 || lseek(fd, 0, SEEK_SET) < 0) {
4873 fdm = mmap(
NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
4874 if (fdm == MAP_FAILED) {
4880 idata.datalen = idata.indlen = fdlen;
4884 idata.origtime =
"0";
4888 idata.duration =
"0";
4892 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4902 if (fdm != MAP_FAILED)
4909#undef STORE_SQL_FMT_CAT
4924static void odbc_rename_message(
char *sdir,
int smsg,
char *mailboxuser,
char *mailboxcontext,
char *ddir,
int dmsg)
4927 char *sql = MAKE_SQL_PTRA(
"UPDATE %s SET dir=?, msgnum=? WHERE mailboxuser=? AND mailboxcontext=? AND dir=? AND msgnum=?");
4931 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
4932 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
4933 SCOPE_ENTER(3,
"sdir: %s smsg: %d user: %s context: %s ddir: %s dmsg: %d\n", sdir, smsg,
4934 mailboxuser, mailboxcontext, ddir, dmsg);
4936 SCOPE_CALL(-1, odbc_delete_message, ddir, dmsg);
4943 snprintf(msgnums,
sizeof(msgnums),
"%d", smsg);
4944 snprintf(msgnumd,
sizeof(msgnumd),
"%d", dmsg);
4950 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4954 char *src_fn = MAKE_FILE_PTRA(sdir, smsg);
4955 char *dst_fn = MAKE_FILE_PTRA(ddir, dmsg);
4957 ast_trace(-1,
"Recordings stored on disk. Renaming '%s' to '%s'\n", src_fn, dst_fn);
4975static int odbc_remove_files(
char *dir,
int msgnum)
4977 char *fn = MAKE_FILE_PTRA(dir, msgnum);
4978 char *full_fn = MAKE_FILE_EXT_PTRA(dir, msgnum,
"txt");
4979 SCOPE_ENTER(3,
"dir: %s msgnum: %d\n", dir, msgnum);
4982 ast_trace(-1,
"Audio stored on disk. Keeping '%s' sound files\n", fn);
4984 ast_trace(-1,
"Audio stored in ODBC. Removing '%s' sound files\n", fn);
4989 ast_trace(-1,
"Removing '%s' information file\n", full_fn);
5009 struct dirent *vment =
NULL;
5014 if ((vmdir = opendir(dir))) {
5015 while ((vment = readdir(vmdir))) {
5016 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7,
".txt", 4)) {
5039 snprintf(stxt,
sizeof(stxt),
"%s.txt", sfn);
5040 snprintf(dtxt,
sizeof(dtxt),
"%s.txt", dfn);
5062 struct dirent *msgdirent;
5071 if (!(msgdir = opendir(dir))) {
5075 while ((msgdirent = readdir(msgdir))) {
5079 ast_debug(4,
"%s map[%d] = %d, count = %d\n", dir, msgdirint, map[msgdirint], stopcount);
5085 stopcount -= map[x];
5104static int copy(
char *infile,
char *outfile)
5112#ifdef HARDLINK_WHEN_POSSIBLE
5114 if (!link(infile, outfile)) {
5119 if ((ifd = open(infile, O_RDONLY)) < 0) {
5144 wrlen = write(ofd,
buf,
len);
5173 const char *origmailbox =
"", *
context =
"", *exten =
"";
5174 const char *
priority =
"", *callerchan =
"", *callerid =
"", *origdate =
"";
5175 const char *origtime =
"", *category =
"", *duration =
"";
5178 snprintf(frompath2,
sizeof(frompath2),
"%s.txt", frompath);
5179 snprintf(topath2,
sizeof(topath2),
"%s.txt", topath);
5184 for (tmp =
var; tmp; tmp = tmp->
next) {
5185 if (!strcasecmp(tmp->
name,
"origmailbox")) {
5186 origmailbox = tmp->
value;
5187 }
else if (!strcasecmp(tmp->
name,
"context")) {
5189 }
else if (!strcasecmp(tmp->
name,
"exten")) {
5191 }
else if (!strcasecmp(tmp->
name,
"priority")) {
5193 }
else if (!strcasecmp(tmp->
name,
"callerchan")) {
5194 callerchan = tmp->
value;
5195 }
else if (!strcasecmp(tmp->
name,
"callerid")) {
5196 callerid = tmp->
value;
5197 }
else if (!strcasecmp(tmp->
name,
"origdate")) {
5198 origdate = tmp->
value;
5199 }
else if (!strcasecmp(tmp->
name,
"origtime")) {
5200 origtime = tmp->
value;
5201 }
else if (!strcasecmp(tmp->
name,
"category")) {
5202 category = tmp->
value;
5203 }
else if (!strcasecmp(tmp->
name,
"duration")) {
5204 duration = tmp->
value;
5207 ast_store_realtime(
"voicemail_data",
"filename", topath,
"origmailbox", origmailbox,
"context",
context,
"exten", exten,
"priority",
priority,
"callerchan", callerchan,
"callerid", callerid,
"origdate", origdate,
"origtime", origtime,
"category", category,
"duration", duration,
SENTINEL);
5209 copy(frompath2, topath2);
5229 txtsize = (strlen(
file) + 5)*
sizeof(
char);
5237 snprintf(txt, txtsize,
"%s.txt",
file);
5245static 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)
5249 char fromdir[256], fromfile[256];
5251 const char *origcallerid, *origtime;
5252 char origcidname[80], origcidnum[80], origdate[80];
5259 snprintf(num,
sizeof(num),
"%d", msgnum);
5273 make_file(fromfile,
sizeof(fromfile), fromdir, msgnum - 1);
5274 if (strlen(fromfile) <
sizeof(fromfile) - 5) {
5275 strcat(fromfile,
".txt");
5278 ast_debug(1,
"Config load for message text file '%s' failed\n", fromfile);
5284 ast_callerid_split(origcallerid, origcidname,
sizeof(origcidname), origcidnum,
sizeof(origcidnum));
5289 if ((origtime =
ast_variable_retrieve(msg_cfg,
"message",
"origtime")) && sscanf(origtime,
"%30d", &inttime) == 1) {
5290 struct timeval tv = { inttime, };
5313 for (ptr = from; *ptr; ptr++) {
5314 if (*ptr ==
'"' || *ptr ==
'\\') {
5355 if (*
str > 126 || *
str < 32 || strchr(
"()<>@,:;/\"[]?.=", *
str)) {
5382 int first_section = 1;
5386 for (; *start; start++) {
5387 int need_encoding = 0;
5388 if (*start < 33 || *start > 126 || strchr(
"()<>@,:;/\"[]?.=_", *start)) {
5391 if ((first_section && need_encoding && preamble +
ast_str_strlen(tmp) > 70) ||
5392 (first_section && !need_encoding && preamble +
ast_str_strlen(tmp) > 72) ||
5394 (!first_section && !need_encoding &&
ast_str_strlen(tmp) > 72)) {
5400 if (need_encoding && *start ==
' ') {
5402 }
else if (need_encoding) {
5441 const char *fromfolder,
5448 int attach_user_voicemail,
5450 const char *category,
5461 char enc_cidnum[256] =
"", enc_cidname[256] =
"";
5463 char *greeting_attachment;
5469 if (!str1 || !str2) {
5481 gethostname(host,
sizeof(host) - 1);
5483 if (strchr(srcemail,
'@')) {
5486 snprintf(who,
sizeof(who),
"%s@%s", srcemail, host);
5489 greeting_attachment = strrchr(
ast_strdupa(attach),
'/');
5490 if (greeting_attachment) {
5491 *greeting_attachment++ =
'\0';
5494 snprintf(dur,
sizeof(dur),
"%d:%02d", duration / 60, duration % 60);
5496 fprintf(p,
"Date: %s" ENDL, date);
5506 prep_email_sub_vars(ast, vmu, msgnum + 1,
context,
mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category,
flag);
5528 fprintf(p,
"From: Asterisk PBX <%s>" ENDL, who);
5535 char *next = emailsbuf;
5553 fprintf(p,
"Subject: New greeting '%s' on %s." ENDL, greeting_attachment, date);
5558 prep_email_sub_vars(ast, vmu, msgnum + 1,
context,
mailbox, fromfolder, cidnum, cidname, dur, date, category,
flag);
5581 fprintf(p,
"Subject: New message %d in mailbox %s" ENDL, msgnum + 1,
mailbox);
5583 fprintf(p,
"Subject: New %s message %d in mailbox %s" ENDL,
flag, msgnum + 1,
mailbox);
5587 fprintf(p,
"Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1,
mailbox);
5589 fprintf(p,
"Subject: [PBX]: New %s message %d in mailbox %s" ENDL,
flag, msgnum + 1,
mailbox);
5593 fprintf(p,
"Message-ID: <Asterisk-%d-%u-%s-%d@%s>" ENDL, msgnum + 1,
5597 fprintf(p,
"X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
5600 fprintf(p,
"X-Asterisk-VM-Context: %s" ENDL,
context);
5604 fprintf(p,
"X-Asterisk-VM-Extension: %s" ENDL,
mailbox);
5607 fprintf(p,
"X-Asterisk-VM-Flag: %s" ENDL,
S_OR(
flag,
""));
5609 fprintf(p,
"X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
5610 fprintf(p,
"X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
5611 fprintf(p,
"X-Asterisk-VM-Duration: %d" ENDL, duration);
5613 fprintf(p,
"X-Asterisk-VM-Category: %s" ENDL, category);
5615 fprintf(p,
"X-Asterisk-VM-Category: " ENDL);
5617 fprintf(p,
"X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ?
"Message" : greeting_attachment);
5618 fprintf(p,
"X-Asterisk-VM-Orig-date: %s" ENDL, date);
5619 fprintf(p,
"X-Asterisk-VM-Orig-time: %ld" ENDL, (
long) time(
NULL));
5620 fprintf(p,
"X-Asterisk-VM-Message-ID: %s" ENDL, msg_id);
5623 fprintf(p,
"X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
5626 fprintf(p,
"X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
5628 fprintf(p,
"MIME-Version: 1.0" ENDL);
5629 if (attach_user_voicemail) {
5631 snprintf(bound,
sizeof(bound),
"----voicemail_%d%s%d%u", msgnum + 1,
mailbox,
5632 (
int) getpid(), (
unsigned int)
ast_random());
5634 fprintf(p,
"Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
5635 fprintf(p,
ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
5636 fprintf(p,
"--%s" ENDL, bound);
5638 fprintf(p,
"Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL,
charset);
5640 fprintf(p,
"This message is to let you know that your greeting '%s' was changed on %s." ENDL
5641 "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL,
5642 greeting_attachment, date);
5647 prep_email_sub_vars(ast, vmu, msgnum + 1,
context,
mailbox, fromfolder, cidnum, cidname, dur, date, category,
flag);
5655 if ((next = strchr(line,
'\n'))) {
5658 fprintf(p,
"%s" ENDL, line);
5675 char fromdir[256], fromfile[256], origdate[80] =
"", origcallerid[80] =
"";
5679 make_file(fromfile,
sizeof(fromfile), fromdir, msgnum);
5680 if (strlen(fromfile) <
sizeof(fromfile) - 5) {
5681 strcat(fromfile,
".txt");
5690 if ((v =
ast_variable_retrieve(msg_cfg,
"message",
"origtime")) && sscanf(v,
"%30d", &inttime) == 1) {
5691 struct timeval tv = { inttime, };
5696 fprintf(p,
"Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded"
5697 " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL
5698 "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a"
5700 msgnum + 1,
mailbox, (cidname ? cidname : (cidnum ? cidnum :
"an unknown caller")),
5701 date, origcallerid, origdate);
5708 fprintf(p,
"Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a "
5709 "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL
5710 "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk"
5712 (cidname ? cidname : (cidnum ? cidnum :
"an unknown caller")), date);
5716 if (imap || attach_user_voicemail) {
5718 snprintf(filename,
sizeof(filename),
"msg%04d.%s", msgnum, format);
5719 ast_debug(5,
"creating second attachment filename %s\n", filename);
5721 snprintf(filename,
sizeof(filename),
"msgintro%04d.%s", msgnum, format);
5722 ast_debug(5,
"creating attachment filename %s\n", filename);
5725 snprintf(filename,
sizeof(filename),
"msg%04d.%s", msgnum, format);
5726 ast_debug(5,
"creating attachment filename %s, no second attachment.\n", filename);
5738 char *file_to_delete =
NULL, *dir_to_delete =
NULL;
5742 char altformat[80] =
"";
5746 char *mime_type = (!strcasecmp(format,
"ogg")) ?
"application/" :
"audio/x-";
5749 snprintf(fname,
sizeof(fname),
"%s.%s", attach, format);
5752 c = strchr(altformat,
'|');
5757 snprintf(altfname,
sizeof(altfname),
"%s.%s", attach, altformat);
5771 res = snprintf(sox_gain_tmpdir,
sizeof(sox_gain_tmpdir),
"%s/vm-gain-XXXXXX", tmpdir);
5772 if (res >=
sizeof(sox_gain_tmpdir)) {
5773 ast_log(
LOG_ERROR,
"Failed to create temporary directory path %s: Out of buffer space\n", tmpdir);
5777 if (
mkdtemp(sox_gain_tmpdir)) {
5781 ast_debug(3,
"sox_gain_tmpdir: %s\n", sox_gain_tmpdir);
5784 dir_to_delete = sox_gain_tmpdir;
5786 res = snprintf(fname,
sizeof(fname),
"%s/output.%s", sox_gain_tmpdir, format);
5787 if (res >=
sizeof(fname)) {
5788 ast_log(
LOG_ERROR,
"Failed to create filename buffer for %s/output.%s: Too long\n", sox_gain_tmpdir, format);
5793 res = snprintf(sox_gain_cmd,
sizeof(sox_gain_cmd),
"sox -v %.4f %s.%s %s",
5794 vmu->
volgain, attach, format, fname);
5796 if (!strcasecmp(format,
"wav")) {
5798 res = snprintf(sox_gain_cmd,
sizeof(sox_gain_cmd),
"sox -v %.4f %s.%s -e signed-integer -b 16 %s",
5799 vmu->
volgain, attach, altformat, fname);
5801 res = snprintf(sox_gain_cmd,
sizeof(sox_gain_cmd),
"sox %s.%s -e signed-integer -b 16 %s",
5802 attach, altformat, fname);
5806 res = snprintf(sox_gain_cmd,
sizeof(sox_gain_cmd),
"sox -v %.4f %s.%s %s",
5807 vmu->
volgain, attach, altformat, fname);
5809 res = snprintf(sox_gain_cmd,
sizeof(sox_gain_cmd),
"sox %s.%s %s",
5810 attach, altformat, fname);
5815 if (res >=
sizeof(sox_gain_cmd)) {
5816 ast_log(
LOG_ERROR,
"Failed to generate sox command, out of buffer space\n");
5823 file_to_delete = fname;
5826 ast_log(
LOG_WARNING,
"Sox failed to re-encode %s: %s (have you installed support for all sox file formats?)\n",
5828 soxstatus == 1 ?
"Problem with command line options" :
"An error occurred during file processing");
5836 if (!file_to_delete) {
5837 res = snprintf(fname,
sizeof(fname),
"%s.%s", attach, format);
5838 if (res >=
sizeof(fname)) {
5839 ast_log(
LOG_ERROR,
"Failed to create filename buffer for %s.%s: Too long\n", attach, format);
5844 fprintf(p,
"--%s" ENDL, bound);
5846 fprintf(p,
"Content-Type: %s%s; name=\"%s\"" ENDL, mime_type, format, filename);
5848 fprintf(p,
"Content-Type: %s%s; name=\"%s.%s\"" ENDL, mime_type, format, greeting_attachment, format);
5849 fprintf(p,
"Content-Transfer-Encoding: base64" ENDL);
5850 fprintf(p,
"Content-Description: Voicemail sound attachment." ENDL);
5852 fprintf(p,
"Content-Disposition: attachment; filename=\"%s\"" ENDL ENDL, filename);
5854 fprintf(p,
"Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, format);
5859 if (file_to_delete) {
5860 unlink(file_to_delete);
5863 if (dir_to_delete) {
5864 rmdir(dir_to_delete);
5875 const char *fromfolder,
5882 int attach_user_voicemail,
5884 const char *category,
5889 char tmp[80] =
"/tmp/astmail-XXXXXX";
5903 if (!strcmp(format,
"wav49"))
5912 make_email_file(p, srcemail, vmu, msgnum,
context,
mailbox, fromfolder, cidnum, cidname, attach, attach2, format, duration, attach_user_voicemail, chan, category, 0,
flag, msg_id);
5914 snprintf(tmp2,
sizeof(tmp2),
"( %s < %s ; rm -f %s ) &",
mailcmd, tmp, tmp);
5921static 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)
5923 char enc_cidnum[256], enc_cidname[256];
5928 char tmp[80] =
"/tmp/astmail-XXXXXX";
5934 if (!str1 || !str2) {
5953 gethostname(host,
sizeof(host)-1);
5954 if (strchr(srcemail,
'@')) {
5957 snprintf(who,
sizeof(who),
"%s@%s", srcemail, host);
5959 snprintf(dur,
sizeof(dur),
"%d:%02d", duration / 60, duration % 60);
5961 fprintf(p,
"Date: %s\n", date);
5970 prep_email_sub_vars(ast, vmu, msgnum + 1,
context,
mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category,
flag);
5992 fprintf(p,
"From: Asterisk PBX <%s>" ENDL, who);
6014 prep_email_sub_vars(ast, vmu, msgnum + 1,
context,
mailbox, fromfolder, cidnum, cidname, dur, date, category,
flag);
6037 fprintf(p,
"Subject: New VM" ENDL);
6039 fprintf(p,
"Subject: New %s VM" ENDL,
flag);
6049 prep_email_sub_vars(ast, vmu, msgnum + 1,
context,
mailbox, fromfolder, cidnum, cidname, dur, date, category,
flag);
6057 fprintf(p,
"New %s long %s msg in box %s\n"
6058 "from %s, on %s", dur,
flag,
mailbox, (cidname ? cidname : (cidnum ? cidnum :
"unknown")), date);
6062 snprintf(tmp2,
sizeof(tmp2),
"( %s < %s ; rm -f %s ) &",
mailcmd, tmp, tmp);
6129#define COUNT_MSGS_SQL_FMT "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'"
6130static int count_messages_in_folder(
struct odbc_obj *odbc,
const char *
context,
const char *
mailbox,
const char *folder,
int *messages)
6133 char sql[
sizeof(COUNT_MSGS_SQL_FMT) + odbc_table_len + strlen(
VM_SPOOL_DIR)
6136 SQLHSTMT stmt =
NULL;
6137 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
6148 res = SQLFetch(stmt);
6149 if (!SQL_SUCCEEDED(res)) {
6150 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
6153 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata,
sizeof(rowdata),
NULL);
6154 if (!SQL_SUCCEEDED(res)) {
6155 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
6159 *messages = atoi(rowdata);
6160 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
6164#undef COUNT_MSGS_SQL_FMT
6166static int inboxcount2(
const char *
mailbox,
int *urgentmsgs,
int *newmsgs,
int *oldmsgs)
6189 char *
next, *remaining = tmp;
6204 SCOPE_EXIT_RTN_VALUE(0,
"Urgent: %d New: %d Old: %d\n", urgentmsgs ? *urgentmsgs : 0, newmsgs ? *newmsgs : 0, oldmsgs ? *oldmsgs : 0);
6219 if (count_messages_in_folder(obj,
context, tmp,
"INBOX", newmsgs)
6220 || count_messages_in_folder(obj,
context, tmp,
"Old", oldmsgs)
6221 || count_messages_in_folder(obj,
context, tmp,
"Urgent", urgentmsgs)) {
6227 SCOPE_EXIT_RTN_VALUE(0,
"Urgent: %d New: %d Old: %d\n", urgentmsgs ? *urgentmsgs : 0, newmsgs ? *newmsgs : 0, oldmsgs ? *oldmsgs : 0);
6238#define MSGCOUNT_SQL_FMT_INBOX "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/INBOX' OR dir = '%s%s/%s/Urgent'"
6239#define MSGCOUNT_SQL_FMT "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'"
6240static int messagecount(
const char *mailbox_id,
const char *folder)
6247 SQLHSTMT stmt =
NULL;
6249 struct generic_prepare_struct gps = { .argc = 0 };
6250 SCOPE_ENTER(3,
"mb: %s folder: %s", mailbox_id, folder);
6267 if (!strcmp(folder,
"INBOX")) {
6282 res = SQLFetch(stmt);
6283 if (!SQL_SUCCEEDED(res)) {
6285 goto bail_with_handle;
6287 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata,
sizeof(rowdata),
NULL);
6288 if (!SQL_SUCCEEDED(res)) {
6290 goto bail_with_handle;
6292 nummsgs = atoi(rowdata);
6295 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
6302#undef MSGCOUNT_SQL_FMT
6303#undef MSGCOUNT_SQL_FMT_INBOX
6345 long duration,
struct ast_vm_user *recip,
char *fmt,
char *dir,
const char *
flag,
6346 const char *dest_folder)
6349 const char *frombox =
mbox(vmu, imbox);
6350 const char *userfolder;
6353 SCOPE_ENTER(3,
"mb: %s imb: %d msgnum: %d recip: %s dir: %s dest_folder: %s",
6359 userfolder =
"Urgent";
6361 userfolder = dest_folder;
6363 userfolder =
"INBOX";
6374 ast_trace(-1,
"fromdir: %s\n", fromdir);
6376 make_file(frompath,
sizeof(frompath), fromdir, msgnum);
6377 ast_trace(-1,
"frompath: %s\n", frompath);
6387 ast_trace(-1,
"recip msgnum: %d\n", recipmsgnum);
6392 make_file(topath,
sizeof(topath), todir, recipmsgnum);
6400 SCOPE_CALL(-1,
STORE, todir, recip->
mailbox, recip->
context, recipmsgnum, chan, recip, fmt, duration,
NULL,
NULL,
NULL);
6420#if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
6468 snprintf(fn,
sizeof(fn),
"%s%s/%s/%s",
VM_SPOOL_DIR,
c, m, folder);
6470 if (!(dir = opendir(fn)))
6473 while ((de = readdir(dir))) {
6474 if (!strncasecmp(de->d_name,
"msg", 3)) {
6478 }
else if (!strncasecmp(de->d_name + 8,
"txt", 3)) {
6500 char tmp[256], *tmp2 = tmp, *box, *
context;
6505 while ((box =
strsep(&tmp2,
",&"))) {
6506 if ((
context = strchr(box,
'@')))
6549 int tmpnew, tmpold, tmpurgent;
6554 while ((cur =
strsep(&mb,
", "))) {
6566 *urgentmsgs += tmpurgent;
6576 if ((
context = strchr(tmp,
'@'))) {
6603 *newmsgs += urgentmsgs;
6610 char arguments[255];
6611 char ext_context[256] =
"";
6612 int newvoicemails = 0, oldvoicemails = 0, urgentvoicemails = 0;
6628 if (!strncmp(mwi_msg->
cause,
"INV", 3))
6630 else if (!strncmp(mwi_msg->
cause,
"BLK", 3))
6640 if (
inboxcount2(ext_context, &urgentvoicemails, &newvoicemails, &oldvoicemails)) {
6643 snprintf(arguments,
sizeof(arguments),
"%s %s %s %d %d %d &",
6646 oldvoicemails, urgentvoicemails);
6647 ast_debug(1,
"Executing %s\n", arguments);
6672 snprintf(dst,
MSG_ID_LEN,
"%ld-%08x", (
long) time(
NULL), unique_counter);
6706 char ext_context[256] =
"";
6722 const char *category =
NULL;
6731 memset(&svm, 0,
sizeof(svm));
6743 duration = (int) (framelength / sample_rate);
6752 if (duration < recipient->minsecs) {
6753 ast_log(
LOG_NOTICE,
"Copying recording to voicemail %s@%s skipped because duration was shorter than "
6754 "minmessage of recipient\n", recdata->
mailbox, recdata->
context);
6764 snprintf(tmptxtfile,
sizeof(tmptxtfile),
"%s/XXXXXX", tmpdir);
6765 txtdes = mkstemp(tmptxtfile);
6775 txt = fdopen(txtdes,
"w+");
6781 "; Message Information file\n"
6804 date, (
long) time(
NULL),
6829 snprintf(ext_context,
sizeof(ext_context),
"%s@%s", recipient->
mailbox, recipient->
context);
6833 res =
inboxcount(ext_context, &newmsgs, &oldmsgs);
6840 if (!(vms = get_vm_state_by_mailbox(recipient->
mailbox, recipient->
context, 0))) {
6845 if (!(vms = create_vm_state_from_user(recipient))) {
6855 msgnum = newmsgs + oldmsgs;
6856 ast_debug(3,
"Messagecount set to %d\n", msgnum);
6857 snprintf(destination,
sizeof(destination),
"%simap/msg%s%04d",
VM_SPOOL_DIR, recipient->
mailbox, msgnum);
6861 if ((res = imap_check_limits(
NULL, vms, recipient, msgnum))) {
6872 ast_debug(3,
"mailbox = %d : inprocess = %d\n",
COUNT(recipient, dir),
6888 ast_log(
LOG_ERROR,
"Couldn't lock directory %s. Voicemail will be lost.\n", dir);
6896 make_file(destination,
sizeof(destination), dir, msgnum);
6898 make_file(tmpaudiofile,
sizeof(tmpaudiofile), tmpdir, msgnum);
6901 ast_log(
LOG_ERROR,
"Audio file failed to copy to tmp dir. Probably low disk space.\n");
6912 ast_log(
LOG_ERROR,
"Audio file failed to move to destination directory. Permissions/Overlap?\n");
6920 snprintf(desttxtfile,
sizeof(desttxtfile),
"%s.txt", destination);
6921 rename(tmptxtfile, desttxtfile);
6938 char cidnum[80], cidname[80];
6944 "origmailbox", recdata->
mailbox,
6951 "origtime", time(
NULL),
6952 "category",
S_OR(category,
""),
6953 "filename", tmptxtfile,
6954 "duration", duration,
6958 STORE(dir, recipient->
mailbox, recipient->
context, msgnum,
NULL, recipient, fmt, 0, vms,
"", msg_id);
7000 int newmsgs, oldmsgs;
7012 int sound_duration = 0;
7014 int greeting_only = 0;
7023 char ext_context[256] =
"";
7026 char ecodes[17] =
"#";
7031 const char *category =
NULL;
7033 const char *alldtmf =
"0123456789ABCD*#";
7045 tmpptr = strchr(
context,
'&');
7047 tmpptr = strchr(
ext,
'&');
7068 memset(&svm, 0,
sizeof(svm));
7083 if (strcmp(vmu->
context,
"default"))
7084 snprintf(ext_context,
sizeof(ext_context),
"%s@%s",
ext, vmu->
context);
7098 ast_trace(-1,
"prefile: %s\n", prefile);
7104 ast_trace(-1,
"tempfile: %s\n", tempfile);
7114 ast_trace(-1,
"new prefile: %s\n", prefile);
7134 strncat(ecodes,
"0",
sizeof(ecodes) - strlen(ecodes) - 1);
7139 strncat(ecodes,
"0",
sizeof(ecodes) - strlen(ecodes) - 1);
7147 strncat(ecodes,
"*",
sizeof(ecodes) - strlen(ecodes) - 1);
7151 strncat(ecodes,
"*",
sizeof(ecodes) - strlen(ecodes) - 1);
7155 for (code = alldtmf; *code; code++) {
7158 if (strchr(ecodes, e[0]) ==
NULL
7162 strncat(ecodes, e,
sizeof(ecodes) - strlen(ecodes) - 1);
7169#if defined(ODBC_STORAGE)
7171#elif defined(IMAP_STORAGE)
7185 if (success == -1) {
7187 ast_trace(-1,
"Greeting '%s' not retrieved from database, but found in file storage. Inserting into database\n", prefile);
7192 ast_trace(-1,
"%s doesn't exist, doing what we can\n", prefile);
7259 if (greeting_only) {
7260 ast_debug(3,
"Greetings only VM (maxmsg=0), Skipping voicemail recording\n");
7284 res =
inboxcount(ext_context, &newmsgs, &oldmsgs);
7291 if (!(vms = get_vm_state_by_mailbox(
ext,
context, 0))) {
7296 if (!(vms = create_vm_state_from_user(vmu))) {
7306 msgnum = newmsgs + oldmsgs;
7307 ast_debug(3,
"Messagecount set to %d\n", msgnum);
7312 if ((res = imap_check_limits(chan, vms, vmu, msgnum))) {
7327 snprintf(tmptxtfile,
sizeof(tmptxtfile),
"%s/XXXXXX", tmpdir);
7328 ast_trace(-1,
"Tempfile: %s\n", tmptxtfile);
7329 txtdes = mkstemp(tmptxtfile);
7353 snprintf(origtime,
sizeof(origtime),
"%ld", (
long) time(
NULL));
7365 "callerid", callerid,
7367 "origtime", origtime,
7368 "category",
S_OR(category,
""),
7369 "filename", tmptxtfile,
7374 txt = fdopen(txtdes,
"w+");
7384 "; Message Information file\n"
7406 date, (
long) time(
NULL),
7407 category ? category :
"",
7409 ast_trace(-1,
"Saving txt file mbox: %s msg_id: %s\n",
ext, msg_id);
7420 res =
SCOPE_CALL_WITH_INT_RESULT(-1,
play_record_review, chan,
NULL, tmptxtfile, vmu->
maxsecs, fmt, 1, vmu, &duration, &sound_duration,
NULL,
options->record_gain, vms,
flag, msg_id, 0);
7426 if (!strcmp(
flag,
"Urgent")) {
7431 fprintf(txt,
"flag=%s\n",
flag);
7432 if (sound_duration < vmu->
minsecs) {
7434 ast_verb(3,
"Recording was %d seconds long but needs to be at least %d - abandoning\n", sound_duration, vmu->
minsecs);
7442 fprintf(txt,
"duration=%d\n", duration);
7451 ast_debug(1,
"The recorded media file is gone, so we should remove the .txt file too!\n");
7471 snprintf(txtfile,
sizeof(txtfile),
"%s.txt", fn);
7473 ast_trace(-1,
"Renaming recordings '%s' -> fn '%s'\n", tmptxtfile, fn);
7477 ast_trace(-1,
"Renaming txt file '%s' -> fn '%s'\n", tmptxtfile, txtfile);
7478 rename(tmptxtfile, txtfile);
7488 snprintf(tmpdur,
sizeof(tmpdur),
"%d", duration);
7495 SCOPE_CALL(-1,
STORE, dir, vmu->
mailbox, vmu->
context, msgnum, chan, vmu, fmt, duration, vms,
flag, msg_id);
7503 exten =
strsep(&tmpptr,
"&");
7504 cntx = strchr(exten,
'@');
7509 memset(&recipu, 0,
sizeof(recipu));
7510 if ((recip =
find_user(&recipu, cntx, exten))) {
7542 }
else if (res > 0 && res !=
't')
7545 if (sound_duration < vmu->
minsecs)
7557 ast_debug(3,
"*** Checking if we can expunge, expungeonhangup set to %d\n", expungeonhangup);
7558 if (expungeonhangup == 1 && vms->mailstream !=
NULL) {
7560#ifdef HAVE_IMAP_TK2006
7561 if (LEVELUIDPLUS (vms->mailstream)) {
7562 mail_expunge_full(vms->mailstream, NIL, EX_UID);
7565 mail_expunge(vms->mailstream);
7574#if !defined(IMAP_STORAGE)
7587 for (x = 0, dest = 0; dest != stopcount && x <
MAXMSGLIMIT; x++) {
7623 snprintf(sequence,
sizeof(sequence),
"%ld", vms->msgArray[msg]);
7625 ast_debug(3,
"Copying sequence %s to mailbox %s\n", sequence,
mbox(vmu, box));
7629 mail_setflag(vms->mailstream, sequence,
"\\Seen");
7631 mail_clearflag(vms->mailstream, sequence,
"\\Seen");
7643 if (vms->mailstream && !mail_status(vms->mailstream,
mailbox, SA_UIDNEXT)) {
7644 if (mail_create(vms->mailstream,
mailbox) != NIL) {
7650 if (init_mailstream(vms, curr_mbox) || !vms->mailstream) {
7655 res = !mail_move(vms->mailstream, sequence, (
char *)
mbox(vmu, box));
7657 res = !mail_copy(vms->mailstream, sequence, (
char *)
mbox(vmu, box));
7669 const char *dbox =
mbox(vmu, box);
7671 SCOPE_ENTER(3,
"dir: %s msg: %d box: %d dbox: %s move? %d \n", dir, msg, box, dbox, move);
7683 ast_trace(-1,
"Deleting message %d\n", msg);
7685 for (i = 1; i <= x; i++) {
7688 make_file(dfn,
sizeof(dfn), ddir, i - 1);
7702 if (strcmp(sfn, dfn)) {
7703 ast_trace(-1,
"Copying message '%s' to '%s'\n", sfn, dfn);
7725 unsigned char buf[256];
7757 bytes += ast_adsi_logo(
buf);
7801 for (x = 0; x < 5; x++) {
7802 snprintf(num,
sizeof(num),
"%d", x);
7830 ast_debug(1,
"Done downloading scripts...\n");
7838 ast_debug(1,
"Restarting session...\n");
7874 unsigned char buf[256];
7876 unsigned char keys[8];
7881 for (x = 0; x < 8; x++)
7900 unsigned char buf[256];
7902 unsigned char keys[8];
7907 for (x = 0; x < 8; x++)
7922 unsigned char buf[256];
7924 unsigned char keys[8];
7930 for (x = 0; x < 5; x++) {
7952 unsigned char buf[256];
7959 char datetime[21] =
"";
7962 unsigned char keys[8];
7970 snprintf(fn2,
sizeof(fn2),
"%s.txt", vms->
fn);
7971 f = fopen(fn2,
"r");
7974 if (!fgets((
char *)
buf,
sizeof(
buf), f)) {
7978 char *stringp =
NULL;
7979 stringp = (
char *)
buf;
7983 if (!strcmp((
char *)
buf,
"callerid"))
7985 if (!strcmp((
char *)
buf,
"origdate"))
7993 for (x = 0; x < 5; x++)
8020 name =
"Unknown Caller";
8037 strcasecmp(vms->
curbox,
"INBOX") ?
" Messages" :
"");
8054 unsigned char buf[256];
8055 unsigned char keys[8];
8063 for (x = 0; x < 5; x++)
8105 unsigned char buf[256] =
"";
8106 char buf1[256] =
"",
buf2[256] =
"";
8108 unsigned char keys[8];
8111 char *newm = (vms->
newmessages == 1) ?
"message" :
"messages";
8112 char *oldm = (vms->
oldmessages == 1) ?
"message" :
"messages";
8118 strncat(
buf1,
" and",
sizeof(
buf1) - strlen(
buf1) - 1);
8121 snprintf(
buf2,
sizeof(
buf2),
"%s.", newm);
8125 snprintf(
buf2,
sizeof(
buf2),
"%s.", oldm);
8127 strcpy(
buf1,
"You have no messages.");
8135 for (x = 0; x < 6; x++)
8152 unsigned char buf[256] =
"";
8153 char buf1[256] =
"",
buf2[256] =
"";
8155 unsigned char keys[8];
8158 char *mess = (vms->
lastmsg == 0) ?
"message" :
"messages";
8164 for (x = 0; x < 6; x++)
8174 strcasecmp(vms->
curbox,
"INBOX") ?
" folder" :
"");
8179 strcpy(
buf2,
"no messages.");
8208 unsigned char buf[256];
8234 for (x = start; x < 5; x++) {
8240 snprintf(fn,
sizeof(fn),
"vm-%s",
mbox(
NULL, x));
8249 ast_verb(4,
"Failed to find file %s; falling back to INBOX\n", fn);
8277 for (x = start; x < 5; x++) {
8281 snprintf(fn,
sizeof(fn),
"vm-%s",
mbox(
NULL, x));
8317 while (((res <
'0') || (res >
'9')) &&
8318 (res !=
'#') && (res >= 0) &&
8333 isprint(res) ? res :
'?', isprint(res) ? res :
'?');
8356 int curmsg,
char *vm_fmts,
char *
context,
signed char record_gain,
long *duration,
8360 int retries = 0, prepend_duration = 0, already_recorded = 0;
8366 signed char zero_gain = 0;
8368 const char *msg_id =
NULL;
8370 const char *duration_str;
8374 make_file(msgfile,
sizeof(msgfile), curdir, curmsg);
8375 ast_trace(-1,
"msgfile: %s\n", msgfile);
8376 strcpy(textfile, msgfile);
8377 strcpy(backup, msgfile);
8378 strcpy(backup_textfile, msgfile);
8379 strncat(textfile,
".txt",
sizeof(textfile) - strlen(textfile) - 1);
8380 strncat(backup,
"-bak",
sizeof(backup) - strlen(backup) - 1);
8381 strncat(backup_textfile,
"-bak.txt",
sizeof(backup_textfile) - strlen(backup_textfile) - 1);
8384 *duration = atoi(duration_str);
8389 while ((cmd >= 0) && (cmd !=
't') && (cmd !=
'*')) {
8400 make_file(vms->introfn,
sizeof(vms->introfn), curdir, curmsg);
8401 strncat(vms->introfn,
"intro",
sizeof(vms->introfn));
8404 cmd =
play_record_review(chan,
NULL, vms->introfn, vmu->
maxsecs, vm_fmts, 1, vmu, (
int *) duration,
NULL,
NULL, record_gain, vms,
flag, msg_id, 1);
8412 ast_trace(-1,
"Prepending to message %d\n", curmsg);
8414 make_file(msgfile,
sizeof(msgfile), curdir, curmsg);
8415 ast_trace(-1,
"msgfile: %s\n", msgfile);
8417 strcpy(textfile, msgfile);
8418 strncat(textfile,
".txt",
sizeof(textfile) - 1);
8429 if (already_recorded) {
8430 ast_trace(-1,
"Restoring '%s' to '%s'\n", backup, msgfile);
8432 copy(backup_textfile, textfile);
8435 ast_trace(-1,
"Backing up '%s' to '%s'\n", backup, msgfile);
8437 copy(textfile, backup_textfile);
8440 already_recorded = 1;
8445 cmd =
SCOPE_CALL_WITH_INT_RESULT(-1,
ast_play_and_prepend, chan,
NULL, msgfile, 0, vm_fmts, &prepend_duration,
NULL, 1,
silencethreshold,
maxsilence);
8458 *duration = atoi(duration_str);
8460 if (prepend_duration) {
8463 char duration_buf[12];
8465 *duration += prepend_duration;
8466 ast_trace(-1,
"Prepending duration: %d total duration: %ld\n", prepend_duration, *duration);
8468 snprintf(duration_buf,
sizeof(duration_buf),
"%ld", *duration);
8479 *vms->introfn =
'\0';
8488 already_recorded = 0;
8506 isprint(cmd) ? cmd :
'?', isprint(cmd) ? cmd :
'?');
8512 if (prepend_duration)
8513 *duration = prepend_duration;
8515 if (already_recorded && cmd == -1) {
8517 ast_trace(-1,
"Restoring '%s' to '%s'\n", backup, msgfile);
8519 rename(backup_textfile, textfile);
8522 if (cmd ==
't' || cmd ==
'S') {
8528static void queue_mwi_event(
const char *channel_id,
const char *box,
int urgent,
int new,
int old)
8537 ast_debug(3,
"Queueing event for mailbox %s New: %d Old: %d\n", box,
new + urgent, old);
8550 ast_debug(3,
"Found alias mapping: %s -> %s\n", mapping->
alias, box);
8576 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;
8577 const char *category;
8589 snprintf(todir,
sizeof(todir),
"%simap",
VM_SPOOL_DIR);
8591 make_file(fn,
sizeof(fn), todir, msgnum);
8592 snprintf(ext_context,
sizeof(ext_context),
"%s@%s", vmu->
mailbox, vmu->
context);
8611 char *msg_id =
NULL;
8617 snprintf(filename,
sizeof(filename),
"%s.txt", fn);
8625 if (attach_user_voicemail)
8629 sendmail(myserveremail, vmu, msgnum, vmu->
context, vmu->
mailbox,
mbox(vmu, 0), cidnum, cidname, fn,
NULL, fmt, duration, attach_user_voicemail, chan, category,
flag, msg_id);
8631 if (attach_user_voicemail)
8636 sendpage(myserveremail, vmu->
pager, msgnum, vmu->
context, vmu->
mailbox,
mbox(vmu, 0), cidnum, cidname, duration, vmu, category,
flag);
8640 DELETE(todir, msgnum, fn, vmu);
8695 char ecodes[16] =
"#";
8696 int res = 0, cmd = 0;
8701 const char mailbox_context[256];
8702 int saved_messages = 0;
8703 int valid_extensions = 0;
8706 char urgent_str[7] =
"";
8707 int prompt_played = 0;
8715 ast_copy_string(urgent_str, urgent ?
"Urgent" :
"",
sizeof(urgent_str));
8725 while (!res && !valid_extensions) {
8726 int use_directory = 0;
8731 while ((cmd >= 0) && !
done ){
8761 isprint(cmd) ? cmd :
'?', isprint(cmd) ? cmd :
'?');
8764 if (cmd < 0 || cmd ==
't')
8768 if (use_directory) {
8771 struct ast_app* directory_app;
8774 if (directory_app) {
8775 char vmcontext[256];
8785 snprintf(vmcontext,
sizeof(vmcontext),
"%s,,v",
context ?
context :
"default");
8786 res =
pbx_exec(chan, directory_app, vmcontext);
8802 if (res || prompt_played > 4)
8804 if ((res =
ast_readstring(chan, username,
sizeof(username) - 1, 2000, 10000,
"#")) < 0)
8812 s =
strsep(&stringp,
"*");
8814 valid_extensions = 1;
8816 snprintf((
char*)mailbox_context,
sizeof(mailbox_context),
"%s@%s", s,
context ?
context :
"default");
8822 if (
inboxcount(mailbox_context, &newmsgs, &oldmsgs)) {
8823 ast_log(
LOG_ERROR,
"Problem in calculating number of voicemail messages available for extension %s\n", mailbox_context);
8826 valid_extensions = 0;
8830 if (!(dstvms = get_vm_state_by_mailbox(s,
context, 0))) {
8831 if (!(dstvms = create_vm_state_from_user(receiver))) {
8835 valid_extensions = 0;
8839 check_quota(dstvms, imapfolder);
8840 if (dstvms->quota_limit && dstvms->quota_usage >= dstvms->quota_limit) {
8841 ast_log(
LOG_NOTICE,
"Mailbox '%s' is exceeded quota %u >= %u\n", mailbox_context, dstvms->quota_usage, dstvms->quota_limit);
8843 valid_extensions = 0;
8852 if ((newmsgs + oldmsgs) >= capacity) {
8853 ast_log(
LOG_NOTICE,
"Mailbox '%s' is full with capacity of %d, prompting for another extension.\n", mailbox_context, capacity);
8855 valid_extensions = 0;
8876 valid_extensions = 0;
8894 s =
strsep(&stringp,
"*");
8897 if (valid_extensions)
8903 if (is_new_message == 1) {
8909 memset(&leave_options, 0,
sizeof(leave_options));
8917 int copy_msg_result = 0;
8921 const char *msg_id =
NULL;
8924 memcpy(&vmstmp, vms,
sizeof(vmstmp));
8928 make_file(filename,
sizeof(filename), dir, curmsg);
8929 strncat(filename,
".txt",
sizeof(filename) - strlen(filename) - 1);
8937 cmd =
SCOPE_CALL_WITH_INT_RESULT(-1,
vm_forwardoptions, chan, sender, vmstmp.
curdir, curmsg,
vmfmts,
S_OR(
context,
"default"), record_gain, &duration, &vmstmp, urgent_str);
8941 int attach_user_voicemail;
8945 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
8947 dstvms = create_vm_state_from_user(vmtmp);
8950 init_mailstream(dstvms, 0);
8951 if (!dstvms->mailstream) {
8954 copy_msg_result =
STORE(vmstmp.
curdir, vmtmp->mailbox, vmtmp->context, curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str, msg_id);
8961 myserveremail = vmtmp->serveremail;
8964 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox,
8968 vmstmp.
fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan,
8969 NULL, urgent_str, msg_id);
8971 copy_msg_result =
SCOPE_CALL_WITH_INT_RESULT(-1,
copy_message, chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str,
NULL);
8981 if (saved_messages > 0 && !copy_msg_result) {
8998 make_file(msgfile,
sizeof(msgfile), dir, curmsg);
8999 strcpy(textfile, msgfile);
9000 strcpy(backup, msgfile);
9001 strcpy(backup_textfile, msgfile);
9002 strncat(textfile,
".txt",
sizeof(textfile) - strlen(textfile) - 1);
9003 strncat(backup,
"-bak",
sizeof(backup) - strlen(backup) - 1);
9004 strncat(backup_textfile,
"-bak.txt",
sizeof(backup_textfile) - strlen(backup_textfile) - 1);
9007 rename(backup_textfile, textfile);
9014 make_file(msgfile,
sizeof(msgfile), dir, curmsg);
9015 strcpy(textfile, msgfile);
9016 strcpy(backup_textfile, msgfile);
9017 strncat(textfile,
".txt",
sizeof(textfile) - strlen(textfile) - 1);
9018 strncat(backup_textfile,
"-bak.txt",
sizeof(backup_textfile) - strlen(backup_textfile) - 1);
9019 rename(backup_textfile, textfile);
9094 if (time_now.tm_year == time_then.tm_year)
9095 snprintf(temp,
sizeof(temp),
"%d", time_now.tm_yday);
9097 snprintf(temp,
sizeof(temp),
"%d", (time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
9143 char *callerid, *
name;
9157 ast_debug(1,
"VM-CID: composite caller ID received: %s, context: %s\n", cid,
context);
9174 ast_verb(3,
"Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
9179 ast_verb(3,
"Playing envelope info: message from '%s'\n", callerid);
9182 res =
wait_file2(chan, vms,
"vm-from-extension");
9188 ast_debug(1,
"VM-CID: Numeric caller id: (%s)\n", callerid);
9194 ast_verb(3,
"Playing recorded name for CID number '%s' - '%s'\n", callerid,prefile);
9197 ast_verb(3,
"Played recorded name result '%d'\n", res);
9200 wait_file2(chan, vms,
"vm-from-phonenumber");
9209 ast_debug(1,
"VM-CID: From an unknown number\n");
9211 res =
wait_file2(chan, vms,
"vm-unknown-caller");
9222 if (duration ==
NULL)
9226 durations = atoi(duration);
9227 durationm = (durations / 60);
9229 ast_debug(1,
"VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
9231 if ((!res) && (durationm >= minduration)) {
9236 div_t num = div(durationm, 10);
9238 if (durationm == 1) {
9241 }
else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
9270 const char *origtime, *
context, *category, *duration, *
flag;
9285 snprintf(filename,
sizeof(filename),
"%s.txt", vms->
fn);
9306 ten = (vms->
curmsg + 1) / 10;
9307 one = (vms->
curmsg + 1) % 10;
9310 snprintf(nextmsg,
sizeof(nextmsg),
"digits/n-%d", vms->
curmsg + 1);
9313 snprintf(nextmsg,
sizeof(nextmsg),
"digits/n-%d", ten * 10);
9317 snprintf(nextmsg,
sizeof(nextmsg),
"digits/n-%d", one);
9359 res =
wait_file2(chan, vms,
"vm-meddelandet");
9426 isprint(res) ? res :
'?', isprint(res) ? res :
'?');
9433static int imap_remove_file(
char *dir,
int msgnum)
9441 snprintf(
intro,
sizeof(
intro),
"%sintro", fn);
9445 if ((msgnum < 0 && imapgreetings) || msgnum > -1) {
9450 snprintf(full_fn,
sizeof(full_fn),
"%s.txt", fn);
9458static int imap_delete_old_greeting (
char *dir,
struct vm_state *vms)
9460 char *
file, *filename;
9470 ast_log(
AST_LOG_ERROR,
"Failed to procure file name from directory passed. You should never see this.\n");
9485 for (i = 0; i < vms->mailstream->nmsgs; i++) {
9486 mail_fetchstructure(vms->mailstream, i + 1, &body);
9488 if (body->nested.part->next && body->nested.part->next->body.parameter->value) {
9489 char *attachment = body->nested.part->next->body.parameter->value;
9490 char copy[strlen(attachment) + 1];
9492 strcpy(
copy, attachment);
9495 filename =
strsep(&attachment,
".");
9496 if (!strcmp(filename,
file)) {
9497 snprintf(arg,
sizeof(arg),
"%d", i + 1);
9498 mail_setflag(vms->mailstream, arg,
"\\DELETED");
9506 mail_expunge(vms->mailstream);
9508 if (curr_mbox != -1) {
9510 if (init_mailstream(vms, curr_mbox) || !vms->mailstream) {
9519#elif !defined(IMAP_STORAGE)
9522 int count_msg, last_msg;
9523 SCOPE_ENTER(3,
"user: %s dir: %s msg: %d box %d\n",
9538 if (count_msg < 0) {
9563 if (last_msg < -1) {
9565 }
else if (vms->
lastmsg != last_msg) {
9566 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);
9577 int last_msg_idx = 0;
9580 int res = 0, nummsg;
9587 ast_trace(-1,
"No messages in mailbox\n");
9600 if (last_msg_idx != vms->
lastmsg) {
9605 for (x = 0; x < last_msg_idx + 1; x++) {
9614 if (strcmp(vms->
fn, fn2)) {
9631 ast_trace(-1,
"Unable to lock path. Not moving message to deleted folder.\n");
9650 for (x = vms->
curmsg + 1; x <= nummsg; x++) {
9664 for (x = last_msg_idx - 1; x >= 0; x--) {
9705 if (!strcasecmp(box,
"vm-INBOX") || !strcasecmp(box,
"vm-Old")){
9718 if (!strcasecmp(box,
"vm-INBOX") || !strcasecmp(box,
"vm-Old")) {
9731 if (!strcasecmp(box,
"vm-INBOX") || !strcasecmp(box,
"vm-Old")) {
9732 if (!strcasecmp(box,
"vm-INBOX"))
9747 if (!strcasecmp(box,
"vm-Family") || !strcasecmp(box,
"vm-Friends") || !strcasecmp(box,
"vm-Work")){
10106 snprintf(recname,
sizeof(recname),
"digits/1kvk");
10108 snprintf(recname,
sizeof(recname),
"digits/%dhk", vms->
urgentmessages);
10121 snprintf(recname,
sizeof(recname),
"digits/1kvk");
10123 snprintf(recname,
sizeof(recname),
"digits/%dhk", vms->
newmessages);
10138 snprintf(recname,
sizeof(recname),
"digits/1kvk");
10140 snprintf(recname,
sizeof(recname),
"digits/%dhk", vms->
oldmessages);
10216 }
else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
10217 if (num.rem == 2) {
10243 }
else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
10244 if (num.rem == 2) {
10918 if (skipadvanced) {
10933 if (!res && !skipadvanced)
10948 int curmsg_deleted;
10957 if (!curmsg_deleted) {
11007 if (skipadvanced) {
11028 if (!res && !skipadvanced)
11043 int curmsg_deleted;
11051 if (!curmsg_deleted) {
11122 char newpassword[80] =
"";
11123 char newpassword2[80] =
"";
11125 unsigned char buf[256];
11142 cmd =
play_record_review(chan,
"vm-rec-name", prefile,
maxgreet, fmtc, 0, vmu, &duration,
NULL,
NULL, record_gain, vms,
NULL,
NULL, 0);
11143 if (cmd < 0 || cmd ==
't' || cmd ==
'#')
11152 cmd =
play_record_review(chan,
"vm-rec-unv", prefile,
maxgreet, fmtc, 0, vmu, &duration,
NULL,
NULL, record_gain, vms,
NULL,
NULL, 0);
11153 if (cmd < 0 || cmd ==
't' || cmd ==
'#')
11159 cmd =
play_record_review(chan,
"vm-rec-busy", prefile,
maxgreet, fmtc, 0, vmu, &duration,
NULL,
NULL, record_gain, vms,
NULL,
NULL, 0);
11160 if (cmd < 0 || cmd ==
't' || cmd ==
'#')
11170 newpassword[1] =
'\0';
11173 newpassword[0] =
'\0';
11174 if (cmd < 0 || cmd ==
't' || cmd ==
'#')
11176 cmd =
ast_readstring(chan, newpassword + strlen(newpassword),
sizeof(newpassword) - 1, 2000, 10000,
"#");
11177 if (cmd < 0 || cmd ==
't' || cmd ==
'#')
11184 newpassword2[1] =
'\0';
11187 newpassword2[0] =
'\0';
11188 if (cmd < 0 || cmd ==
't' || cmd ==
'#')
11190 cmd =
ast_readstring(chan, newpassword2 + strlen(newpassword2),
sizeof(newpassword2) - 1, 2000, 10000,
"#");
11191 if (cmd < 0 || cmd ==
't' || cmd ==
'#')
11193 if (!strcmp(newpassword, newpassword2))
11209 ast_debug(1,
"User %s set password to %s of length %d\n", vms->
username, newpassword, (
int) strlen(newpassword));
11220 char newpassword[80] =
"";
11221 char newpassword2[80] =
"";
11223 unsigned char buf[256];
11236 while ((cmd >= 0) && (cmd !=
't')) {
11242 cmd =
SCOPE_CALL_WITH_INT_RESULT(-1,
play_record_review, chan,
"vm-rec-unv", prefile,
maxgreet, fmtc, 0, vmu, &duration,
NULL,
NULL, record_gain, vms,
NULL,
NULL, 0);
11246 cmd =
SCOPE_CALL_WITH_INT_RESULT(-1,
play_record_review, chan,
"vm-rec-busy", prefile,
maxgreet, fmtc, 0, vmu, &duration,
NULL,
NULL, record_gain, vms,
NULL,
NULL, 0);
11250 cmd =
SCOPE_CALL_WITH_INT_RESULT(-1,
play_record_review, chan,
"vm-rec-name", prefile,
maxgreet, fmtc, 0, vmu, &duration,
NULL,
NULL, record_gain, vms,
NULL,
NULL, 0);
11260 newpassword[1] =
'\0';
11263 newpassword[0] =
'\0';
11267 if ((cmd =
ast_readstring(chan, newpassword + strlen(newpassword),
sizeof(newpassword) - 1, 2000, 10000,
"#")) < 0) {
11280 newpassword2[1] =
'\0';
11283 newpassword2[0] =
'\0';
11288 if ((cmd =
ast_readstring(chan, newpassword2 + strlen(newpassword2),
sizeof(newpassword2) - 1, 2000, 10000,
"#")) < 0) {
11292 if (strcmp(newpassword, newpassword2)) {
11308 ast_debug(1,
"User %s set password to %s of length %d\n",
11309 vms->
username, newpassword, (
int) strlen(newpassword));
11336 isprint(cmd) ? cmd :
'?', isprint(cmd) ? cmd :
'?');
11366 unsigned char buf[256];
11380 while ((cmd >= 0) && (cmd !=
't')) {
11385 cmd =
play_record_review(chan,
"vm-rec-temp", prefile,
maxgreet, fmtc, 0, vmu, &duration,
NULL,
NULL, record_gain, vms,
NULL,
NULL, 0);
11393 cmd =
play_record_review(chan,
"vm-rec-temp", prefile,
maxgreet, fmtc, 0, vmu, &duration,
NULL,
NULL, record_gain, vms,
NULL,
NULL, 0);
11396 DELETE(prefile, -1, prefile, vmu);
11406 "vm-tempgreeting2" :
"vm-tempgreeting");
11417 isprint(cmd) ? cmd :
'?', isprint(cmd) ? cmd :
'?');
11443 if (!strcasecmp(vms->
vmbox,
"vm-INBOX") ||!strcasecmp(vms->
vmbox,
"vm-Old")){
11445 snprintf(vms->
fn,
sizeof(vms->
fn),
"vm-%ss", vms->
curbox);
11454 snprintf(vms->
fn,
sizeof(vms->
fn),
"vm-%s", vms->
curbox);
11470 if (!strcasecmp(vms->
fn,
"INBOX")) {
11498 snprintf(vms->
fn,
sizeof(vms->
fn),
"vm-%s", vms->
curbox);
11526 snprintf(vms->
fn,
sizeof(vms->
fn),
"vm-%s", vms->
curbox);
11548 snprintf(vms->
fn,
sizeof(vms->
fn),
"vm-%s", vms->
curbox);
11579 snprintf(vms->
fn,
sizeof(vms->
fn),
"vm-%s", vms->
curbox);
11603 snprintf(vms->
fn,
sizeof(vms->
fn),
"vm-%s", vms->
curbox);
11633 snprintf(vms->
fn,
sizeof(vms->
fn),
"vm-%s", vms->
curbox);
11657 snprintf(vms->
fn,
sizeof(vms->
fn),
"vm-%s", vms->
curbox);
11700 int skipuser,
int max_logins,
int silent)
11702 int useadsi = 0, valid = 0, logretries = 0;
11708 if (!skipuser && useadsi)
11717 while (!valid && (logretries < max_logins)) {
11727 ast_verb(3,
"Username not entered\n");
11730 }
else if (
mailbox[0] ==
'*') {
11732 ast_verb(4,
"Mailbox begins with '*', attempting jump to extension 'a'\n");
11737 ast_verb(4,
"Jump to extension 'a' failed; setting mailbox to NULL\n");
11745 char fullusername[80];
11748 strncat(fullusername,
mailbox,
sizeof(fullusername) - 1 - strlen(fullusername));
11753 memset(&vmus, 0,
sizeof(vmus));
11772 ast_verb(4,
"Password begins with '*', attempting jump to extension 'a'\n");
11779 ast_verb(4,
"Jump to extension 'a' failed; setting mailbox and user to NULL\n");
11789 if (passptr[0] ==
'-') passptr++;
11791 if (vmu && !strcmp(passptr,
password))
11800 if (skipuser || logretries >= max_logins) {
11821 if (!valid && (logretries >= max_logins)) {
11827 if (vmu && !skipuser) {
11836 const char *msg_id)
11885 memset(&vmus, 0,
sizeof(vmus));
11886 memset(&vms, 0,
sizeof(vms));
11889 goto play_msg_cleanup;
11901 goto play_msg_cleanup;
11913 goto play_msg_cleanup;
11929 vmstate_delete(&vms);
11979#define VMBOX_STRING_HEADER_FORMAT "%-32.32s %-32.32s %-16.16s %-16.16s %-16.16s %-16.16s\n"
11980#define VMBOX_STRING_DATA_FORMAT "%-32.32s %-32.32s %-16.16s %-16.16s %-16.16s %-16.16s\n"
11986 memset(&vmus, 0,
sizeof(vmus));
11987 memset(&vms, 0,
sizeof(vms));
12002#define VM_STRING_HEADER_FORMAT "%-8.8s %-32.32s %-32.32s %-9.9s %-6.6s %-30.30s\n"
12011 if (!mailbox_snapshot) {
12018 for (i = 0; i < mailbox_snapshot->
folders; i++) {
12021 msg->flag,
msg->msg_id);
12044 const char *from_context =
a->argv[3];
12045 const char *from_folder =
a->argv[4];
12046 const char *
id[] = {
a->argv[5] };
12047 const char *to_mailbox =
a->argv[6];
12048 const char *to_context =
a->argv[7];
12049 const char *to_folder =
a->argv[8];
12052 ast_cli(
a->fd,
"Error forwarding message %s from mailbox %s@%s %s to mailbox %s@%s %s\n",
12053 id[0],
from_mailbox, from_context, from_folder, to_mailbox, to_context, to_folder);
12055 ast_cli(
a->fd,
"Forwarded message %s from mailbox %s@%s %s to mailbox %s@%s %s\n",
12056 id[0],
from_mailbox, from_context, from_folder, to_mailbox, to_context, to_folder);
12065 const char *from_folder =
a->argv[4];
12066 const char *
id[] = {
a->argv[5] };
12067 const char *to_folder =
a->argv[6];
12070 ast_cli(
a->fd,
"Error moving message %s from mailbox %s@%s %s to %s\n",
12073 ast_cli(
a->fd,
"Moved message %s from mailbox %s@%s %s to %s\n",
12083 const char *folder =
a->argv[4];
12084 const char *
id[] = {
a->argv[5] };
12087 ast_cli(
a->fd,
"Error removing message %s from mailbox %s@%s %s\n",
12090 ast_cli(
a->fd,
"Removed message %s from mailbox %s@%s %s\n",
12098 const char *
word =
a->word;
12109 wordlen = strlen(
word);
12112 if (!strncasecmp(
word, vmu->
mailbox , wordlen)) {
12122 }
else if (pos == 4) {
12124 const char *box =
a->argv[3];
12125 wordlen = strlen(
word);
12147 e->
command =
"voicemail show mailbox";
12149 "Usage: voicemail show mailbox <mailbox> <context>\n"
12150 " Show contents of mailbox <mailbox>@<context>\n";
12158 if (
a->argc != 5) {
12188 const char *
word =
a->word;
12194 const char *
context =
"", *
mailbox =
"", *folder =
"", *
id =
"";
12197 if (pos > maxpos) {
12203 if (pos == 2 || (pos == 6 && maxpos == 8)) {
12205 wordlen = strlen(
word);
12208 if (!strncasecmp(
word, vmu->
mailbox , wordlen)) {
12218 }
else if (pos == 3 || pos == 7) {
12220 mailbox = (pos == 3) ?
a->argv[2] :
a->argv[6];
12221 wordlen = strlen(
word);
12234 }
else if (pos == 4 || pos == 8 || (pos == 6 && maxpos == 6) ) {
12237 wordlen = strlen(
word);
12244 }
else if (pos == 5) {
12250 folder =
a->argv[4];
12251 wordlen = strlen(
word);
12263 if (
id && !strncasecmp(
word,
msg->msg_id, wordlen) && ++which >
state) {
12281 e->
command =
"voicemail forward";
12283 "Usage: voicemail forward <from_mailbox> <from_context> <from_folder> <messageid> <to_mailbox> <to_context> <to_folder>\n"
12284 " Forward message <messageid> in mailbox <mailbox>@<context> <from_folder>\n"
12285 " to mailbox <mailbox>@<context> <to_folder>\n";
12293 if (
a->argc != 9) {
12308 e->
command =
"voicemail move";
12310 "Usage: voicemail move <mailbox> <context> <from_folder> <messageid> <to_folder>\n"
12311 " Move message <messageid> in mailbox <mailbox>&<context> from <from_folder> to <to_folder>\n";
12319 if (
a->argc != 7) {
12334 e->
command =
"voicemail remove";
12336 "Usage: voicemail remove <mailbox> <context> <from_folder> <messageid>\n"
12337 " Remove message <messageid> from <from_folder> in mailbox <mailbox>@<context>\n";
12345 if (
a->argc != 6) {
12364 char prefixstr[80] =
"";
12365 char ext_context[256]=
"";
12372 int silentexit = 0;
12374 signed char record_gain = 0;
12376 int play_folder = 0;
12405 if (
args.argc == 2) {
12415 record_gain = (
signed char) gain;
12435 if (play_folder > 9 || play_folder < 0) {
12437 "Invalid value '%s' provided for folder autoplay option. Defaulting to 'INBOX'\n",
12447 while (*(
args.argv0)) {
12448 if (*(
args.argv0) ==
's')
12450 else if (*(
args.argv0) ==
'p')
12515 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
12516 pthread_setspecific(ts_vmstate.key, &vms);
12518 vms.interactive = 1;
12522 vmstate_insert(&vms);
12523 init_vm_state(&vms);
12529 ast_channel_language_set(chan, vmu->
language);
12534 ast_trace(-1,
"Before open_mailbox\n");
12537 ast_trace(-1,
"open mailbox: %d\n", res);
12545 ast_trace(-1,
"open mailbox: %d\n", res);
12554 ast_trace(-1,
"open mailbox: %d\n", res);
12571 ast_trace(-1,
"open mailbox: %d\n", res);
12609 if ((cmd ==
't') || (cmd ==
'#')) {
12615 }
else if (cmd < 0) {
12624 ast_debug(3,
"Checking quotas: comparing %u to %u\n", vms.quota_usage, vms.quota_limit);
12625 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
12626 ast_debug(1,
"*** QUOTA EXCEEDED!!\n");
12643 isprint(cmd) ? cmd :
'?', isprint(cmd) ? cmd :
'?');
12647 while ((cmd > -1) && (cmd !=
't') && (cmd !=
'#')) {
12649 ast_trace(-1,
"Main menu: %d %c\n", cmd, (cmd >= 32 && cmd <= 126 ? cmd :
' '));
12665 isprint(cmd) ? cmd :
'?', isprint(cmd) ? cmd :
'?');
12668 }
else if (cmd > 0) {
12672 ast_trace(-1,
"close mailbox: %d\n", res);
12676 if (cmd != 11) in_urgent = 0;
12679 ast_trace(-1,
"open mailbox: %d\n", res);
12699 while ((cmd > -1) && (cmd !=
't') && (cmd !=
'#')) {
12706 ast_trace(-1,
"advanced options: %d\n", cmd);
12716 ast_verb(3,
"Callback Requested\n");
12719 ast_trace(-1,
"advanced options: %d\n", cmd);
12737 ast_trace(-1,
"advanced options: %d\n", cmd);
12764 ast_trace(-1,
"forward message: %d\n", cmd);
12807 isprint(cmd) ? cmd :
'?', isprint(cmd) ? cmd :
'?');
12830 ast_trace(-1,
"close mailbox: %d\n", res);
12835 ast_trace(-1,
"open mailbox: %d\n", res);
12838 ast_debug(1,
"No more new messages, opened INBOX and got %d Urgent messages\n", vms.
lastmsg + 1);
12865 ast_trace(-1,
"close mailbox: %d\n", res);
12870 ast_trace(-1,
"open mailbox: %d\n", res);
12873 ast_debug(1,
"No more urgent messages, opened INBOX and got %d new messages\n", vms.
lastmsg + 1);
12892 if (play_folder == 0) {
12899 else if (play_folder == 1)
12903 if (play_folder == 0) {
12910 else if (play_folder == 1)
12926 if (in_urgent == 1) {
12931 ast_trace(-1,
"close mailbox: %d\n", res);
12936 ast_trace(-1,
"open mailbox: %d\n", res);
12939 ast_debug(1,
"No more urgent messages, opened INBOX and got %d new messages\n", vms.
lastmsg + 1);
12961 ast_trace(-1,
"forward message: %d\n", res);
12974 ast_trace(-1,
"close mailbox: %d\n", res);
12979 ast_trace(-1,
"open mailbox: %d\n", res);
12982 ast_debug(1,
"No more urgent messages, opened INBOX and got %d new messages\n", vms.
lastmsg + 1);
13003 isprint(cmd) ? cmd :
'?', isprint(cmd) ? cmd :
'?');
13008 }
else if (cmd > 0) {
13009 box = cmd = cmd -
'0';
13013 ast_trace(-1,
"save to folder: %d\n", res);
13015#ifndef IMAP_STORAGE
13027 snprintf(vms.
fn,
sizeof(vms.
fn),
"vm-%s",
mbox(vmu, box));
13056 ast_trace(-1,
"close mailbox: %d\n", res);
13061 ast_trace(-1,
"open mailbox: %d\n", res);
13064 ast_debug(1,
"No more urgent messages, opened INBOX and got %d new messages\n", vms.
lastmsg + 1);
13113 ast_trace(-1,
"open mailbox: %d\n", res);
13124 if ((cmd ==
't') || (cmd ==
'#')) {
13152 int new = 0, old = 0, urgent = 0;
13153 snprintf(ext_context,
sizeof(ext_context),
"%s@%s", vms.
username, vmu->
context);
13161 ast_debug(3,
"*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n", deleted, expungeonhangup);
13162 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream !=
NULL) {
13164#ifdef HAVE_IMAP_TK2006
13165 if (LEVELUIDPLUS (vms.mailstream)) {
13166 mail_expunge_full(vms.mailstream, NIL, EX_UID);
13169 mail_expunge(vms.mailstream);
13175 vmstate_delete(&vms);
13182 pthread_setspecific(ts_vmstate.key,
NULL);
13200 memset(&leave_options, 0,
sizeof(leave_options));
13205 if (
args.argc == 2) {
13231 res =
ast_app_getdata(chan,
"vm-whichbox", temp,
sizeof(temp) - 1, 0);
13281 ast_log(
LOG_ERROR,
"Voicemail data file %s/%d.txt has no [message] category?\n", dir, msg);
13302 ast_log(
LOG_WARNING,
"Mailbox %s in context %s begins with '*' character. The '*' character,"
13303 "\n\twhen it is the first character in a mailbox or password, is used to jump to a"
13304 "\n\tpredefined extension 'a'. A mailbox or password beginning with '*' is not valid"
13305 "\n\tand will be ignored.\n", box,
context);
13312 ast_log(
LOG_WARNING,
"\nIt has been detected that you have defined mailbox '%s' in separate\
13313 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
13314 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
13315 \n\tamend your voicemail.conf file to avoid this situation.\n", box);
13345 int new = 0, old = 0, urgent = 0;
13356 if ((s =
strsep(&stringp,
","))) {
13359 "\n\tmust be reset in voicemail.conf.\n", box);
13364 if (stringp && (s =
strsep(&stringp,
","))) {
13367 if (stringp && (s =
strsep(&stringp,
","))) {
13370 if (stringp && (s =
strsep(&stringp,
","))) {
13390 imap_logout(mailbox_full);
13397#ifdef TEST_FRAMEWORK
13403 static const char options_string[] =
"attach=yes|attachfmt=wav49|"
13404 "serveremail=someguy@digium.com|fromstring=Voicemail System|tz=central|delete=yes|saycid=yes|"
13405 "sendvoicemail=yes|review=yes|tempgreetwarn=yes|messagewrap=yes|operator=yes|leaveurgent=yes|"
13406 "envelope=yes|moveheard=yes|sayduration=yes|saydurationm=5|forcename=yes|"
13407 "forcegreetings=yes|callback=somecontext|dialout=somecontext2|"
13408 "exitcontext=somecontext3|minsecs=10|maxsecs=100|nextaftercmd=yes|"
13409 "backupdeleted=50|volgain=1.3|passwordlocation=spooldir|emailbody="
13410 "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message|emailsubject="
13411 "[PBX]: New message \\\\${VM_MSGNUM}\\\\ in mailbox ${VM_MAILBOX}";
13413 static const char option_string2[] =
"imapuser=imapuser|imappassword=imappasswd|"
13414 "imapfolder=INBOX|imapvmshareid=6000|imapserver=imapserver|imapport=1234|imapflags=flagged";
13419 info->name =
"vmuser";
13420 info->category =
"/apps/app_voicemail/";
13421 info->summary =
"Vmuser unit test";
13422 info->description =
13423 "This tests passing all supported parameters to apply_options, the voicemail user config parser";
13441 if (strcasecmp(vmu->
attachfmt,
"wav49")) {
13445 if (strcasecmp(vmu->
fromstring,
"Voicemail System")) {
13449 if (strcasecmp(vmu->
serveremail,
"someguy@digium.com")) {
13453 if (!vmu->
emailsubject || strcasecmp(vmu->
emailsubject,
"[PBX]: New message \\${VM_MSGNUM}\\ in mailbox ${VM_MAILBOX}")) {
13457 if (!vmu->
emailbody || strcasecmp(vmu->
emailbody,
"Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message")) {
13461 if (strcasecmp(vmu->
zonetag,
"central")) {
13521 if (strcasecmp(vmu->
callback,
"somecontext")) {
13525 if (strcasecmp(vmu->
dialout,
"somecontext2")) {
13529 if (strcasecmp(vmu->
exit,
"somecontext3")) {
13560 if (strcasecmp(vmu->imapuser,
"imapuser")) {
13564 if (strcasecmp(vmu->imappassword,
"imappasswd")) {
13568 if (strcasecmp(vmu->imapfolder,
"INBOX")) {
13572 if (strcasecmp(vmu->imapvmshareid,
"6000")) {
13576 if (strcasecmp(vmu->imapserver,
"imapserver")) {
13580 if (strcasecmp(vmu->imapport,
"1234")) {
13584 if (strcasecmp(vmu->imapflags,
"flagged")) {
13614 ast_log(
LOG_ERROR,
"VM_INFO requires an argument (<mailbox>[@<context>],attribute[,folder])\n");
13624 ast_log(
LOG_ERROR,
"VM_INFO requires an argument (<mailbox>[@<context>],attribute[,folder])\n");
13628 memset(&svm, 0,
sizeof(svm));
13631 if (!strncasecmp(arg.attribute,
"exists", 5)) {
13638 if (!strncasecmp(arg.attribute,
"password", 8)) {
13640 }
else if (!strncasecmp(arg.attribute,
"fullname", 8)) {
13642 }
else if (!strncasecmp(arg.attribute,
"email", 5)) {
13644 }
else if (!strncasecmp(arg.attribute,
"pager", 5)) {
13646 }
else if (!strncasecmp(arg.attribute,
"language", 8)) {
13648 }
else if (!strncasecmp(arg.attribute,
"locale", 6)) {
13650 }
else if (!strncasecmp(arg.attribute,
"tz", 2)) {
13652 }
else if (!strncasecmp(arg.attribute,
"count", 5)) {
13661 ast_log(
LOG_ERROR,
"Unable to retrieve message count for mailbox %s\n", arg.mailbox_context);
13665 snprintf(
buf,
len,
"%d", res);
13667 ast_log(
LOG_ERROR,
"Unknown attribute '%s' for VM_INFO\n", arg.attribute);
13687 int silent = 0, skipuser = 0;
13713 }
else if (
mailbox[0] ==
'*') {
13726 const char *cat =
NULL;
13735 "=============================================================\n"
13736 "=== Configured Voicemail Users ==============================\n"
13737 "=============================================================\n"
13743 "=== Mailbox ...\n"
13749 "=== ---------------------------------------------------------\n"
13754 "=============================================================\n"
13773 wordlen = strlen(
word);
13794#define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
13796 int users_counter = 0;
13800 e->
command =
"voicemail show users [for]";
13802 "Usage: voicemail show users [for <context>]\n"
13803 " Lists all mailboxes currently set up\n";
13809 if ((
a->argc < 3) || (
a->argc > 5) || (
a->argc == 4))
13811 if (
a->argc == 5) {
13812 if (strcmp(
a->argv[3],
"for"))
13819 ast_cli(
a->fd,
"You must specify a specific context to show users from realtime!\n");
13827 ast_cli(
a->fd,
"There are no voicemail users currently defined\n");
13850 int newmsgs = 0, oldmsgs = 0;
13851 char count[12], tmp[256] =
"";
13856 snprintf(count,
sizeof(count),
"%d", newmsgs);
13862 ast_cli(
a->fd,
"%d voicemail users configured.\n", users_counter);
13870#define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
13875 e->
command =
"voicemail show zones";
13877 "Usage: voicemail show zones\n"
13878 " Lists zone message formats\n";
13894 ast_cli(
a->fd,
"There are no voicemail zones currently defined\n");
13907#define ALIASES_OUTPUT_FORMAT "%-32s %-32s\n"
13912 e->
command =
"voicemail show aliases";
13914 "Usage: voicemail show aliases\n"
13915 " Lists mailbox aliases\n";
13925 ast_cli(
a->fd,
"Aliases are not enabled\n");
13947 e->
command =
"voicemail reload";
13949 "Usage: voicemail reload\n"
13950 " Reload voicemail configuration\n";
13959 ast_cli(
a->fd,
"Reloading voicemail configuration...\n");
13978 int new = 0, old = 0, urgent = 0;
13988 if (imap_poll_logout) {
14004 struct timespec ts = { 0, };
14005 struct timeval wait;
14014 ts.tv_sec = wait.tv_sec;
14015 ts.tv_nsec = wait.tv_usec * 1000;
14026static void imap_logout(
const char *mailbox_id)
14039 memset(&vmus, 0,
sizeof(vmus));
14045 vms = get_vm_state_by_imapuser(vmu->imapuser, 0);
14054 vms->mailstream = mail_close(vms->mailstream);
14057 vmstate_delete(vms);
14060static int imap_close_subscribed_mailbox(
struct ast_mwi_state *mwi_state,
void *data)
14083 imap_close_subscribed_mailbox(mwi_state,
NULL);
14157 const char* event_name,
14158 const char* actionid
14166 if((s ==
NULL) || (vmu ==
NULL) || (event_name ==
NULL) || (actionid ==
NULL)) {
14186 ast_log(
LOG_ERROR,
"Could not get mailbox count. user[%s], context[%s]\n",
14194 "VMContext: %s\r\n"
14195 "VoiceMailbox: %s\r\n"
14199 "ServerEmail: %s\r\n"
14200 "FromString: %s\r\n"
14201 "MailCommand: %s\r\n"
14207 "ExitContext: %s\r\n"
14208 "SayDurationMinimum: %d\r\n"
14209 "SayEnvelope: %s\r\n"
14211 "AttachMessage: %s\r\n"
14212 "AttachmentFormat: %s\r\n"
14213 "DeleteMessage: %s\r\n"
14214 "VolumeGain: %.2f\r\n"
14215 "CanReview: %s\r\n"
14216 "CanMarkUrgent: %s\r\n"
14217 "CallOperator: %s\r\n"
14218 "MaxMessageCount: %d\r\n"
14219 "MaxMessageLength: %d\r\n"
14220 "NewMessageCount: %d\r\n"
14221 "OldMessageCount: %d\r\n"
14224 "IMAPServer: %s\r\n"
14226 "IMAPFlags: %s\r\n"
14282 const char* event_name,
14283 const char* actionid)
14287 int nummessages = 0;
14292 if (!mailbox_snapshot) {
14300 for (i = 0; i < mailbox_snapshot->
folders; i++) {
14345 (at = strchr(mwi_state->
uniqueid,
'@')) &&
14349 (at = strchr(mwi_state->
uniqueid,
'@')) &&
14350 strcmp(
context, at + 1) == 0) ||
14353 (at = strchr(mwi_state->
uniqueid,
'@')) &&
14355 strcmp(
context, at + 1) == 0)
14375 char actionid[128];
14387 actionid[0] =
'\0';
14389 snprintf(actionid,
sizeof(actionid),
"ActionID: %s\r\n",
id);
14393 memset(&svm, 0,
sizeof(svm));
14397 astman_send_ack(s, m,
"There is no voicemail user of the given info.");
14421 char actionid[128];
14425 actionid[0] =
'\0';
14427 snprintf(actionid,
sizeof(actionid),
"ActionID: %s\r\n",
id);
14433 astman_send_ack(s, m,
"There are no voicemail users currently defined.");
14462 char actionid[128];
14473 actionid[0] =
'\0';
14475 snprintf(actionid,
sizeof(actionid),
"ActionID: %s\r\n",
id);
14479 memset(&svm, 0,
sizeof(svm));
14483 astman_send_ack(s, m,
"There is no voicemail user matching the given user.");
14663 if (!
str->used ||
str->str[
str->used - 1] !=
'\r') {
14718#ifdef TEST_FRAMEWORK
14730 size_t from_len = strlen(
alias) + 1;
14731 size_t to_len = strlen(
mailbox) + 1;
14733 mapping =
ao2_alloc(
sizeof(*mapping) + from_len + to_len,
NULL);
14773 char storage[strlen(
var->value) + 1];
14780 strcpy(storage,
var->value);
14805 if (strcasecmp(cat,
"general") == 0
14807 || strcasecmp(cat,
"zonemessages") == 0) {
14822 char *q, *stringp, *tmp;
14824 unsigned int tmpadsi[4];
14825 long tps_queue_low;
14826 long tps_queue_high;
14878 strcpy(odbc_database,
"asterisk");
14883 strcpy(odbc_table,
"voicemessages");
14887 odbc_table_len = strlen(odbc_table);
14923 if (sscanf(
val,
"%30d", &x) == 1)
14992 expungeonhangup = 0;
14994 expungeonhangup = 1;
14996 expungeonhangup = 1;
15023 imap_poll_logout = 0;
15031 mail_parameters(NIL, SET_READTIMEOUT, (
void *) (atol(
val)));
15033 mail_parameters(NIL, SET_READTIMEOUT, (
void *) 60L);
15037 mail_parameters(NIL, SET_WRITETIMEOUT, (
void *) (atol(
val)));
15039 mail_parameters(NIL, SET_WRITETIMEOUT, (
void *) 60L);
15043 mail_parameters(NIL, SET_OPENTIMEOUT, (
void *) (atol(
val)));
15045 mail_parameters(NIL, SET_OPENTIMEOUT, (
void *) 60L);
15049 mail_parameters(NIL, SET_CLOSETIMEOUT, (
void *) (atol(
val)));
15051 mail_parameters(NIL, SET_CLOSETIMEOUT, (
void *) 60L);
15067 ast_debug(1,
"Enabled SMDI voicemail notification\n");
15071 ast_debug(1,
"No SMDI interface set, trying default (/dev/ttyS0)\n");
15075 ast_log(
AST_LOG_ERROR,
"No valid SMDI interface specified, disabling SMDI voicemail notification\n");
15090 if (sscanf(
val,
"%30d", &x) == 1) {
15099 if (sscanf(
val,
"%30d", &x) == 1) {
15116 ast_log(
LOG_ERROR,
"Error processing format string, defaulting to format 'wav'\n");
15124 if (sscanf(
val,
"%30d", &x) == 1) {
15132 if (sscanf(
val,
"%30d", &x) == 1) {
15141 if (sscanf(
val,
"%30d", &x) == 1) {
15150 if (sscanf(
val,
"%30d", &x) == 1) {
15168 ast_debug(1,
"VM_CID Internal context string: %s\n",
val);
15172 q =
strsep(&stringp,
",");
15173 while ((*q ==
' ')||(*q ==
'\t'))
15183 ast_debug(1,
"VM Review Option disabled globally\n");
15191 ast_debug(1,
"VM leave urgent messages disabled globally\n");
15198 ast_debug(1,
"VM Temporary Greeting Reminder Option disabled globally\n");
15201 ast_debug(1,
"VM Temporary Greeting Reminder Option enabled globally\n");
15205 ast_debug(1,
"VM next message wrap disabled globally\n");
15211 ast_debug(1,
"VM Operator break disabled globally\n");
15217 ast_debug(1,
"VM CID Info before msg disabled globally\n");
15223 ast_debug(1,
"Send Voicemail msg disabled globally\n");
15229 ast_debug(1,
"ENVELOPE before msg enabled globally\n");
15235 ast_debug(1,
"Move Heard enabled globally\n");
15241 ast_debug(1,
"Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
15247 ast_debug(1,
"Duration info before msg enabled globally\n");
15254 if (sscanf(
val,
"%30d", &x) == 1) {
15262 ast_debug(1,
"We are not going to skip to the next msg after save/delete\n");
15328 val =
"voicemail.conf";
15330 if (!(strcmp(
val,
"spooldir"))) {
15350 strcpy(
charset,
"ISO-8859-1");
15376 sscanf(
val,
"%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
15377 for (x = 0; x < 4; x++) {
15378 memcpy(&
adsifdn[x], &tmpadsi[x], 1);
15382 sscanf(
val,
"%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
15383 for (x = 0; x < 4; x++) {
15384 memcpy(&
adsisec[x], &tmpadsi[x], 1);
15413 if (sscanf(
val,
"%30ld", &tps_queue_high) != 1 || tps_queue_high <= 0) {
15418 tps_queue_low = -1;
15420 if (sscanf(
val,
"%30ld", &tps_queue_low) != 1 ||
15421 tps_queue_low < -1 || tps_queue_high < tps_queue_low) {
15423 tps_queue_low = -1;
15462 ast_debug(2,
"About to try retrieving name file %s\n", dir);
15508 ast_log(
LOG_NOTICE,
"Failed reading voicemail password from %s, using secret from config file\n", secretfn);
15567#ifdef TEST_FRAMEWORK
15582 static const char TEST_CONTEXT[] =
"very_long_unique_context_so_that_nobody_will_ever_have_the_same_one_configured_3141592653";
15590 .
write = fake_write,
15596 info->name =
"vmsayname_exec";
15597 info->category =
"/apps/app_voicemail/";
15598 info->summary =
"Vmsayname unit test";
15599 info->description =
15600 "This tests passing various parameters to vmsayname";
15607 NULL,
NULL, 0, 0,
"TestChannel1"))) {
15608 goto exit_vmsayname_test;
15614 goto exit_vmsayname_test;
15634 goto exit_vmsayname_test;
15639 goto exit_vmsayname_test;
15644 if ((res = symlink(dir, dir2))) {
15646 goto exit_vmsayname_test;
15661exit_vmsayname_test:
15684 struct test_files *tmp =
ast_alloca(
sizeof(
struct test_files) * 3);
15686 const char origweasels[] =
"tt-weasels";
15687 const char testcontext[] =
"test";
15688 const char testmailbox[] =
"00000000";
15689 const char testspec[] =
"00000000@test";
15691 int new, old, urgent;
15692 const char *folders[3] = {
"Old",
"Urgent",
"INBOX" };
15693 const int folder2mbox[3] = { 1, 11, 0 };
15694 const int expected_results[3][12] = {
15696 { 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 },
15697 { 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
15698 { 1, 1, 1, 1, 0, 2, 1, 1, 1, 1, 1, 2 },
15703 info->name =
"test_voicemail_msgcount";
15704 info->category =
"/apps/app_voicemail/";
15705 info->summary =
"Test Voicemail status checks";
15706 info->description =
15707 "Verify that message counts are correct when retrieved through the public API";
15714 snprintf(syscmd,
sizeof(syscmd),
"rm -rf \"%s%s/%s\"",
VM_SPOOL_DIR, testcontext, testmailbox);
15717 syserr > 0 ? strerror(syserr) :
"unable to fork()");
15728 memset(&svm, 0,
sizeof(svm));
15729 if (!(vmu =
find_user(&svm, testcontext, testmailbox)) &&
15739 memset(&vms, 0,
sizeof(vms));
15742 for (i = 0; i < 3; i++) {
15743 create_dirpath(tmp[i].dir,
sizeof(tmp[i].dir), testcontext, testmailbox, folders[i]);
15745 snprintf(tmp[i].txtfile,
sizeof(tmp[i].txtfile),
"%s.txt", tmp[i].
file);
15748 snprintf(syscmd,
sizeof(syscmd),
"cp \"%s/sounds/en/%s.gsm\" \"%s/%s/%s/%s/msg0000.gsm\"",
ast_config_AST_DATA_DIR, origweasels,
15752 syserr > 0 ? strerror(syserr) :
"unable to fork()");
15761 if ((txt = fopen(tmp[i].txtfile,
"w+"))) {
15762 fprintf(txt,
"; just a stub\n[message]\nflag=%s\n", strcmp(folders[i],
"Urgent") ?
"" :
"Urgent");
15770 STORE(tmp[i].dir, testmailbox, testcontext, 0, chan, vmu,
"gsm", 600, &vms, strcmp(folders[i],
"Urgent") ?
"" :
"Urgent",
NULL);
15773 for (j = 0; j < 3; j++) {
15782 new = old = urgent = 0;
15786 }
else if (old != expected_results[i][3 + 0] ||
new != expected_results[i][3 + 2]) {
15788 testspec, old, expected_results[i][3 + 0],
new, expected_results[i][3 + 2]);
15792 new = old = urgent = 0;
15796 }
else if (old != expected_results[i][6 + 0] ||
15797 urgent != expected_results[i][6 + 1] ||
15798 new != expected_results[i][6 + 2] ) {
15799 ast_test_status_update(
test,
"inboxcount2(%s) returned old=%d (expected %d), urgent=%d (expected %d), and new=%d (expected %d)\n",
15800 testspec, old, expected_results[i][6 + 0], urgent, expected_results[i][6 + 1],
new, expected_results[i][6 + 2]);
15804 new = old = urgent = 0;
15805 for (j = 0; j < 3; j++) {
15808 testspec, folders[j],
ast_app_messagecount(testspec, folders[j]), expected_results[i][9 + j]);
15814 for (i = 0; i < 3; i++) {
15834 snprintf(syscmd,
sizeof(syscmd),
"rm -rf \"%s%s/%s\"",
VM_SPOOL_DIR, testcontext, testmailbox);
15837 syserr > 0 ? strerror(syserr) :
"unable to fork()");
15848 char testcontext[] =
"test";
15849 char testmailbox[] =
"00000000";
15850 char from[] =
"test@example.net", cidnum[] =
"1234", cidname[] =
"Mark Spencer", format[] =
"gsm";
15851 char attach[256], attach2[256];
15852 char buf[256] =
"";
15860 enum { INT, FLAGVAL, STATIC, STRPTR }
type;
15867 {
"plain jane config", STATIC, vmus.
password, .u.strval =
"1234" },
15868 {
"emailsubject", STRPTR, vmus.
emailsubject, .u.strval =
"Oogly boogly\xf8koogly with what appears to be UTF-8" },
15869 {
"emailbody", STRPTR, vmus.
emailbody, .u.strval =
"This is a test\n\twith multiple\nlines\nwithin\n" },
15870 {
"serveremail", STATIC, vmus.
serveremail, .u.strval =
"\"\xf8Something\xe8that\xd8seems to have UTF-8 chars\" <test@example.net>" },
15871 {
"attachment flag", FLAGVAL, &vmus.
flags, .u.intval =
VM_ATTACH },
15872 {
"attach2", STRPTR, attach2, .u.strval =
"" },
15873 {
"attach", STRPTR, attach, .u.strval =
"" },
15879 info->name =
"test_voicemail_notify_endl";
15880 info->category =
"/apps/app_voicemail/";
15881 info->summary =
"Test Voicemail notification end-of-line";
15882 info->description =
15883 "Verify that notification emails use a consistent end-of-line character";
15892 if (!(vmu =
find_user(&vmus, testcontext, testmailbox)) &&
15898 if (vmu != &vmus && !(vmu =
find_user(&vmus, testcontext, testmailbox))) {
15910 for (which = 0; which <
ARRAY_LEN(test_items); which++) {
15913 if (ftruncate(fileno(
file), 0)) {
15920 if (test_items[which].
type == INT) {
15921 *((
int *) test_items[which].location) = test_items[which].u.intval;
15922 }
else if (test_items[which].
type == FLAGVAL) {
15928 }
else if (test_items[which].
type == STATIC) {
15929 strcpy(test_items[which].location, test_items[which].u.strval);
15930 }
else if (test_items[which].
type == STRPTR) {
15931 test_items[which].location = test_items[which].u.strval;
15934 make_email_file(
file, from, vmu, 0, testcontext, testmailbox,
"INBOX", cidnum, cidname, attach, attach2, format, 999, 1, chan,
NULL, 0,
NULL,
NULL);
15938 (strlen(
buf) > 1 &&
15940 buf[strlen(
buf) - 2] !=
'\r'
15942 buf[strlen(
buf) - 2] ==
'\r'
15945 ||
buf[strlen(
buf) - 1] !=
'\n') {
15968 info->name =
"test_voicemail_load_config";
15969 info->category =
"/apps/app_voicemail/";
15970 info->summary =
"Test loading Voicemail config";
15971 info->description =
15972 "Verify that configuration is loaded consistently. "
15973 "This is to test regressions of ASTERISK-18838 where it was noticed that "
15974 "some options were loaded after the mailboxes were instantiated, causing "
15975 "those options not to be set correctly.";
15985 if (!(
file = fdopen(fd,
"w"))) {
15990 fputs(
"[general]\ncallback=somecontext\nlocale=de_DE.UTF-8\ntz=european\n[test]",
file);
15991 fputs(
"00000001 => 9999,Mr. Test,,,callback=othercontext|locale=nl_NL.UTF-8|tz=central\n",
file);
15992 fputs(
"00000002 => 9999,Mrs. Test\n",
file);
16000 load_config_from_memory(1, cfg);
16003#define CHECK(u, attr, value) else if (strcmp(u->attr, value)) { \
16004 ast_test_status_update(test, "mailbox %s should have %s '%s', but has '%s'\n", \
16005 u->mailbox, #attr, value, u->attr); res = AST_TEST_FAIL; break; }
16009 if (!strcmp(vmu->
mailbox,
"00000001")) {
16011 CHECK(vmu,
callback,
"othercontext")
16012 CHECK(vmu,
locale, "nl_NL.UTF-8")
16013 CHECK(vmu,
zonetag, "central")
16014 } else
if (!strcmp(vmu->
mailbox, "00000002")) {
16016 CHECK(vmu,
callback,
"somecontext")
16017 CHECK(vmu,
locale, "de_DE.UTF-8")
16018 CHECK(vmu,
zonetag, "european")
16037 const char testcontext[] =
"test";
16038 const char testmailbox[] =
"00000000";
16039 const char vminfo_cmd[] =
"VM_INFO";
16040 char vminfo_buf[256], vminfo_args[256];
16043 int test_counter = 0;
16046 char *vminfo_test_args;
16047 char *vminfo_expected;
16051 {
"00000000@test,badparam",
"", -1 },
16052 {
"00000000@test",
"", -1 },
16053 {
"00000000@test,exists",
"1", 0 },
16054 {
"11111111@test,exists",
"0", 0 },
16055 {
"00000000@test,email",
"vm-info-test@example.net", 0 },
16056 {
"11111111@test,email",
"", 0 },
16057 {
"00000000@test,fullname",
"Test Framework Mailbox", 0 },
16058 {
"00000000@test,pager",
"vm-info-pager-test@example.net", 0 },
16059 {
"00000000@test,locale",
"en_US", 0 },
16060 {
"00000000@test,tz",
"central", 0 },
16061 {
"00000000@test,language",
"en", 0 },
16062 {
"00000000@test,password",
"9876", 0 },
16067 info->name =
"test_voicemail_vm_info";
16068 info->category =
"/apps/app_voicemail/";
16069 info->summary =
"VM_INFO unit test";
16070 info->description =
16071 "This tests passing various parameters to VM_INFO";
16104 for (test_counter = 0; test_counter <
ARRAY_LEN(test_items); test_counter++) {
16105 ast_copy_string(vminfo_args, test_items[test_counter].vminfo_test_args,
sizeof(vminfo_args));
16106 test_ret =
acf_vm_info(chan, vminfo_cmd, vminfo_args, vminfo_buf,
sizeof(vminfo_buf));
16107 if (strcmp(vminfo_buf, test_items[test_counter].vminfo_expected)) {
16108 ast_test_status_update(
test,
"VM_INFO response was: '%s', but expected: '%s'\n", vminfo_buf, test_items[test_counter].vminfo_expected);
16111 if (!(test_ret == test_items[test_counter].vminfo_ret)) {
16112 ast_test_status_update(
test,
"VM_INFO return code was: '%i', but expected '%i'\n", test_ret, test_items[test_counter].vminfo_ret);
16170#ifdef TEST_FRAMEWORK
16181#ifdef TEST_FRAMEWORK
16182 ast_uninstall_vm_test_functions();
16213 prnt(where,
"Alias: %s Mailbox: %s", mapping->
alias, mapping->
mailbox);
16243 alias_mailbox_mapping_hash_fn,
NULL, alias_mailbox_mapping_cmp_fn);
16245 ast_log(
LOG_ERROR,
"Unable to create alias_mailbox_mappings container\n");
16251 ast_log(
LOG_ERROR,
"Unable to register alias_mailbox_mappings container\n");
16258 mailbox_alias_mapping_hash_fn,
NULL, mailbox_alias_mapping_cmp_fn);
16260 ast_log(
LOG_ERROR,
"Unable to create mailbox_alias_mappings container\n");
16268 ast_log(
LOG_ERROR,
"Unable to register mailbox_alias_mappings container\n");
16301#ifdef TEST_FRAMEWORK
16311 ast_log(
LOG_ERROR,
"Failure registering applications, functions or tests\n");
16334#ifdef TEST_FRAMEWORK
16335 ast_install_vm_test_functions(vm_test_create_user, vm_test_destroy_user);
16347 char destination[80] =
"";
16351 ast_verb(3,
"Destination number will be entered manually\n");
16352 while (retries < 3 && cmd !=
't') {
16353 destination[1] =
'\0';
16362 destination[0] = cmd;
16371 ast_verb(3,
"User hit '*' to cancel outgoing call\n");
16374 if ((cmd =
ast_readstring(chan, destination + strlen(destination),
sizeof(destination) - 1, 6000, 10000,
"#")) < 0)
16380 isprint(cmd) ? cmd :
'?', isprint(cmd) ? cmd :
'?');
16382 if (retries >= 3) {
16387 ast_verb(3,
"Destination number is CID number '%s'\n", num);
16392 if (destination[strlen(destination) -1 ] ==
'*')
16394 ast_verb(3,
"Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context,
ast_channel_context(chan));
16421 const char *origtime, *
context;
16432 snprintf(filename,
sizeof(filename),
"%s.txt", vms->
fn);
16467 while ((res > -1) && (res !=
't')) {
16491 ast_verb(3,
"Caller can not specify callback number - no dialout context available\n");
16513 ast_verb(3,
"Confirm CID number '%s' is number to use for callback\n", num);
16544 isprint(res) ? res :
'?', isprint(res) ? res :
'?');
16550 else if (res ==
'*')
16562 ast_verb(3,
"No CID number available, no reply sent\n");
16569 memset(&vmu2, 0,
sizeof(vmu2));
16576 ast_verb(3,
"Leaving voicemail for '%s' in context '%s'\n", num, vmu->
context);
16578 memset(&leave_options, 0,
sizeof(leave_options));
16589 ast_verb(3,
"No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->
context);
16603#ifndef IMAP_STORAGE
16606 vms->
heard[msg] = 1;
16614 int outsidecaller,
struct ast_vm_user *vmu,
int *duration,
int *sound_duration,
const char *unlockdir,
16620 int max_attempts = 3;
16623 int msg_exists = 0;
16624 signed char zero_gain = 0;
16626 char *acceptdtmf =
"#";
16627 char *canceldtmf =
"";
16628 int canceleddtmf = 0;
16629 SCOPE_ENTER(3,
"%s: rf: %s fmt: %s type: %s vmu: %s\n",
16630 ast_channel_name(chan), recordfile, fmt, outsidecaller ?
"msg" :
"greeting",
16635 if (duration ==
NULL) {
16639 if (!outsidecaller)
16640 snprintf(tempfile,
sizeof(tempfile),
"%s.tmp", recordfile);
16646 while ((cmd >= 0) && (cmd !=
't')) {
16655 ast_verb(3,
"Saving message as is\n");
16656 if (!outsidecaller) {
16657 ast_trace(-1,
"Renaming greeting '%s' to '%s'\n", tempfile, recordfile);
16660 if (!forwardintro) {
16663 if (!outsidecaller) {
16665 ast_trace(-1,
"Saving greeting '%s'\n", recordfile);
16666 SCOPE_CALL(-1,
STORE, recordfile, vmu->
mailbox, vmu->
context, -1, chan, vmu, fmt, *duration, vms,
flag, msg_id);
16674 ast_verb(3,
"Reviewing the message\n");
16675 ast_trace(-1,
"Reviewing '%s'\n", tempfile);
16682 ast_verb(3,
"Re-recording the message\n");
16684 ast_verb(3,
"Recording the message\n");
16686 if (recorded && outsidecaller) {
16687 if (forwardintro) {
16697 SCOPE_EXIT_RTN_VALUE(cmd,
"User hung up before message could be rerecorded. Deleted '%s'\n", tempfile);
16705 ast_trace(-1,
"Recording '%s'\n", tempfile);
16706 cmd =
ast_play_and_record_full(chan, playfile, tempfile, maxtime, fmt, duration, sound_duration, 0,
silencethreshold,
maxsilence, unlockdir, acceptdtmf, canceldtmf, 0,
AST_RECORD_IF_EXISTS_OVERWRITE);
16707 if (strchr(canceldtmf, cmd)) {
16715 if (!outsidecaller) {
16720 outsidecaller ?
"Saved message " :
"Deleted greeting \n", tempfile);
16724 }
else if (cmd ==
'*') {
16727 }
else if (vmu->review && sound_duration && (*sound_duration < 5)) {
16729 ast_verb(3,
"Message too short\n");
16733 }
else if (vmu->review && (cmd == 2 && sound_duration && *sound_duration < (
maxsilence + 3))) {
16735 ast_verb(3,
"Nothing recorded\n");
16752 ast_verb(3,
"marking message as Urgent\n");
16754 strcpy(
flag,
"Urgent");
16756 ast_verb(3,
"UNmarking message as Urgent\n");
16783 if (outsidecaller) {
16795 if (msg_exists || recorded) {
16796 ast_trace(-1,
"Reviewing '%s'\n", tempfile);
16801 ast_trace(-1,
"Saving '%s' to '%s'\n", tempfile, recordfile);
16805 }
else if (cmd ==
'4') {
16808 strcpy(
flag,
"Urgent");
16813 ast_trace(-1,
"Deleting '%s'\n", tempfile);
16857 if (attempts > max_attempts) {
16862 if (!outsidecaller && (cmd == -1 || cmd ==
't')) {
16864 ast_trace(-1,
"Deleting '%s' on hangup or timeout\n", tempfile);
16868 if (cmd !=
't' && outsidecaller)
16878 if (!(msg_snapshot =
ast_calloc(1,
sizeof(*msg_snapshot)))) {
16887 return msg_snapshot;
16898#ifdef TEST_FRAMEWORK
16900static int vm_test_destroy_user(
const char *
context,
const char *
mailbox)
16918static int vm_test_create_user(
const char *
context,
const char *
mailbox)
16945 int snapshot_index,
16961 snprintf(filename,
sizeof(filename),
"%s.txt", vms->
fn);
16985 filename,
id,
sizeof(
id), vmu, mailbox_index))) {
17016 switch (sort_val) {
17029 if (descending &&
val >= 0) {
17033 }
else if (!descending &&
val <= 0) {
17059 const char *folder,
17062 int combine_INBOX_and_OLD)
17069 int this_index_only = -1;
17076 ast_log(
LOG_WARNING,
"Cannot create a mailbox snapshot since no mailbox was specified\n");
17080 memset(&vmus, 0,
sizeof(vmus));
17086 this_index_only = i;
17090 if (this_index_only == -1) {
17101 if (!(mailbox_snapshot =
ast_calloc(1,
sizeof(*mailbox_snapshot)))) {
17115 for (i = 0; i < mailbox_snapshot->
folders; i++) {
17116 int msg_folder_index = i;
17123 if (!(this_index_only == -1 || this_index_only == i || (this_index_only == inbox_index && combine_INBOX_and_OLD && (i == old_index || i == urgent_index)))) {
17128 if (combine_INBOX_and_OLD && (i == old_index || i == urgent_index)) {
17129 msg_folder_index = inbox_index;
17132 memset(&vms, 0,
sizeof(vms));
17140 goto snapshot_cleanup;
17148 goto snapshot_cleanup;
17154 goto snapshot_cleanup;
17166 vmstate_delete(&vms);
17171 return mailbox_snapshot;
17179 for (i = 0; i < mailbox_snapshot->
folders; i++) {
17212 for (i = 0; i < num_msgs; ++i) {
17213 const char *
msg_id = msg_ids[i];
17216 const char *other_msg_id;
17222 snprintf(filename,
sizeof(filename),
"%s.txt", vms->
fn);
17233 if (!
ast_strlen_zero(other_msg_id) && !strcmp(other_msg_id, msg_id)) {
17238 msg_nums[i] = vms->
curmsg;
17259 int new = 0, old = 0, urgent = 0;
17260 char ext_context[1024];
17262 snprintf(ext_context,
sizeof(ext_context),
"%s@%s", vmu->
mailbox, vmu->
context);
17269 const char *from_context,
17270 const char *from_folder,
17271 const char *to_mailbox,
17272 const char *to_context,
17273 const char *to_folder,
17275 const char *msg_ids [],
17284 int from_folder_index;
17291 ast_log(
LOG_WARNING,
"Cannot forward message because either the from or to mailbox was not specified\n");
17296 ast_log(
LOG_WARNING,
"Invalid number of messages specified to forward: %zu\n", num_msgs);
17301 ast_log(
LOG_WARNING,
"Cannot forward message because the from_folder or to_folder was not specified\n");
17305 memset(&vmus, 0,
sizeof(vmus));
17306 memset(&to_vmus, 0,
sizeof(to_vmus));
17307 memset(&from_vms, 0,
sizeof(from_vms));
17310 if (from_folder_index == -1) {
17323 if (!(to_vmu =
find_user(&to_vmus, to_context, to_mailbox))) {
17324 ast_log(
LOG_WARNING,
"Can't find voicemail user to forward to (%s@%s)\n", to_mailbox, to_context);
17334 if ((res =
open_mailbox(&from_vms, vmu, from_folder_index)) < 0) {
17337 goto vm_forward_cleanup;
17342 if ((from_vms.
lastmsg + 1) < num_msgs) {
17343 ast_log(
LOG_WARNING,
"Folder %s has less than %zu messages\n", from_folder, num_msgs);
17345 goto vm_forward_cleanup;
17348 msg_nums =
ast_alloca(
sizeof(
int) * num_msgs);
17351 goto vm_forward_cleanup;
17355 for (i = 0; i < num_msgs; i++) {
17356 int cur_msg = msg_nums[i];
17361 snprintf(filename,
sizeof(filename),
"%s.txt", from_vms.
fn);
17373 duration = atoi(
value);
17379 from_vms.
deleted[cur_msg] = 1;
17388 goto vm_forward_cleanup;
17398 vmstate_delete(&from_vms);
17414 const char *oldfolder,
17415 const char *old_msg_ids [],
17416 const char *newfolder)
17420 int old_folder_index;
17421 int new_folder_index;
17433 ast_log(
LOG_WARNING,
"Invalid number of messages specified to move: %zu\n", num_msgs);
17438 ast_log(
LOG_WARNING,
"Cannot move message because either oldfolder or newfolder was not specified\n");
17445 memset(&vmus, 0,
sizeof(vmus));
17446 memset(&vms, 0,
sizeof(vms));
17448 if (old_folder_index == -1 || new_folder_index == -1) {
17461 if ((res =
open_mailbox(&vms, vmu, old_folder_index)) < 0) {
17464 goto vm_move_cleanup;
17469 if ((vms.
lastmsg + 1) < num_msgs) {
17470 ast_log(
LOG_WARNING,
"Folder %s has less than %zu messages\n", oldfolder, num_msgs);
17472 goto vm_move_cleanup;
17475 old_msg_nums =
ast_alloca(
sizeof(
int) * num_msgs);
17478 goto vm_move_cleanup;
17482 for (i = 0; i < num_msgs; ++i) {
17485 goto vm_move_cleanup;
17487 vms.
deleted[old_msg_nums[i]] = 1;
17493 goto vm_move_cleanup;
17503 vmstate_delete(&vms);
17518 const char *folder,
17519 const char *msgs[])
17535 ast_log(
LOG_WARNING,
"Invalid number of messages specified to remove: %zu\n", num_msgs);
17544 memset(&vmus, 0,
sizeof(vmus));
17545 memset(&vms, 0,
sizeof(vms));
17548 if (folder_index == -1) {
17563 if ((res =
open_mailbox(&vms, vmu, folder_index)) < 0) {
17566 goto vm_remove_cleanup;
17571 if ((vms.
lastmsg + 1) < num_msgs) {
17574 goto vm_remove_cleanup;
17577 msg_nums =
ast_alloca(
sizeof(
int) * num_msgs);
17580 goto vm_remove_cleanup;
17583 for (i = 0; i < num_msgs; i++) {
17584 vms.
deleted[msg_nums[i]] = 1;
17591 goto vm_remove_cleanup;
17601 vmstate_delete(&vms);
17616 const char *folder,
17617 const char *msg_id,
17642 ast_log(
LOG_WARNING,
"Cannot play message because no message number was specified\n");
17646 memset(&vmus, 0,
sizeof(vmus));
17647 memset(&vms, 0,
sizeof(vms));
17662 goto play2_msg_cleanup;
17668 goto play2_msg_cleanup;
17673 snprintf(filename,
sizeof(filename),
"%s.txt", vms.
fn);
17680 goto play2_msg_cleanup;
17683 duration = atoi(
value);
17696 cb(chan, vms.
fn, duration);
17697 }
else if ((
wait_file(chan, &vms, vms.
fn)) < 0) {
17715 vmstate_delete(&vms);
17736 .optional_modules =
"res_adsi,res_smdi",
ADSI Support (built upon Caller*ID)
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_adsi_load_soft_key(unsigned char *buf, int key, const char *llabel, const char *slabel, char *ret, int data)
Creates "load soft key" parameters.
#define ADSI_MSG_DOWNLOAD
int ast_adsi_data_mode(unsigned char *buf)
Puts CPE in data mode.
int ast_adsi_unload_session(struct ast_channel *chan)
int ast_adsi_begin_download(struct ast_channel *chan, char *service, unsigned char *fdn, unsigned char *sec, int version)
int ast_adsi_set_line(unsigned char *buf, int page, int line)
Sets the current line and page.
int ast_adsi_input_control(unsigned char *buf, int page, int line, int display, int format, int just)
Set input information.
int ast_adsi_input_format(unsigned char *buf, int num, int dir, int wrap, char *format1, char *format2)
Set input format.
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,...
int ast_adsi_end_download(struct ast_channel *chan)
int ast_adsi_download_disconnect(unsigned char *buf)
Disconnects (and hopefully saves) a downloaded script.
int ast_adsi_available(struct ast_channel *chan)
Returns non-zero if Channel does or might support ADSI.
int ast_adsi_transmit_message(struct ast_channel *chan, unsigned char *msg, int msglen, int msgtype)
#define ADSI_DIR_FROM_LEFT
int ast_adsi_set_keys(unsigned char *buf, unsigned char *keys)
Set which soft keys should be displayed.
int ast_adsi_voice_mode(unsigned char *buf, int when)
Puts CPE in voice mode.
struct sla_ringing_trunk * last
#define VMBOX_STRING_DATA_FORMAT
static char * vm_check_password_shell(char *command, char *buf, size_t len)
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.
static int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box, int *newmsg, int move)
static char pagerfromstring[100]
static char vm_password[80]
static char vm_invalid_password[80]
#define VM_ODBC_AUDIO_ON_DISK
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.
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 char listen_control_reverse_key[12]
#define MAX_VM_CONTEXT_LEN
#define EXISTS(a, b, c, d)
static int vm_intro_pl(struct ast_channel *chan, struct vm_state *vms)
static void adsi_password(struct ast_channel *chan)
static char serveremail[80]
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
#define VMSTATE_MAX_MSG_ARRAY
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 void adsi_folders(struct ast_channel *chan, int start, char *label)
static int close_mailbox(struct vm_state *vms, struct ast_vm_user *vmu)
static int mwi_handle_unsubscribe2(void *data)
#define VOICEMAIL_DIR_MODE
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...
static int manager_voicemail_refresh(struct mansession *s, const struct message *m)
static int inprocess_hash_fn(const void *obj, const int flags)
static struct ast_custom_function vm_info_acf
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 ...
static int show_messages_for_mailbox(struct ast_cli_args *a)
static int vm_msg_play(struct ast_channel *chan, const char *mailbox, const char *context, const char *folder, const char *msg_num, ast_vm_msg_play_cb cb)
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, const char *msg_id)
Creates the email file to be sent to indicate a new voicemail exists for a user.
static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
Manager list voicemail users command.
#define DEFAULT_LISTEN_CONTROL_FORWARD_KEY
static int vm_delete(char *file)
Removes the voicemail sound and information file.
static int wait_file2(struct ast_channel *chan, struct vm_state *vms, char *file)
static int msg_id_incrementor
static const struct ast_vm_functions vm_table
static void free_zone(struct vm_zone *z)
static void adsi_begin(struct ast_channel *chan, int *useadsi)
static char * handle_voicemail_show_mailbox(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static void read_password_from_file(const char *secretfn, char *password, int passwordlen)
static int say_and_wait(struct ast_channel *chan, int num, const char *language)
static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
Loads the options specific to a voicemail user.
static void populate_defaults(struct ast_vm_user *vmu)
Sets default voicemail system options to a voicemail user.
static struct ast_taskprocessor * mwi_subscription_tps
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.
static char vm_newpassword[80]
static int vm_intro_he(struct ast_channel *chan, struct vm_state *vms)
static int vm_execmain(struct ast_channel *chan, const char *data)
static void free_user(struct ast_vm_user *vmu)
AO2_STRING_FIELD_CMP_FN(alias_mailbox_mapping, alias)
static int vm_play_folder_name_gr(struct ast_channel *chan, char *box)
static int vm_instructions_zh(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent, int nodelete)
static int actual_load_config(int reload, struct ast_config *cfg)
static int invent_message(struct ast_channel *chan, char *context, char *ext, int busy, char *ecodes)
static int vm_instructions(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent, int nodelete)
#define UPDATE_MSG_ID(a, b, c, d, e, f)
static int vm_instructions_en(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent, int nodelete)
#define VM_STRING_HEADER_FORMAT
static void generate_msg_id(char *dst)
Sets the destination string to a uniquely identifying msg_id string.
static struct ast_flags globalflags
static char listen_control_forward_key[12]
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, const char *msg_id, int forwardintro)
static int vmauthenticate(struct ast_channel *chan, const char *data)
static int play_message_duration(struct ast_channel *chan, struct vm_state *vms, const char *duration, int minduration)
static int vm_browse_messages_pt(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
Portuguese syntax for 'You have N messages' greeting.
static char vm_newuser[80]
#define VMBOX_STRING_HEADER_FORMAT
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, const char *msg_id)
static const char * ast_str_quote(struct ast_str **buf, ssize_t maxlen, const char *from)
Wraps a character sequence in double quotes, escaping occurrences of quotes within the string.
static ast_mutex_t poll_lock
static int check_mime(const char *str)
Check if the string would need encoding within the MIME standard, to avoid confusing certain mail sof...
static const char * vm_index_to_foldername(int id)
static unsigned char adsisec[4]
static int play_message_category(struct ast_channel *chan, const char *category)
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 const char * substitute_escapes(const char *value)
static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
Performs a change of the voicemail password in the realtime engine.
static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
Resets a user password to a specified password.
static int count_messages(struct ast_vm_user *vmu, char *dir)
Find all .txt files - even if they are not in sequence from 0000.
static pthread_t poll_thread
static int vm_intro_multilang(struct ast_channel *chan, struct vm_state *vms, const char message_gender[])
static int vm_exec(struct ast_channel *chan, const char *data)
static struct ast_vm_msg_snapshot * vm_msg_snapshot_alloc(void)
static char * pagersubject
static int manager_voicemail_forward(struct mansession *s, const struct message *m)
static int manager_voicemail_move(struct mansession *s, const struct message *m)
#define COPY(a, b, c, d, e, f, g, h)
static void load_zonemessages(struct ast_config *cfg)
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.
static int vm_intro(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
static int vm_playmsgexec(struct ast_channel *chan, const char *data)
static int vm_intro_de(struct ast_channel *chan, struct vm_state *vms)
static int passwordlocation
static int get_folder_ja(struct ast_channel *chan, int start)
static char vm_mismatch[80]
static void adsi_delete(struct ast_channel *chan, struct vm_state *vms)
static const struct ast_app_option vm_app_options[128]
static char * voicemail_app
static char * playmsg_app
static int vm_browse_messages_es(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
Spanish syntax for 'You have N messages' greeting.
static void notify_new_state(struct ast_vm_user *vmu)
static void adsi_message(struct ast_channel *chan, struct vm_state *vms)
#define ASTERISK_USERNAME
static int vm_newuser_setup(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
static int valid_config(const struct ast_config *cfg)
Check if configuration file is valid.
static char vm_pls_try_again[80]
static int play_message_callerid(struct ast_channel *chan, struct vm_state *vms, char *cid, const char *context, int callback, int saycidnumber)
static int write_password_to_file(const char *secretfn, const char *password)
static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file)
static int append_vmbox_info_astman(struct mansession *s, const struct message *m, struct ast_vm_user *vmu, const char *event_name, const char *actionid)
Append vmbox info string into given astman with event_name.
static int msg_create_from_file(struct ast_vm_recording_data *recdata)
static char * complete_voicemail_show_mailbox(struct ast_cli_args *a)
static const struct ast_vm_greeter_functions vm_greeter_table
static void rename_file(char *sfn, char *dfn)
Renames a message in a mailbox folder.
static int move_message_from_mailbox(struct ast_cli_args *a)
static struct alias_mailbox_mapping * alias_mailbox_mapping_create(const char *alias, const char *mailbox)
static struct ast_vm_mailbox_snapshot * vm_mailbox_snapshot_destroy(struct ast_vm_mailbox_snapshot *mailbox_snapshot)
struct ast_mwi_observer mwi_observer
static char ext_pass_check_cmd[128]
static int vm_intro_pt_BR(struct ast_channel *chan, struct vm_state *vms)
static int append_vmu_info_astman(struct mansession *s, struct ast_vm_user *vmu, const char *event_name, const char *actionid)
Append vmu info string into given astman with event_name.
static int separate_mailbox(char *mailbox_id, char **mailbox, char **context)
static int vm_msg_snapshot_create(struct ast_vm_user *vmu, struct vm_state *vms, struct ast_vm_mailbox_snapshot *mailbox_snapshot, int snapshot_index, int mailbox_index, int descending, enum ast_vm_snapshot_sort_val sort_val)
Create and store off all the msgs in an open mailbox.
static char dialcontext[AST_MAX_CONTEXT]
static int vmsayname_exec(struct ast_channel *chan, const char *data)
#define DEFAULT_POLL_FREQ
static int vm_intro_vi(struct ast_channel *chan, struct vm_state *vms)
static int messagecount(const char *mailbox_id, const char *folder)
static int manager_voicemail_remove(struct mansession *s, const struct message *m)
static void stop_poll_thread(void)
AO2_STRING_FIELD_HASH_FN(alias_mailbox_mapping, alias)
static char aliasescontext[MAX_VM_CONTEXT_LEN]
static int vm_sayname(struct ast_channel *chan, const char *mailbox_id)
#define DELETE(a, b, c, d)
static void print_mappings(void *v_obj, void *where, ao2_prnt_fn *prnt)
static struct ast_cli_entry cli_voicemail[]
#define DEFAULT_LISTEN_CONTROL_RESTART_KEY
static char listen_control_stop_key[12]
static char fromstring[100]
static int vm_browse_messages_ja(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
Japanese syntax for 'You have N messages' greeting.
#define PWDCHANGE_INTERNAL
static char * handle_voicemail_forward_message(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int vm_intro_cs(struct ast_channel *chan, struct vm_state *vms)
static void mwi_handle_unsubscribe(const char *id, struct ast_mwi_subscriber *sub)
static int adsi_load_vmail(struct ast_channel *chan, int *useadsi)
static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
The handler for the change password option.
static void * mb_poll_thread(void *data)
static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64]
static void run_externnotify(const char *context, const char *extension, const char *flag)
static int append_mailbox(const char *context, const char *box, const char *data)
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...
static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms)
static int vm_intro_nl(struct ast_channel *chan, struct vm_state *vms)
static void adsi_status(struct ast_channel *chan, struct vm_state *vms)
#define DEFAULT_LISTEN_CONTROL_STOP_KEY
static int acf_vm_info(struct ast_channel *chan, const char *cmd, char *args, char *buf, size_t len)
static int open_mailbox(struct vm_state *vms, struct ast_vm_user *vmu, int box)
static int vm_intro_zh(struct ast_channel *chan, struct vm_state *vms)
static char emaildateformat[32]
static char vm_reenterpassword[80]
static void adsi_login(struct ast_channel *chan)
static int manager_get_mailbox_summary(struct mansession *s, const struct message *m)
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.
#define MAX_VM_MAILBOX_LEN
static int __has_voicemail(const char *context, const char *mailbox, const char *folder, int shortcircuit)
static int vm_intro_pt(struct ast_channel *chan, struct vm_state *vms)
static int check_password(struct ast_vm_user *vmu, char *password)
Check that password meets minimum required length.
static int play_message_by_id_helper(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, const char *msg_id)
static int load_config_force(int reload, int force)
Reload voicemail.conf.
static int saydurationminfo
struct ao2_container * inprocess_container
static int vm_allocate_dh(struct vm_state *vms, struct ast_vm_user *vmu, int count_msg)
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)
static char * sayname_app
static void free_user_final(struct ast_vm_user *vmu)
static int vm_instructions_ja(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int skipadvanced, int in_urgent, int nodelete)
static void load_users(struct ast_config *cfg)
static int message_range_and_existence_check(struct vm_state *vms, const char *msg_ids[], size_t num_msgs, int *msg_nums, struct ast_vm_user *vmu)
common bounds checking and existence check for Voicemail API functions.
static int get_folder2(struct ast_channel *chan, char *fn, int start)
plays a prompt and waits for a keypress.
static int vm_msg_forward(const char *from_mailbox, const char *from_context, const char *from_folder, const char *to_mailbox, const char *to_context, const char *to_folder, size_t num_msgs, const char *msg_ids[], int delete_old)
static void adsi_goodbye(struct ast_channel *chan)
#define HVSU_OUTPUT_FORMAT
static char ext_pass_cmd[128]
static int is_valid_dtmf(const char *key)
Determines if a DTMF key entered is valid.
static char pagerdateformat[32]
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'.
static int get_folder_by_name(const char *name)
#define HVSZ_OUTPUT_FORMAT
static char * emailsubject
static int inprocess_count(const char *context, const char *mailbox, int delta)
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 struct ao2_container * mailbox_alias_mappings
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 apply_options(struct ast_vm_user *vmu, const char *options)
Destructively Parse options and apply.
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 char externnotify[160]
static int adsi_logo(unsigned char *buf)
static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, const char *origtime, const char *filename)
static unsigned char poll_thread_run
static char listen_control_restart_key[12]
static int add_message_id(struct ast_config *msg_cfg, char *dir, int msg, char *filename, char *id, size_t id_size, struct ast_vm_user *vmu, int folder)
static int play_message_by_id(struct ast_channel *chan, const char *mailbox, const char *context, const char *msg_id)
Finds a message in a specific mailbox by msg_id and plays it to the channel.
static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
basically mkdir -p $dest/$context/$ext/$folder
#define MAX_VM_MBOX_ID_LEN
static char * handle_voicemail_show_aliases(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Show a list of voicemail zones in the CLI.
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.
static void copy_plain_file(char *frompath, char *topath)
Copies a voicemail information (envelope) file.
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.
#define DEFAULT_LISTEN_CONTROL_PAUSE_KEY
#define MAX_NUM_CID_CONTEXTS
static int vm_play_folder_name_pl(struct ast_channel *chan, char *box)
static char * complete_voicemail_show_users(const char *line, const char *word, int pos, int state)
static int inboxcount(const char *mailbox, int *newmsgs, int *oldmsgs)
@ OPT_PWLOC_VOICEMAILCONF
static char vm_prepend_timeout[80]
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)
#define RETRIEVE(a, b, c, d)
static int inprocess_cmp_fn(void *obj, void *arg, int flags)
static int vm_intro_en(struct ast_channel *chan, struct vm_state *vms)
static char VM_SPOOL_DIR[PATH_MAX]
static int vm_options(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, char *fmtc, signed char record_gain)
#define SMDI_MWI_WAIT_TIMEOUT
static char callcontext[AST_MAX_CONTEXT]
static void mwi_handle_subscribe(const char *id, struct ast_mwi_subscriber *sub)
static int vm_intro_da(struct ast_channel *chan, struct vm_state *vms)
static void vm_change_password_shell(struct ast_vm_user *vmu, char *newpassword)
static int vm_intro_fr(struct ast_channel *chan, struct vm_state *vms)
static int show_mailbox_snapshot(struct ast_cli_args *a)
static int vm_browse_messages_it(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
Italian syntax for 'You have N messages' greeting.
static int vm_msg_remove(const char *mailbox, const char *context, size_t num_msgs, const char *folder, const char *msgs[])
static char listen_control_pause_key[12]
static int copy(char *infile, char *outfile)
Utility function to copy a file.
static int silencethreshold
static void start_poll_thread(void)
#define MAX_MAIL_BODY_CONTENT_SIZE
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 RENAME(a, b, c, d, e, f, g, h)
static int load_module(void)
Load the module.
static char * handle_voicemail_move_message(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
static int vm_browse_messages_he(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
static unsigned int poll_mailboxes
static int poll_subscribed_mailbox(struct ast_mwi_state *mwi_state, void *data)
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)
static int forward_message_from_mailbox(struct ast_cli_args *a)
#define STORE(a, b, c, d, e, f, g, h, i, j, k)
static int vm_intro_is(struct ast_channel *chan, struct vm_state *vms)
static char * complete_voicemail_move_message(struct ast_cli_args *a, int maxpos)
static char * handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Reload voicemail configuration from the CLI.
static unsigned int poll_freq
static int resequence_mailbox(struct ast_vm_user *vmu, char *dir, int stopcount)
static int last_message_index(char *dir)
Determines the highest message number in use for a given user and mailbox folder.
static ast_cond_t poll_cond
static void adsi_status2(struct ast_channel *chan, struct vm_state *vms)
static int unload_module(void)
static int load_config(int reload)
static void free_vm_zones(void)
Free the zones structure.
static int mwi_handle_subscribe2(void *data)
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 vm_intro_es(struct ast_channel *chan, struct vm_state *vms)
#define PWDCHANGE_EXTERNAL
static struct ast_vm_user * find_or_create(const char *context, const char *box)
static unsigned char adsifdn[4]
static void queue_mwi_event(const char *channel_id, const char *box, int urgent, int new, int old)
static int manager_status_voicemail_user(struct mansession *s, const struct message *m)
#define VOICEMAIL_FILE_MODE
static char * handle_voicemail_remove_message(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
#define LAST_MSG_INDEX(a)
static void load_aliases(struct ast_config *cfg)
static struct ao2_container * alias_mailbox_mappings
static int vm_play_folder_name(struct ast_channel *chan, char *mbox)
static const 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.
static int vm_play_folder_name_ua(struct ast_channel *chan, char *box)
#define DEFAULT_LISTEN_CONTROL_REVERSE_KEY
static char * show_users_realtime(int fd, const char *context)
static int remove_message_from_mailbox(struct ast_cli_args *a)
static int has_voicemail(const char *mailbox, const char *folder)
Determines if the given folder has messages.
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.
#define VM_EMAIL_EXT_RECS
static struct ast_vm_mailbox_snapshot * vm_mailbox_snapshot_create(const char *mailbox, const char *context, const char *folder, int descending, enum ast_vm_snapshot_sort_val sort_val, int combine_INBOX_and_OLD)
static int manager_match_mailbox(struct ast_mwi_state *mwi_state, void *data)
static int vm_intro_ja(struct ast_channel *chan, struct vm_state *vms)
static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
Check the given mailbox's message count.
static char exitcontext[AST_MAX_CONTEXT]
static int dialout(struct ast_channel *chan, struct ast_vm_user *vmu, char *num, char *outgoing_context)
static int vm_msg_move(const char *mailbox, const char *context, size_t num_msgs, const char *oldfolder, const char *old_msg_ids[], const char *newfolder)
static int sayname(struct ast_channel *chan, const char *mailbox, const char *context)
static int get_date(char *s, int len)
Gets the current date and time, as formatted string.
static const char *const mailbox_folders[]
static int show_mailbox_details(struct ast_cli_args *a)
static const char * mbox(struct ast_vm_user *vmu, int id)
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, const char *dest_folder)
Copies a message from one mailbox to another.
static char * vmauthenticate_app
static int vm_play_folder_name_ja(struct ast_channel *chan, char *box)
#define force_reload_config()
Forcibly reload voicemail.conf, even if it has not changed. This is necessary after running unit test...
static int vm_intro_se(struct ast_channel *chan, struct vm_state *vms)
static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
Sets a specific property value.
static char vm_passchanged[80]
static struct ast_vm_msg_snapshot * vm_msg_snapshot_destroy(struct ast_vm_msg_snapshot *msg_snapshot)
static char * voicemailmain_app
#define ALIASES_OUTPUT_FORMAT
static int vm_intro_it(struct ast_channel *chan, struct vm_state *vms)
static int vm_browse_messages_gr(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
Greek syntax for 'You have N messages' greeting.
static struct ast_smdi_interface * smdi_iface
static int vm_intro_gr(struct ast_channel *chan, struct vm_state *vms)
static void free_vm_users(void)
Free the users structure.
static int vm_intro_no(struct ast_channel *chan, struct vm_state *vms)
static int input(yyscan_t yyscanner)
char * strsep(char **str, const char *delims)
char * mkdtemp(char *template_s)
char * strcasestr(const char *, const char *)
Asterisk main include file. File version handling, generic pbx functions.
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
#define ast_realloc(p, len)
A wrapper for realloc()
#define ast_strdup(str)
A wrapper for strdup()
#define ast_strdupa(s)
duplicate a string in memory from the stack
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
#define ast_calloc(num, len)
A wrapper for calloc()
#define ast_malloc(len)
A wrapper for malloc()
#define ao2_iterator_next(iter)
#define ao2_link(container, obj)
Add an object to a container.
@ AO2_ALLOC_OPT_LOCK_MUTEX
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container,...
void ao2_container_unregister(const char *name)
Unregister a container for CLI stats and integrity check.
#define ao2_find(container, arg, flags)
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
int ao2_container_register(const char *name, struct ao2_container *self, ao2_prnt_obj_fn *prnt_obj)
Register a container for CLI stats and integrity check.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
@ OBJ_SEARCH_KEY
The arg parameter is a search key, but is not an object.
#define ao2_alloc(data_size, destructor_fn)
#define ao2_container_alloc_hash(ao2_options, container_options, n_buckets, hash_fn, sort_fn, cmp_fn)
Allocate and initialize a hash container with the desired number of buckets.
void() ao2_prnt_fn(void *where, const char *fmt,...)
Print output.
char * ast_callerid_merge(char *buf, int bufsiz, const char *name, const char *num, const char *unknown)
int ast_callerid_parse(char *instr, char **name, char **location)
Destructively parse inbuf into name and location (or number)
int ast_callerid_split(const char *src, char *name, int namelen, char *num, int numlen)
static SQLHSTMT generic_prepare(struct odbc_obj *obj, void *data)
static char language[MAX_LANGUAGE]
static int transfer(void *data)
General Asterisk PBX channel definitions.
void ast_channel_exten_set(struct ast_channel *chan, const char *value)
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
const char * ast_channel_name(const struct ast_channel *chan)
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
#define ast_channel_alloc(needqueue, state, cid_num, cid_name, acctcode, exten, context, assignedids, requestor, amaflag,...)
Create a channel structure.
void ast_channel_nativeformats_set(struct ast_channel *chan, struct ast_format_cap *value)
#define ast_channel_lock(chan)
struct ast_party_redirecting * ast_channel_redirecting(struct ast_channel *chan)
int ast_channel_priority(const struct ast_channel *chan)
const char * ast_channel_uniqueid(const struct ast_channel *chan)
const char * ast_channel_context(const struct ast_channel *chan)
void ast_channel_set_rawreadformat(struct ast_channel *chan, struct ast_format *format)
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
void ast_channel_set_rawwriteformat(struct ast_channel *chan, struct ast_format *format)
void ast_channel_set_readformat(struct ast_channel *chan, struct ast_format *format)
#define ast_channel_unref(c)
Decrease channel reference count.
const char * ast_channel_language(const struct ast_channel *chan)
void ast_channel_context_set(struct ast_channel *chan, const char *value)
#define ast_dummy_channel_alloc()
Create a fake channel structure.
int ast_channel_setoption(struct ast_channel *channel, int option, void *data, int datalen, int block)
Sets an option on a channel.
struct ast_party_caller * ast_channel_caller(struct ast_channel *chan)
void ast_channel_priority_set(struct ast_channel *chan, int value)
int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int rtimeout, char *enders)
Reads multiple digits.
int ast_answer(struct ast_channel *chan)
Answer a channel.
void ast_channel_adsicpe_set(struct ast_channel *chan, enum ast_channel_adsicpe value)
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
void ast_channel_tech_set(struct ast_channel *chan, const struct ast_channel_tech *value)
const char * ast_channel_exten(const struct ast_channel *chan)
#define ast_channel_unlock(chan)
#define AST_MAX_EXTENSION
void ast_channel_set_writeformat(struct ast_channel *chan, struct ast_format *format)
void ast_party_caller_init(struct ast_party_caller *init)
Initialize the given caller structure.
ast_channel_state
ast_channel states
static struct ast_channel * callback(struct ast_channelstorage_instance *driver, ao2_callback_data_fn *cb_fn, void *arg, void *data, int ao2_flags)
Standard Command Line Interface.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
#define AST_CLI_DEFINE(fn, txt,...)
void ast_cli(int fd, const char *fmt,...)
#define ast_cli_register_multiple(e, len)
Register multiple commands.
static struct progalias aliases[]
Convenient Signal Processing routines.
int ast_dsp_get_threshold_from_settings(enum threshold which)
Get silence threshold from dsp.conf.
static char * config_filename
Generic File Format Support. Should be included by clients of the file handling routines....
off_t ast_tellstream(struct ast_filestream *fs)
Tell where we are in a stream.
int ast_stopstream(struct ast_channel *c)
Stops a stream.
int ast_seekstream(struct ast_filestream *fs, off_t sample_offset, int whence)
Seeks into stream.
int ast_filerename(const char *oldname, const char *newname, const char *fmt)
Renames a file.
struct ast_filestream * ast_readfile(const char *filename, const char *type, const char *comment, int flags, int check, mode_t mode)
Starts reading from a file.
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
FILE * ast_file_mkftemp(char *template_name, mode_t mode)
same as mkstemp, but return a FILE
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.
char * ast_format_str_reduce(char *fmts)
int ast_filecopy(const char *oldname, const char *newname, const char *fmt)
Copies a file.
int ast_ratestream(struct ast_filestream *fs)
Return the sample rate of the stream's format.
int ast_closestream(struct ast_filestream *f)
Closes a stream.
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
int ast_filedelete(const char *filename, const char *fmt)
Deletes a file.
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
static int exists(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static struct ast_threadstorage buf2
static struct ast_threadstorage buf1
static int quote(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t len)
static int len(struct ast_channel *chan, const char *cmd, char *data, char *buf, size_t buflen)
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
void ast_manager_publish_event(const char *type, int class_type, struct ast_json *obj)
Publish an event to AMI.
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
void astman_append(struct mansession *s, const char *fmt,...)
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
#define SCOPE_EXIT_RTN(...)
#define SCOPE_EXIT_RTN_VALUE(__return_value,...)
#define SCOPE_EXIT_LOG_RTN_VALUE(__value, __log_level,...)
#define SCOPE_ENTER(level,...)
#define SCOPE_CALL_WITH_INT_RESULT(level, __funcname,...)
#define SCOPE_CALL(level, __funcname,...)
#define SCOPE_EXIT_LOG_RTN(__log_level,...)
#define ast_trace(level,...)
static char prefix[MAX_PREFIX]
Application convenience functions, designed to give consistent look and feel to Asterisk apps.
#define AST_APP_ARG(name)
Define an application argument.
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 beep, int silencethreshold, int maxsilence_ms, const char *path, const char *acceptdtmf, const char *canceldtmf, int skip_confirmation_sound, enum ast_record_if_exists if_exists)
Record a file based on input from a channel This function will play "auth-thankyou" upon successful r...
int ast_app_messagecount(const char *mailbox_id, const char *folder)
Get the number of messages in a given mailbox folder.
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.
void ast_vm_greeter_unregister(const char *module_name)
Unregister the specified voicemail greeter provider.
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
enum ast_getdata_result 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.
@ AST_VM_SNAPSHOT_SORT_BY_ID
@ AST_VM_SNAPSHOT_SORT_BY_TIME
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...
enum AST_LOCK_RESULT ast_lock_path(const char *path)
Lock a filesystem path.
#define AST_APP_OPTION_ARG(option, flagno, argno)
Declares an application option that accepts an argument.
int ast_app_has_voicemail(const char *mailboxes, const char *folder)
Determine if a given mailbox has any voicemail If folder is NULL, defaults to "INBOX"....
#define VM_GREETER_MODULE_VERSION
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 AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define VM_MODULE_VERSION
struct ast_vm_mailbox_snapshot * ast_vm_mailbox_snapshot_destroy(struct ast_vm_mailbox_snapshot *mailbox_snapshot)
destroy a snapshot
int ast_safe_system(const char *s)
Safely spawn an OS shell command while closing file descriptors.
void ast_vm_unregister(const char *module_name)
Unregister the specified voicemail provider.
#define ast_vm_register(vm_table)
See __ast_vm_register()
int ast_app_inboxcount(const char *mailboxes, int *newmsgs, int *oldmsgs)
Determine number of new/old messages in a mailbox.
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.
#define AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
void() ast_vm_msg_play_cb(struct ast_channel *chan, const char *playfile, int duration)
Voicemail playback callback function definition.
@ AST_RECORD_IF_EXISTS_OVERWRITE
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
#define AST_NONSTANDARD_APP_ARGS(args, parse, sep)
Performs the 'nonstandard' argument separation process for an application.
int ast_app_inboxcount2(const char *mailboxes, int *urgentmsgs, int *newmsgs, int *oldmsgs)
Determine number of urgent/new/old messages in a mailbox.
#define ast_vm_greeter_register(vm_table)
See __ast_vm_greeter_register()
struct ast_vm_mailbox_snapshot * ast_vm_mailbox_snapshot_create(const char *mailbox, const char *context, const char *folder, int descending, enum ast_vm_snapshot_sort_val sort_val, int combine_INBOX_and_OLD)
Create a snapshot of a mailbox which contains information about every msg.
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.
int ast_unlock_path(const char *path)
Unlock a path.
void ast_close_fds_above_n(int n)
Common routine for child processes, to close all fds prior to exec(2)
Configuration File Parser.
#define ast_config_load(filename, flags)
Load a config file.
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
int ast_update2_realtime(const char *family,...) attribute_sentinel
Update realtime configuration.
struct ast_config * ast_config_new(void)
Create a new base configuration structure.
int ast_realtime_require_field(const char *family,...) attribute_sentinel
Inform realtime what fields that may be stored.
struct ast_config * ast_load_realtime_multientry(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
int ast_config_text_file_save(const char *filename, const struct ast_config *cfg, const char *generator)
Save a config text file preserving the pre 13.2 behavior.
void ast_category_append(struct ast_config *config, struct ast_category *category)
Appends a category to a config.
void ast_variable_append(struct ast_category *category, struct ast_variable *variable)
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.
struct ast_category * ast_category_new(const char *name, const char *in_file, int lineno)
Create a category.
#define ast_variable_new(name, value, filename)
int ast_unload_realtime(const char *family)
Release any resources cached for a realtime family.
#define CONFIG_STATUS_FILEUNCHANGED
#define CONFIG_STATUS_FILEINVALID
int ast_check_realtime(const char *family)
Check if realtime engine is configured for family.
int ast_destroy_realtime(const char *family, const char *keyfield, const char *lookup,...) attribute_sentinel
Destroy realtime configuration.
void ast_category_destroy(struct ast_category *cat)
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
const char * ast_variable_retrieve(struct ast_config *config, const char *category, const char *variable)
int ast_update_realtime(const char *family, const char *keyfield, const char *lookup,...) attribute_sentinel
Update realtime configuration.
int ast_store_realtime(const char *family,...) attribute_sentinel
Create realtime configuration.
struct ast_variable * ast_load_realtime(const char *family,...) attribute_sentinel
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
@ CONFIG_FLAG_WITHCOMMENTS
@ CONFIG_FLAG_FILEUNCHANGED
struct ast_variable * ast_variable_browse(const struct ast_config *config, const char *category_name)
struct ast_category * ast_category_get(const struct ast_config *config, const char *category_name, const char *filter)
Retrieve a category if it exists.
#define AST_OPTION_RXGAIN
struct ast_frame ast_null_frame
Support for logging to various files, console and syslog Configuration in file logger....
#define DEBUG_ATLEAST(level)
#define ast_debug(level,...)
Log a DEBUG message.
#define ast_verb(level,...)
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
#define AST_LIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
#define AST_LIST_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
#define AST_LIST_HEAD_NOLOCK_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
#define AST_LIST_INSERT_BEFORE_CURRENT(elm, field)
Inserts a list entry before the current entry during a traversal.
#define AST_LIST_LOCK(head)
Locks a list.
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
#define AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
Custom localtime functions for multiple timezones.
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
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...
int ast_strftime_locale(char *buf, size_t len, const char *format, const struct ast_tm *tm, const char *locale)
Asterisk locking-related definitions:
#define AST_PTHREADT_NULL
#define ast_cond_timedwait(cond, mutex, time)
#define ast_mutex_init(pmutex)
#define ast_mutex_unlock(a)
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
pthread_cond_t ast_cond_t
#define ast_mutex_destroy(a)
#define ast_mutex_lock(a)
#define AST_MUTEX_DEFINE_STATIC(mutex)
#define ast_cond_signal(cond)
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
#define EVENT_FLAG_REPORTING
#define EVENT_FLAG_SYSTEM
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Asterisk module definitions.
#define AST_MODULE_INFO(keystr, flags_to_set, desc, fields...)
@ AST_MODULE_SUPPORT_CORE
#define ASTERISK_GPL_KEY
The text the key() function should return.
int ast_unregister_application(const char *app)
Unregister an application.
@ AST_MODULE_LOAD_SUCCESS
@ AST_MODULE_LOAD_DECLINE
Module has failed to load, may be in an inconsistent state.
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
#define ast_publish_mwi_state_channel(mailbox, context, new_msgs, old_msgs, channel_id)
Publish a MWI state update associated with some channel.
void ast_mwi_state_callback_all(on_mwi_state handler, void *data)
For each managed mailbox call the given handler.
void ast_mwi_state_callback_subscribed(on_mwi_state handler, void *data)
For each managed mailbox that has a subscriber call the given handler.
int ast_mwi_add_observer(struct ast_mwi_observer *observer)
Add an observer to receive MWI state related events.
int ast_delete_mwi_state_full(const char *mailbox, const char *context, struct ast_eid *eid)
Delete MWI state cached by stasis with all parameters.
void ast_mwi_remove_observer(struct ast_mwi_observer *observer)
Remove an MWI state observer.
struct ast_mwi_state * ast_mwi_subscriber_data(struct ast_mwi_subscriber *sub)
Retrieves the state data object associated with the MWI subscriber.
def from_mailbox(key, val, section, pjsip, nmapped)
Asterisk file paths, configured in asterisk.conf.
const char * ast_config_AST_DATA_DIR
const char * ast_config_AST_SPOOL_DIR
Core PBX routines and definitions.
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
int ast_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data)
Execute an application.
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.
#define ast_custom_function_register(acf)
Register a custom function.
int ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
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.
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
struct ast_app * pbx_findapp(const char *app)
Look up an application.
static void * cleanup(void *unused)
static char intro[ADSI_MAX_INTRO][20]
static struct stasis_rest_handlers mailboxes
REST handler for /api-docs/mailboxes.json.
struct stasis_forward * sub
int ast_odbc_prepare(struct odbc_obj *obj, SQLHSTMT *stmt, const char *sql)
Prepares a SQL query on a statement.
void ast_odbc_release_obj(struct odbc_obj *obj)
Releases an ODBC object previously allocated by ast_odbc_request_obj()
struct ast_str * ast_odbc_print_errors(SQLSMALLINT handle_type, SQLHANDLE handle, const char *operation)
Shortcut for printing errors to logs after a failed SQL operation.
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.
SQLRETURN ast_odbc_execute_sql(struct odbc_obj *obj, SQLHSTMT *stmt, const char *sql)
Execute a unprepared SQL query.
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.
#define ast_odbc_request_obj(name, check)
Get a ODBC connection object.
static int debug
Global debug status.
Say numbers and dates (maybe words one day too)
int ast_say_character_str(struct ast_channel *chan, const char *num, const char *ints, const char *lang, enum ast_say_case_sensitivity sensitivity)
function to pronounce character and phonetic strings
int ast_say_number(struct ast_channel *chan, int num, const char *ints, const char *lang, const char *options)
says a number
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)
int ast_say_counted_noun(struct ast_channel *chan, int num, const char *noun)
int ast_say_counted_adjective(struct ast_channel *chan, int num, const char *adjective, const char *gender)
int ast_say_digit_str(struct ast_channel *chan, const char *num, const char *ints, const char *lang)
says digits of a string
SMDI support for Asterisk.
struct ast_smdi_interface * ast_smdi_interface_find(const char *iface_name)
Find an SMDI interface with the specified name.
int ast_smdi_mwi_set(struct ast_smdi_interface *iface, const char *mailbox)
Set the MWI indicator for a mailbox.
struct ast_smdi_mwi_message * ast_smdi_mwi_message_wait_station(struct ast_smdi_interface *iface, int timeout, const char *station)
int ast_smdi_mwi_unset(struct ast_smdi_interface *iface, const char *mailbox)
Unset the MWI indicator for a mailbox.
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
String manipulation functions.
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one.
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true"....
#define S_COR(a, b, c)
returns the equivalent of logic or for strings, with an additional boolean check: second one if not e...
int ast_get_time_t(const char *src, time_t *dst, time_t _default, int *consumed)
Parse a time (integer) string.
static force_inline int attribute_pure ast_strlen_zero(const char *s)
int ast_build_string(char **buffer, size_t *space, const char *fmt,...)
Build a string in a buffer, designed to be called repeatedly.
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"....
#define ast_str_alloca(init_len)
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
ast_app: A registered application
Structure to describe a channel "technology", ie a channel driver See for examples:
int(*const write)(struct ast_channel *chan, struct ast_frame *frame)
Write a frame, in standard format (see frame.h)
struct ast_format_cap * capabilities
Main Channel structure associated with a channel.
descriptor for a cli entry.
Data structure associated with a custom dialplan function.
This structure is allocated by file.c in one chunk, together with buf_size and desc_size bytes of mem...
Structure used to handle boolean flags.
Data structure associated with a single frame of data.
Abstract JSON element (object, array, string, int, ...).
Structure for mutex and tracking information.
MWI state event interface.
void(* on_subscribe)(const char *mailbox, struct ast_mwi_subscriber *sub)
Raised when MWI is being subscribed.
The structure that contains MWI state.
const ast_string_field uniqueid
Caller Party information.
struct ast_party_id id
Caller party ID.
struct ast_party_name name
Subscriber name.
struct ast_party_number number
Subscriber phone number.
unsigned char valid
TRUE if the name information is valid/present.
char * str
Subscriber name (Malloced)
unsigned char valid
TRUE if the number information is valid/present.
char * str
Subscriber phone number (Malloced)
An SMDI message waiting indicator message.
char cause[SMDI_MWI_FAIL_CAUSE_LEN+1]
char fwd_st[SMDI_MAX_STATION_NUM_LEN+1]
Support for dynamic strings.
A ast_taskprocessor structure is a singleton by name.
Structure for variables, used for configurations and for channel variables.
struct ast_variable * next
Voicemail function table definition.
unsigned int module_version
The version of this function table.
const char * module_name
The name of the module that provides the voicemail functionality.
Voicemail greeter function table definition.
unsigned int module_version
The version of this function table.
const char * module_name
The name of the module that provides the voicemail greeter functionality.
struct ast_vm_mailbox_snapshot::@188 * snapshots
const ast_string_field origtime
struct ast_vm_msg_snapshot::@187 msg
const ast_string_field msg_id
Structure used for ast_copy_recording_to_vm in order to cleanly supply data needed for making the rec...
const ast_string_field recording_file
const ast_string_field call_callerchan
const ast_string_field context
const ast_string_field folder
const ast_string_field call_callerid
const ast_string_field call_context
const ast_string_field recording_ext
const ast_string_field call_extension
const ast_string_field mailbox
char mailbox[MAX_VM_MBOX_ID_LEN]
struct ast_vm_user::@82 list
char context[MAX_VM_CONTEXT_LEN]
char language[MAX_LANGUAGE]
struct ast_vm_user::@84 list
All configuration options for http media cache.
structure to hold extensions
Options for leaving voicemail with the voicemail() application.
In case you didn't read that giant block of text above the mansession_session struct,...
structure to hold users read from phoneprov_users.conf
list of users found in the config file
An API for managing task processing threads that can be shared across modules.
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_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
int ast_taskprocessor_push(struct ast_taskprocessor *tps, int(*task_exe)(void *datap), void *datap) attribute_warn_unused_result
Push a task into the specified taskprocessor queue and signal the taskprocessor thread.
#define AST_TASKPROCESSOR_HIGH_WATER_LEVEL
int ast_taskprocessor_alert_set_levels(struct ast_taskprocessor *tps, long low_water, long high_water)
Set the high and low alert water marks of the given taskprocessor queue.
#define AST_TEST_REGISTER(cb)
#define ast_test_status_update(a, b, c...)
#define AST_TEST_UNREGISTER(cb)
#define ast_test_suite_event_notify(s, f,...)
#define AST_TEST_DEFINE(hdr)
Definitions to aid in the use of thread local storage.
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
Time-related functions and macros.
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 ...
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
#define ast_test_flag(p, flag)
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
int ast_file_is_readable(const char *filename)
Test that a file exists and is readable by the effective user.
#define ast_pthread_create(a, b, c, d)
#define ast_set2_flag(p, value, flag)
#define ast_clear_flag(p, flag)
long int ast_random(void)
int ast_mkdir(const char *path, int mode)
Recursively create directory path.
#define ast_set_flag(p, flag)
#define ast_copy_flags(dest, src, flagz)
int ast_base64_encode_file_path(const char *filename, FILE *outputfile, const char *endl)
Performs a base 64 encode algorithm on the contents of a File.