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)
833#define force_reload_config() load_config_force(1, 1)
933#define MAX_VM_MBOX_ID_LEN (AST_MAX_EXTENSION)
934#define MAX_VM_CONTEXT_LEN (AST_MAX_CONTEXT)
936#define MAX_VM_MAILBOX_LEN (MAX_VM_MBOX_ID_LEN + MAX_VM_CONTEXT_LEN)
971 char imappassword[80];
973 char imapvmshareid[80];
988#define VMSTATE_MAX_MSG_ARRAY 256
1013 unsigned msg_array_max;
1014 MAILSTREAM *mailstream;
1017 char imapfolder[64];
1018 char imapserver[48];
1020 char imapflags[128];
1024 unsigned int quota_limit;
1025 unsigned int quota_usage;
1031static char odbc_database[80] =
"asterisk";
1032static char odbc_table[80] =
"voicemessages";
1033size_t odbc_table_len =
sizeof(odbc_table);
1034#define COUNT(a, b) odbc_count_messages(a,b)
1035#define LAST_MSG_INDEX(a) odbc_last_message_index(a)
1036#define RETRIEVE(a,b,c,d) odbc_retrieve_message(a,b)
1037#define DISPOSE(a,b) odbc_remove_files(a,b)
1038#define STORE(a,b,c,d,e,f,g,h,i,j,k) odbc_store_message(a,b,c,d)
1039#define EXISTS(a,b,c,d) (odbc_message_exists(a,b))
1040#define RENAME(a,b,c,d,e,f,g,h) (odbc_rename_message(a,b,c,d,e,f))
1041#define COPY(a,b,c,d,e,f,g,h) (odbc_copy_message(a,b,c,d,e,f))
1042#define DELETE(a,b,c,d) (odbc_delete_message(a,b))
1043#define UPDATE_MSG_ID(a, b, c, d, e, f) (odbc_update_msg_id((a), (b), (c)))
1046#define DISPOSE(a,b) (imap_remove_file(a,b))
1047#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))
1048#define RETRIEVE(a,b,c,d) imap_retrieve_file(a,b,c,d)
1049#define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
1050#define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
1051#define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
1052#define DELETE(a,b,c,d) (vm_imap_delete(a,b,d))
1053#define UPDATE_MSG_ID(a, b, c, d, e, f) (vm_imap_update_msg_id((a), (b), (c), (d), (e), (f)))
1055#define COUNT(a, b) count_messages(a,b)
1056#define LAST_MSG_INDEX(a) last_message_index(a)
1057#define RETRIEVE(a,b,c,d)
1059#define STORE(a,b,c,d,e,f,g,h,i,j,k)
1060#define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
1061#define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
1062#define COPY(a,b,c,d,e,f,g,h) (copy_plain_file(g,h));
1063#define DELETE(a,b,c,d) (vm_delete(c))
1064#define UPDATE_MSG_ID(a, b, c, d, e, f)
1075#define PWDCHANGE_INTERNAL (1 << 1)
1076#define PWDCHANGE_EXTERNAL (1 << 2)
1080#define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
1083# define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
1085# define tdesc "Comedian Mail (Voicemail System)"
1133#define DEFAULT_POLL_FREQ 30
1156#define MAPPING_BUCKETS 511
1214static unsigned char adsifdn[4] =
"\x00\x00\x00\x0F";
1215static unsigned char adsisec[4] =
"\x9B\xDB\xF7\xAC";
1226 char *fmt,
int outsidecaller,
struct ast_vm_user *vmu,
int *duration,
int *sound_duration,
const char *unlockdir,
1227 signed char record_gain,
struct vm_state *vms,
char *
flag,
const char *msg_id,
int forwardintro);
1231static 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);
1263static 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);
1264static 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);
1268#ifdef TEST_FRAMEWORK
1269static int vm_test_destroy_user(
const char *
context,
const char *
mailbox);
1270static int vm_test_create_user(
const char *
context,
const char *
mailbox);
1318 if (strcmp(i->
mailbox, j->mailbox)) {
1326 int context_len = strlen(
context) + 1;
1327 int mailbox_len = strlen(
mailbox) + 1;
1342 if (!(i =
ao2_alloc(
sizeof(*i) + context_len + mailbox_len,
NULL))) {
1356#if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
1374 if (bufptr ==
buf + buflen - 1) {
1401static size_t get_msg_path_len(
const char *dir)
1415#define MAX_SOUND_EXTEN_LEN 12
1428static size_t get_msg_path_ext_len(
const char *dir)
1434 return strlen(dir) + 1 +
MSGFILE_LEN + MAX_SOUND_EXTEN_LEN + 1;
1458#define MAKE_FILE_PTRA(dir, msgnum) \
1460 size_t __len = get_msg_path_len(dir); \
1463 __var = ast_strdupa(dir); \
1465 __var = ast_alloca(__len); \
1466 snprintf(__var, __len, "%s/msg%04d", dir, msgnum); \
1500#define MAKE_FILE_EXT_PTRA(dir, msgnum, ext) \
1502 size_t __len = get_msg_path_ext_len(dir); \
1503 char *__var = ast_alloca(__len); \
1505 snprintf(__var, __len, "%s.%s", dir, ext); \
1507 snprintf(__var, __len, "%s/msg%04d.%s", dir, msgnum, ext); \
1558 ast_copy_string(vmu->imapfolder, imapfolder,
sizeof(vmu->imapfolder));
1559 ast_copy_string(vmu->imapserver, imapserver,
sizeof(vmu->imapserver));
1576 if (!strcasecmp(
var,
"attach")) {
1578 }
else if (!strcasecmp(
var,
"attachfmt")) {
1580 }
else if (!strcasecmp(
var,
"attachextrecs")) {
1582 }
else if (!strcasecmp(
var,
"serveremail")) {
1584 }
else if (!strcasecmp(
var,
"fromstring")) {
1586 }
else if (!strcasecmp(
var,
"emailbody")) {
1589 }
else if (!strcasecmp(
var,
"emailsubject")) {
1592 }
else if (!strcasecmp(
var,
"language")) {
1594 }
else if (!strcasecmp(
var,
"tz")) {
1596 }
else if (!strcasecmp(
var,
"locale")) {
1599 }
else if (!strcasecmp(
var,
"imapuser")) {
1601 vmu->imapversion = imapversion;
1602 }
else if (!strcasecmp(
var,
"imapserver")) {
1604 vmu->imapversion = imapversion;
1605 }
else if (!strcasecmp(
var,
"imapport")) {
1607 vmu->imapversion = imapversion;
1608 }
else if (!strcasecmp(
var,
"imapflags")) {
1610 vmu->imapversion = imapversion;
1611 }
else if (!strcasecmp(
var,
"imappassword") || !strcasecmp(
var,
"imapsecret")) {
1613 vmu->imapversion = imapversion;
1614 }
else if (!strcasecmp(
var,
"imapfolder")) {
1616 vmu->imapversion = imapversion;
1617 }
else if (!strcasecmp(
var,
"imapvmshareid")) {
1619 vmu->imapversion = imapversion;
1621 }
else if (!strcasecmp(
var,
"delete") || !strcasecmp(
var,
"deletevoicemail")) {
1623 }
else if (!strcasecmp(
var,
"saycid")){
1625 }
else if (!strcasecmp(
var,
"sendvoicemail")){
1627 }
else if (!strcasecmp(
var,
"review")){
1629 }
else if (!strcasecmp(
var,
"leaveurgent")){
1631 }
else if (!strcasecmp(
var,
"tempgreetwarn")){
1633 }
else if (!strcasecmp(
var,
"messagewrap")){
1635 }
else if (!strcasecmp(
var,
"operator")) {
1637 }
else if (!strcasecmp(
var,
"envelope")){
1639 }
else if (!strcasecmp(
var,
"moveheard")){
1641 }
else if (!strcasecmp(
var,
"sayduration")){
1643 }
else if (!strcasecmp(
var,
"saydurationm")){
1644 if (sscanf(
value,
"%30d", &x) == 1) {
1649 }
else if (!strcasecmp(
var,
"forcename")){
1651 }
else if (!strcasecmp(
var,
"forcegreetings")){
1653 }
else if (!strcasecmp(
var,
"callback")) {
1655 }
else if (!strcasecmp(
var,
"dialout")) {
1657 }
else if (!strcasecmp(
var,
"exitcontext")) {
1659 }
else if (!strcasecmp(
var,
"minsecs")) {
1660 if (sscanf(
value,
"%30d", &x) == 1 && x >= 0) {
1666 }
else if (!strcasecmp(
var,
"maxmessage") || !strcasecmp(
var,
"maxsecs")) {
1674 if (!strcasecmp(
var,
"maxmessage"))
1675 ast_log(
AST_LOG_WARNING,
"Option 'maxmessage' has been deprecated in favor of 'maxsecs'. Please make that change in your voicemail config.\n");
1676 }
else if (!strcasecmp(
var,
"maxmsg")) {
1686 }
else if (!strcasecmp(
var,
"nextaftercmd")) {
1688 }
else if (!strcasecmp(
var,
"backupdeleted")) {
1689 if (sscanf(
value,
"%30d", &x) == 1)
1703 }
else if (!strcasecmp(
var,
"volgain")) {
1705 }
else if (!strcasecmp(
var,
"passwordlocation")) {
1706 if (!strcasecmp(
value,
"spooldir")) {
1711 }
else if (!strcasecmp(
var,
"options")) {
1718 int fds[2], pid = 0;
1723 snprintf(
buf,
len,
"FAILURE: Pipe failed: %s", strerror(
errno));
1732 snprintf(
buf,
len,
"FAILURE: Fork failed");
1736 if (read(fds[0],
buf,
len) < 0) {
1748 dup2(fds[1], STDOUT_FILENO);
1754 execv(arg.v[0], arg.v);
1755 printf(
"FAILURE: %s", strerror(
errno));
1778 char cmd[255],
buf[255];
1780 ast_debug(1,
"Verify password policies for %s\n", password);
1785 if (!strncasecmp(
buf,
"VALID", 5)) {
1788 }
else if (!strncasecmp(
buf,
"FAILURE", 7)) {
1813 if (!strcmp(vmu->
password, password)) {
1818 if (strlen(password) > 10) {
1838 while ((s =
strsep(&stringp,
"|"))) {
1854 if (!strcasecmp(
var->name,
"vmsecret")) {
1856 }
else if (!strcasecmp(
var->name,
"secret") || !strcasecmp(
var->name,
"password")) {
1860 "\n\tmust be reset in voicemail.conf.\n", retval->
mailbox);
1865 }
else if (!strcasecmp(
var->name,
"uniqueid")) {
1867 }
else if (!strcasecmp(
var->name,
"pager")) {
1869 }
else if (!strcasecmp(
var->name,
"email")) {
1872 }
else if (!strcasecmp(
var->name,
"fullname")) {
1874 }
else if (!strcasecmp(
var->name,
"context")) {
1876 }
else if (!strcasecmp(
var->name,
"emailsubject")) {
1879 }
else if (!strcasecmp(
var->name,
"emailbody")) {
1883 }
else if (!strcasecmp(
var->name,
"imapuser")) {
1885 retval->imapversion = imapversion;
1886 }
else if (!strcasecmp(
var->name,
"imapserver")) {
1888 retval->imapversion = imapversion;
1889 }
else if (!strcasecmp(
var->name,
"imapport")) {
1891 retval->imapversion = imapversion;
1892 }
else if (!strcasecmp(
var->name,
"imapflags")) {
1894 retval->imapversion = imapversion;
1895 }
else if (!strcasecmp(
var->name,
"imappassword") || !strcasecmp(
var->name,
"imapsecret")) {
1897 retval->imapversion = imapversion;
1898 }
else if (!strcasecmp(
var->name,
"imapfolder")) {
1900 retval->imapversion = imapversion;
1901 }
else if (!strcasecmp(
var->name,
"imapvmshareid")) {
1903 retval->imapversion = imapversion;
1922 for (i = 0; i < strlen(key); ++i) {
1947 if ((retval = (ivm ? ivm :
ast_calloc(1,
sizeof(*retval))))) {
1949 memset(retval, 0,
sizeof(*retval));
1994 if (cur->imapversion != imapversion) {
2005 if ((vmu = (ivm ? ivm :
ast_calloc(1,
sizeof(*vmu))))) {
2032 char *search_mailbox =
NULL;
2033 char *search_context =
NULL;
2037 vmu =
find_user(ivm, search_mailbox, search_context);
2076 "NewPassword", newpass);
2103 char *category =
NULL;
2104 const char *tmp =
NULL;
2118 ast_verb(4,
"Writing voicemail password to file %s succeeded\n", secretfn);
2123 ast_log(
LOG_WARNING,
"Writing voicemail password to file %s failed, falling back to config file\n", secretfn);
2129 if (!strcasecmp(category, vmu->
context)) {
2136 value = strstr(tmp,
",");
2139 sprintf(
new,
"%s", newpassword);
2142 sprintf(
new,
"%s%s", newpassword,
value);
2156 ast_test_suite_event_notify(
"PASSWORDCHANGED",
"Message: voicemail.conf updated with new password\r\nPasswordSource: voicemail.conf");
2173 ast_debug(4,
"users.conf: %s\n", category);
2174 if (!strcasecmp(category, vmu->
mailbox)) {
2175 char new[strlen(newpassword) + 1];
2177 ast_debug(3,
"looks like we need to make vmsecret!\n");
2183 sprintf(
new,
"%s", newpassword);
2185 ast_debug(4,
"failed to get category!\n");
2254static int make_file(
char *dest,
const int len,
const char *dir,
const int num)
2256 return snprintf(dest,
len,
"%s/msg%04d", dir, num);
2283 if (vmu &&
id == 0) {
2284 return vmu->imapfolder;
2342 int arraysize = (vmu->
maxmsg > count_msg ? vmu->
maxmsg : count_msg);
2355 if (arraysize > 0) {
2373static void vm_imap_delete(
char *
file,
int msgnum,
struct ast_vm_user *vmu)
2377 unsigned long messageNum;
2380 if (msgnum < 0 && !imapgreetings) {
2385 if (!(vms = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 0))) {
2386 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);
2391 imap_delete_old_greeting(
file, vms);
2397 messageNum = vms->msgArray[msgnum];
2398 if (messageNum == 0) {
2399 ast_log(
LOG_WARNING,
"msgnum %d, mailbox message %lu is zero.\n", msgnum, messageNum);
2402 ast_debug(3,
"deleting msgnum %d, which is mailbox message %lu\n", msgnum, messageNum);
2404 snprintf (arg,
sizeof(arg),
"%lu", messageNum);
2406 mail_setflag (vms->mailstream, arg,
"\\DELETED");
2407 mail_expunge(vms->mailstream);
2411static 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)
2418 const char *duration_str;
2462 sscanf(duration_str,
"%30d", &duration);
2478 vm_imap_delete(dir, msgnum, vmu);
2484static int imap_retrieve_greeting(
const char *dir,
const int msgnum,
struct ast_vm_user *vmu)
2487 char *
file, *filename;
2497 if (msgnum > -1 || !imapgreetings) {
2504 ast_debug(1,
"Failed to procure file name from directory passed.\n");
2510 if (!(vms_p = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 1)) &&
2511 !(vms_p = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 0))) {
2516 if (!(vms_p = create_vm_state_from_user(vmu))) {
2523 *vms_p->introfn =
'\0';
2537 for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
2538 mail_fetchstructure(vms_p->mailstream, i + 1, &body);
2540 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
2541 char *attachment = body->nested.part->next->body.parameter->value;
2542 char copy[strlen(attachment) + 1];
2544 strcpy(
copy, attachment);
2547 filename =
strsep(&attachment,
".");
2548 if (!strcmp(filename,
file)) {
2550 vms_p->msgArray[vms_p->
curmsg] = i + 1;
2552 save_body(body, vms_p,
"2", attachment, 0);
2563 if (curr_mbox != -1) {
2565 if (init_mailstream(vms_p, curr_mbox) || !vms_p->mailstream) {
2574static int imap_retrieve_file(
const char *dir,
const int msgnum,
const char *
mailbox,
const char *
context)
2577 char *header_content;
2578 char *attachedfilefmt;
2582 FILE *text_file_ptr;
2593 if (imapgreetings) {
2594 res = imap_retrieve_greeting(dir, msgnum, vmu);
2605 if (!(vms = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 0))) {
2620 if (curr_mbox < 0) {
2621 ast_debug(3,
"Mailbox folder curbox not set, defaulting to Inbox\n");
2624 init_mailstream(vms, curr_mbox);
2625 if (!vms->mailstream) {
2632 snprintf(vms->introfn,
sizeof(vms->introfn),
"%sintro", vms->
fn);
2640 ast_debug(3,
"Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
2641 if (vms->msgArray[msgnum] == 0) {
2649 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
2653 ast_log(
LOG_ERROR,
"Could not fetch header for message number %ld\n", vms->msgArray[msgnum]);
2659 mail_fetchstructure(vms->mailstream, vms->msgArray[msgnum], &body);
2663 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
2664 attachedfilefmt =
ast_strdupa(body->nested.part->next->body.parameter->value);
2673 strsep(&attachedfilefmt,
".");
2674 if (!attachedfilefmt) {
2675 ast_log(
LOG_ERROR,
"File format could not be obtained from IMAP message attachment\n");
2680 save_body(body, vms,
"2", attachedfilefmt, 0);
2681 if (save_body(body, vms,
"3", attachedfilefmt, 1)) {
2682 *vms->introfn =
'\0';
2686 snprintf(text_file,
sizeof(text_file),
"%s.%s", vms->
fn,
"txt");
2688 if (!(text_file_ptr = fopen(text_file,
"w"))) {
2693 fprintf(text_file_ptr,
"%s\n",
"[message]");
2695 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Caller-ID-Name:",
buf,
sizeof(
buf))) {
2696 fprintf(text_file_ptr,
"callerid=\"%s\" ",
S_OR(
buf,
""));
2698 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Caller-ID-Num:",
buf,
sizeof(
buf))) {
2699 fprintf(text_file_ptr,
"<%s>\n",
S_OR(
buf,
""));
2701 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Context:",
buf,
sizeof(
buf))) {
2702 fprintf(text_file_ptr,
"context=%s\n",
S_OR(
buf,
""));
2704 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Orig-time:",
buf,
sizeof(
buf))) {
2705 fprintf(text_file_ptr,
"origtime=%s\n",
S_OR(
buf,
""));
2707 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Duration:",
buf,
sizeof(
buf))) {
2708 fprintf(text_file_ptr,
"duration=%s\n",
S_OR(
buf,
""));
2710 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Category:",
buf,
sizeof(
buf))) {
2711 fprintf(text_file_ptr,
"category=%s\n",
S_OR(
buf,
""));
2713 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Flag:",
buf,
sizeof(
buf))) {
2714 fprintf(text_file_ptr,
"flag=%s\n",
S_OR(
buf,
""));
2716 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Message-ID:",
buf,
sizeof(
buf))) {
2717 fprintf(text_file_ptr,
"msg_id=%s\n",
S_OR(
buf,
""));
2719 fclose(text_file_ptr);
2726static int folder_int(
const char *folder)
2732 if (!strcasecmp(folder, imapfolder)) {
2734 }
else if (!strcasecmp(folder,
"Old")) {
2736 }
else if (!strcasecmp(folder,
"Work")) {
2738 }
else if (!strcasecmp(folder,
"Family")) {
2740 }
else if (!strcasecmp(folder,
"Friends")) {
2742 }
else if (!strcasecmp(folder,
"Cust1")) {
2744 }
else if (!strcasecmp(folder,
"Cust2")) {
2746 }
else if (!strcasecmp(folder,
"Cust3")) {
2748 }
else if (!strcasecmp(folder,
"Cust4")) {
2750 }
else if (!strcasecmp(folder,
"Cust5")) {
2752 }
else if (!strcasecmp(folder,
"Urgent")) {
2759static int __messagecount(
const char *
context,
const char *
mailbox,
const char *folder)
2767 int fold = folder_int(folder);
2780 memset(&vmus, 0,
sizeof(vmus));
2788 if (vmu->imapuser[0] ==
'\0') {
2796 if (vmu->imapuser[0] ==
'\0') {
2803 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1);
2808 ast_debug(3,
"Returning before search - user is logged in\n");
2820 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 0);
2826 vms_p = create_vm_state_from_user(vmu);
2828 ret = init_mailstream(vms_p, fold);
2829 if (!vms_p->mailstream) {
2836 pgm = mail_newsearchpgm ();
2837 hdr = mail_newsearchheader (
"X-Asterisk-VM-Extension", (
char *)(!
ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid :
mailbox));
2838 hdr->next = mail_newsearchheader(
"X-Asterisk-VM-Context", (
char *)
S_OR(
context,
"default"));
2864 vms_p->vmArrayIndex = 0;
2865 mail_search_full (vms_p->mailstream,
NULL, pgm, NIL);
2866 if (fold == 0 && urgent == 0)
2870 if (fold == 0 && urgent == 1)
2873 mail_free_searchpgm(&pgm);
2877 return vms_p->vmArrayIndex;
2880 mail_ping(vms_p->mailstream);
2890 check_quota(vms, vmu->imapfolder);
2891 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
2892 ast_debug(1,
"*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
2902 ast_log(
LOG_WARNING,
"Unable to leave message since we will exceed the maximum number of messages allowed (%u >= %u)\n", msgnum, vmu->
maxmsg);
2921static int messagecount(
const char *mailbox_id,
const char *folder)
2937 return count < 0 ? 0 : count;
2940static 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)
2948 char tmp[80] =
"/tmp/astmail-XXXXXX";
2954 char *imap_flags = NIL;
2963 if(!imapgreetings) {
2970 if (imap_check_limits(chan, vms, vmu, msgcount)) {
2976 ast_debug(3,
"Setting message flag \\\\FLAGGED.\n");
2977 imap_flags =
"\\FLAGGED";
2993 snprintf(introfn,
sizeof(introfn),
"%sintro",
fn);
3008 if (!strcmp(fmt,
"wav49"))
3010 ast_debug(3,
"Storing file '%s', format '%s'\n",
fn, fmt);
3023 if (msgnum < 0 && imapgreetings) {
3028 imap_delete_old_greeting(
fn, vms);
3034 fn, introfn, fmt, duration, 1, chan,
NULL, 1,
flag, msg_id);
3042 *(vmu->
email) =
'\0';
3051 ((
char *)
buf)[
len] =
'\0';
3053 ret = init_mailstream(vms, box);
3057 if(!mail_append_full(vms->mailstream,
mailbox, imap_flags, NIL, &
str))
3073 *(vmu->
email) =
'\0';
3092static int inboxcount2(
const char *mailbox_context,
int *urgentmsgs,
int *newmsgs,
int *oldmsgs)
3107 ast_debug(3,
"Mailbox is set to %s\n", mailbox_context);
3114 if (strchr(mailbox_context,
',')) {
3115 int tmpnew, tmpold, tmpurgent;
3118 while ((cur =
strsep(&mb,
", "))) {
3128 *urgentmsgs += tmpurgent;
3140 mailboxnc = (
char *) mailbox_context;
3149 if ((count = __messagecount(
context, mailboxnc, vmu->imapfolder)) < 0) {
3157 if ((count = __messagecount(
context, mailboxnc,
"Old")) < 0) {
3163 if ((count = __messagecount(
context, mailboxnc,
"Urgent")) < 0) {
3166 *urgentmsgs = count;
3183 char tmp[256], *tmp2, *box, *
context;
3186 if (strchr(tmp2,
',') || strchr(tmp2,
'&')) {
3187 while ((box =
strsep(&tmp2,
",&"))) {
3195 if ((
context = strchr(tmp,
'@'))) {
3200 return __messagecount(
context, tmp, folder) > 0 ? 1 : 0;
3222 char messagestring[10];
3223 if (msgnum >= recip->
maxmsg) {
3227 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
3231 if (!get_vm_state_by_imapuser(recip->imapuser, 0)) {
3235 snprintf(messagestring,
sizeof(messagestring),
"%ld", sendvms->msgArray[msgnum]);
3237 if ((mail_copy(sendvms->mailstream, messagestring, (
char *)
mbox(vmu, imbox)) == T)) {
3246static void imap_mailbox_name(
char *spec,
size_t len,
struct vm_state *vms,
int box,
int use_folder)
3248 char tmp[256], *t = tmp;
3249 size_t left =
sizeof(tmp);
3282 snprintf(spec,
len,
"%s%s", tmp, use_folder? vms->imapfolder:
"INBOX");
3284 snprintf(spec,
len,
"%s%s", tmp, greetingfolder);
3288 snprintf(spec,
len,
"%s%s%c%s", tmp, imapparentfolder, delimiter,
mbox(
NULL, box));
3290 snprintf(spec,
len,
"%s%s", tmp,
mbox(
NULL, box));
3295static int init_mailstream(
struct vm_state *vms,
int box)
3297 MAILSTREAM *stream = NIL;
3305 ast_debug(3,
"vm_state user is:%s\n", vms->imapuser);
3306 if (vms->mailstream == NIL || !vms->mailstream) {
3309 stream = vms->mailstream;
3314 if (delimiter ==
'\0') {
3316#ifdef USE_SYSTEM_IMAP
3317#include <imap/linkage.c>
3318#elif defined(USE_SYSTEM_CCLIENT)
3319#include <c-client/linkage.c>
3324 imap_mailbox_name(tmp,
sizeof(tmp), vms, 0, 1);
3327 stream = mail_open (stream, tmp,
debug ? OP_DEBUG : NIL);
3330 if (stream == NIL) {
3334 get_mailbox_delimiter(vms, stream);
3336 for (cp = vms->imapfolder; *cp; cp++)
3341 imap_mailbox_name(tmp,
sizeof(tmp), vms, box, 1);
3342 ast_debug(3,
"Before mail_open, server: %s, box:%d\n", tmp, box);
3345 vms->mailstream = mail_open (stream, tmp,
debug ? OP_DEBUG : NIL);
3347 if (vms->mailstream && !mail_status(vms->mailstream, tmp, SA_UIDNEXT)) {
3348 mail_create(vms->mailstream, tmp);
3352 if (vms->mailstream == NIL) {
3372 ast_copy_string(vms->imapfolder, vmu->imapfolder,
sizeof(vms->imapfolder));
3373 ast_copy_string(vms->imapserver, vmu->imapserver,
sizeof(vms->imapserver));
3375 ast_copy_string(vms->imapflags, vmu->imapflags,
sizeof(vms->imapflags));
3376 vms->imapversion = vmu->imapversion;
3377 ast_debug(3,
"Before init_mailstream, user is %s\n", vmu->imapuser);
3379 if (init_mailstream(vms, box) || !vms->mailstream) {
3388 ast_debug(3,
"Mailbox name set to: %s, about to check quotas\n",
mbox(vmu, box));
3389 check_quota(vms, (
char *)
mbox(vmu, box));
3393 pgm = mail_newsearchpgm();
3396 hdr = mail_newsearchheader(
"X-Asterisk-VM-Extension", (!
ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->
mailbox));
3397 hdr->next = mail_newsearchheader(
"X-Asterisk-VM-Context", vmu->
context);
3408 }
else if (box ==
NEW_FOLDER && urgent == 0) {
3418 ast_debug(3,
"Before mail_search_full, user is %s\n", vmu->imapuser);
3420 vms->vmArrayIndex = 0;
3421 mail_search_full (vms->mailstream,
NULL, pgm, NIL);
3422 vms->
lastmsg = vms->vmArrayIndex - 1;
3423 mail_free_searchpgm(&pgm);
3429 ast_log(
LOG_WARNING,
"The code expects the old messages to be checked first, fix the code.\n");
3440static void write_file(
char *filename,
char *buffer,
unsigned long len)
3444 if (!filename || !buffer) {
3448 if (!(output = fopen(filename,
"w"))) {
3453 if (fwrite(buffer,
len, 1, output) != 1) {
3454 if (ferror(output)) {
3461static void update_messages_by_imapuser(
const char *
user,
unsigned long number)
3463 struct vm_state *vms = get_vm_state_by_imapuser(
user, 1);
3465 if (!vms && !(vms = get_vm_state_by_imapuser(
user, 0))) {
3469 ast_debug(3,
"saving mailbox message number %lu as message %d. Interactive set to %d\n",
number, vms->vmArrayIndex, vms->interactive);
3472 if (vms->vmArrayIndex >= vms->msg_array_max) {
3473 long *new_mem =
ast_realloc(vms->msgArray, 2 * vms->msg_array_max *
sizeof(
long));
3477 vms->msgArray = new_mem;
3478 vms->msg_array_max *= 2;
3481 vms->msgArray[vms->vmArrayIndex++] =
number;
3484void mm_searched(MAILSTREAM *stream,
unsigned long number)
3494static struct ast_vm_user *find_user_realtime_imapuser(
const char *imapuser)
3519void mm_exists(MAILSTREAM * stream,
unsigned long number)
3528void mm_expunged(MAILSTREAM * stream,
unsigned long number)
3537void mm_flags(MAILSTREAM * stream,
unsigned long number)
3546void mm_notify(MAILSTREAM * stream,
char *
string,
long errflg)
3548 ast_debug(5,
"Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg,
string);
3549 mm_log (
string, errflg);
3553void mm_list(MAILSTREAM * stream,
int delim,
char *
mailbox,
long attributes)
3555 if (delimiter ==
'\0') {
3560 if (attributes & LATT_NOINFERIORS)
3562 if (attributes & LATT_NOSELECT)
3564 if (attributes & LATT_MARKED)
3566 if (attributes & LATT_UNMARKED)
3571void mm_lsub(MAILSTREAM * stream,
int delim,
char *
mailbox,
long attributes)
3574 if (attributes & LATT_NOINFERIORS)
3576 if (attributes & LATT_NOSELECT)
3578 if (attributes & LATT_MARKED)
3580 if (attributes & LATT_UNMARKED)
3585void mm_status(MAILSTREAM * stream,
char *
mailbox, MAILSTATUS *
status)
3594 if (
status->flags & SA_MESSAGES) {
3597 if (
status->flags & SA_RECENT) {
3600 if (
status->flags & SA_UNSEEN) {
3603 if (
status->flags & SA_UIDVALIDITY) {
3606 if (
status->flags & SA_UIDNEXT) {
3615void mm_log(
char *
string,
long errflg)
3617 switch ((
short) errflg) {
3619 ast_debug(1,
"IMAP Info: %s\n",
string);
3632void mm_dlog(
char *
string)
3638void mm_login(NETMBX * mb,
char *
user,
char *pwd,
long trial)
3642 ast_debug(4,
"Entering callback mm_login\n");
3651 if (!strcasecmp(mb->user, vmu->imapuser)) {
3657 if ((vmu = find_user_realtime_imapuser(mb->user))) {
3666void mm_critical(MAILSTREAM * stream)
3671void mm_nocritical(MAILSTREAM * stream)
3676long mm_diskerror(MAILSTREAM * stream,
long errcode,
long serious)
3678 kill (getpid (), SIGSTOP);
3683void mm_fatal(
char *
string)
3689static void mm_parsequota(MAILSTREAM *stream,
unsigned char *msg, QUOTALIST *pquota)
3693 char buf[1024] =
"";
3694 unsigned long usage = 0, limit = 0;
3697 usage = pquota->usage;
3698 limit = pquota->limit;
3699 pquota = pquota->next;
3702 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)))) {
3709 vms->quota_usage =
usage;
3710 vms->quota_limit = limit;
3713static char *get_header_by_tag(
char *
header,
char *tag,
char *
buf,
size_t len)
3715 char *start, *eol_pnt;
3721 taglen = strlen(tag) + 1;
3732 if ((eol_pnt = strchr(
buf,
'\r')) || (eol_pnt = strchr(
buf,
'\n')))
3737static char *get_user_by_mailbox(
char *
mailbox,
char *
buf,
size_t len)
3739 char *start, *eol_pnt, *
quote;
3744 if (!(start = strstr(
mailbox,
"/user=")))
3750 if ((eol_pnt = strchr(
buf,
'/')) || (eol_pnt = strchr(
buf,
'}'))) {
3755 if ((eol_pnt = strchr(
quote + 1,
'"'))) {
3766 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
3767 if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->
username, vmu->
mailbox)) {
3770 ast_debug(5,
"Adding new vmstate for %s\n", vmu->imapuser);
3772 if (!(vms_p =
ast_calloc(1,
sizeof(*vms_p))))
3774 ast_copy_string(vms_p->imapuser, vmu->imapuser,
sizeof(vms_p->imapuser));
3775 ast_copy_string(vms_p->imapfolder, vmu->imapfolder,
sizeof(vms_p->imapfolder));
3776 ast_copy_string(vms_p->imapserver, vmu->imapserver,
sizeof(vms_p->imapserver));
3777 ast_copy_string(vms_p->imapport, vmu->imapport,
sizeof(vms_p->imapport));
3778 ast_copy_string(vms_p->imapflags, vmu->imapflags,
sizeof(vms_p->imapflags));
3781 vms_p->mailstream = NIL;
3782 vms_p->imapversion = vmu->imapversion;
3783 ast_debug(5,
"Copied %s to %s\n", vmu->imapuser, vms_p->imapuser);
3787 init_vm_state(vms_p);
3788 vmstate_insert(vms_p);
3792static struct vm_state *get_vm_state_by_imapuser(
const char *
user,
int interactive)
3794 struct vmstate *vlist =
NULL;
3798 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
3799 if ((vms = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms->imapuser,
user)) {
3810 if (vlist->vms->imapversion != imapversion) {
3814 if (!strcmp(vlist->vms->imapuser,
user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
3826static struct vm_state *get_vm_state_by_mailbox(
const char *
mailbox,
const char *
context,
int interactive)
3829 struct vmstate *vlist =
NULL;
3830 const char *local_context =
S_OR(
context,
"default");
3834 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
3835 if ((vms = pthread_getspecific(ts_vmstate.key)) &&
3847 if (vlist->vms->imapversion != imapversion) {
3851 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);
3853 if (!strcmp(vlist->vms->username,
mailbox) && !strcmp(vlist->vms->context, local_context) && vlist->vms->interactive == interactive) {
3866static void vmstate_insert(
struct vm_state *vms)
3874 if (vms->interactive == 1) {
3880 vms->vmArrayIndex = altvms->vmArrayIndex;
3885 vms->persist_vms = altvms;
3887#ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
3888 vms->mailstream = altvms->mailstream;
3890 vms->mailstream = NIL;
3901 ast_debug(3,
"Inserting vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->
username);
3908static void vmstate_delete(
struct vm_state *vms)
3910 struct vmstate *vc =
NULL;
3915 if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
3919 altvms->updated = 1;
3920 vms->mailstream = mail_close(vms->mailstream);
3926 ast_debug(3,
"Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->
username);
3930 if (vc->vms == vms) {
3941 vc->vms->msgArray =
NULL;
3942 vc->vms->msg_array_max = 0;
3950static void set_update(MAILSTREAM * stream)
3954 char buf[1024] =
"";
3956 if (!(
user = get_user_by_mailbox(
mailbox,
buf,
sizeof(
buf))) || !(vms = get_vm_state_by_imapuser(
user, 0))) {
3967static void init_vm_state(
struct vm_state *vms)
3970 vms->msgArray =
ast_calloc(vms->msg_array_max,
sizeof(
long));
3971 if (!vms->msgArray) {
3973 vms->msg_array_max = 0;
3975 vms->vmArrayIndex = 0;
3979static int save_body(BODY *body,
struct vm_state *vms,
char *section,
char *format,
int is_intro)
3983 char *
fn = is_intro ? vms->introfn : vms->
fn;
3984 unsigned long len = 0;
3985 unsigned long newlen = 0;
3988 if (!body || body == NIL)
3992 body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->
curmsg], section, &
len);
3996 "Msgno %ld, section %s. The body's content size %ld is huge (max %ld). User:%s, mailbox %s\n",
4000 if (body_content != NIL &&
len) {
4001 snprintf(filename,
sizeof(filename),
"%s.%s",
fn, format);
4003 body_decoded = rfc822_base64((
unsigned char *) body_content,
len, &newlen);
4005 if (!newlen || !body_decoded) {
4008 write_file(filename, (
char *) body_decoded, newlen);
4010 ast_debug(5,
"Body of message is NULL.\n");
4024static void get_mailbox_delimiter(
struct vm_state *vms, MAILSTREAM *stream) {
4026 snprintf(tmp,
sizeof(tmp),
"{%s}",
S_OR(vms->imapserver, imapserver));
4027 mail_list(stream, tmp,
"*");
4039 mail_parameters(
NULL, SET_QUOTA, (
void *) mm_parsequota);
4041 if (vms && vms->mailstream !=
NULL) {
4042 imap_getquotaroot(vms->mailstream,
mailbox);
4065#define MSG_ID_LEN 256
4088#define MAKE_SQL_PTRA(__sql_fmt) \
4091 char *__sql = ast_alloca(strlen(__sql_fmt) + odbc_table_len); \
4092 sprintf(__sql, __sql_fmt, odbc_table); \
4106#define MAKE_SQL_PTRA2(__sql_fmt) \
4109 char *__sql = ast_alloca(strlen(__sql_fmt) + (odbc_table_len * 2)); \
4110 sprintf(__sql, __sql_fmt, odbc_table, odbc_table); \
4114struct generic_prepare_struct {
4122 struct generic_prepare_struct *gps = data;
4126 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->
con, &stmt);
4127 if (!SQL_SUCCEEDED(res)) {
4132 if (!SQL_SUCCEEDED(res)) {
4134 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4137 for (i = 0; i < gps->argc; i++)
4138 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0,
NULL);
4143static void odbc_update_msg_id(
char *dir,
int msg_num,
char *msg_id)
4146 char *sql = MAKE_SQL_PTRA(
"UPDATE %s SET msg_id=? WHERE dir=? AND msgnum=?");
4148 char msg_num_str[20];
4149 char *argv[] = { msg_id, dir, msg_num_str };
4150 struct generic_prepare_struct gps = { .sql = sql, .argc = 3, .argv = argv };
4151 SCOPE_ENTER(3,
"dir: %s msg_num: %d msg_id: %s\n", dir, msg_num, msg_id);
4158 snprintf(msg_num_str,
sizeof(msg_num_str),
"%d", msg_num);
4163 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4169#define AUDIO_ON_DISK_MAGIC "AUDMAGIC"
4170#define AUDIO_ON_DISK_MAGIC_LEN 8
4172static void odbc_update_set_audmagic(
char *dir,
int msg_num)
4175 char *sql = MAKE_SQL_PTRA(
"UPDATE %s SET recording=? WHERE dir=? AND msgnum=?");
4177 SQLLEN datalen = AUDIO_ON_DISK_MAGIC_LEN;
4178 SQLLEN indlen = datalen;
4180 char msg_num_str[20];
4181 SCOPE_ENTER(3,
"dir: %s msg_num: %d\n", dir, msg_num);
4188 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->
con, &stmt);
4189 if (!SQL_SUCCEEDED(res)) {
4194 snprintf(msg_num_str,
sizeof(msg_num_str),
"%d", msg_num);
4196 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY,
4197 datalen, 0, (
void *) AUDIO_ON_DISK_MAGIC,
4200 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR,
4201 strlen(dir), 0, (
void *) dir, 0,
NULL);
4203 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR,
4204 strlen(msg_num_str), 0, (
void *) msg_num_str, 0,
NULL);
4207 if (!SQL_SUCCEEDED(res)) {
4211 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4218static int odbc_store_message(
const char *dir,
const char *mailboxuser,
const char *mailboxcontext,
int msgnum);
4234static int odbc_retrieve_message(
char *dir,
int msgnum)
4240 void *fdm = MAP_FAILED;
4241 SQLSMALLINT colcount = 0;
4243 char *sql = MAKE_SQL_PTRA(
"SELECT * FROM %s WHERE dir=? AND msgnum=?");
4248 SQLSMALLINT datatype;
4249 SQLSMALLINT decimaldigits;
4250 SQLSMALLINT nullable;
4255 char *fn = MAKE_FILE_PTRA(dir, msgnum);
4256 char *full_fn = MAKE_FILE_EXT_PTRA(dir, msgnum,
"txt");
4258 char *mailboxuser =
NULL;
4259 char *mailboxcontext =
NULL;
4261 char *argv[] = { dir, msgnums };
4262 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
4264 int storage_conversion_to_disk = 0;
4265 int storage_conversion_to_odbc = 0;
4266 SCOPE_ENTER(3,
"dir: %s msgnum: %d msgtype: %s\n", dir, msgnum, msgnum < 0 ?
"Greeting" :
"Message");
4274 c = strchr(fmt,
'|');
4277 if (!strcasecmp(fmt,
"wav49"))
4280 snprintf(msgnums,
sizeof(msgnums),
"%d", msgnum);
4282 ast_trace(-1,
"Opening '%s' for writing\n", full_fn);
4283 if (!(f = fopen(full_fn,
"w+"))) {
4288 sprintf(full_fn,
"%s.%s", fn, fmt);
4296 res = SQLFetch(stmt);
4297 if (!SQL_SUCCEEDED(res)) {
4298 if (res != SQL_NO_DATA) {
4301 goto bail_with_handle;
4304 res = SQLNumResultCols(stmt, &colcount);
4305 if (!SQL_SUCCEEDED(res)) {
4307 goto bail_with_handle;
4310 fprintf(f,
"[message]\n");
4311 for (x = 0; x < colcount; x++) {
4314 collen =
sizeof(coltitle);
4315 res = SQLDescribeCol(stmt, x + 1, (
unsigned char *) coltitle,
sizeof(coltitle), &collen,
4316 &datatype, &colsize, &decimaldigits, &nullable);
4317 if (!SQL_SUCCEEDED(res)) {
4319 goto bail_with_handle;
4322 if (!strcasecmp(coltitle,
"recording")) {
4326 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
4328 ast_trace(-1,
"Audio size: %ld\n", colsize2);
4329 if (colsize2 == AUDIO_ON_DISK_MAGIC_LEN) {
4330 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, AUDIO_ON_DISK_MAGIC_LEN,
NULL);
4331 if (memcmp(rowdata, AUDIO_ON_DISK_MAGIC, AUDIO_ON_DISK_MAGIC_LEN) != 0) {
4333 rowdata[0], rowdata[1], rowdata[2], rowdata[3], rowdata[4], rowdata[5], rowdata[6],
4334 rowdata[7], full_fn);
4335 goto bail_with_handle;
4337 ast_trace(-1,
"Audio is stored on disk. No need to write '%s'\n", full_fn);
4339 storage_conversion_to_odbc = 1;
4345 ast_trace(-1,
"Opening '%s' for writing\n", full_fn);
4349 goto bail_with_handle;
4352 storage_conversion_to_disk = 1;
4355 lseek(fd, fdlen - 1, SEEK_SET);
4356 if (write(fd, tmp, 1) != 1) {
4362 for (offset = 0; offset < colsize2; offset +=
CHUNKSIZE) {
4363 if ((fdm = mmap(
NULL,
CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
4365 goto bail_with_handle;
4367 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm,
CHUNKSIZE,
NULL);
4369 if (!SQL_SUCCEEDED(res)) {
4372 goto bail_with_handle;
4375 if (truncate(full_fn, fdlen) < 0) {
4378 ast_trace(-1,
"Wrote %d bytes to '%s'\n", (
int)fdlen, full_fn);
4380 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata,
sizeof(rowdata),
NULL);
4381 if (res == SQL_NULL_DATA && !strcasecmp(coltitle,
"msg_id")) {
4387 ast_trace(-1,
"msg_id was NULL. Generating new one: %s\n", msg_id);
4388 snprintf(rowdata,
sizeof(rowdata),
"%s", msg_id);
4389 }
else if (!strcasecmp(coltitle,
"mailboxuser")) {
4391 }
else if (!strcasecmp(coltitle,
"mailboxcontext")) {
4393 }
else if (res == SQL_NULL_DATA && !strcasecmp(coltitle,
"category")) {
4395 ast_trace(-1,
"Ignoring null category column in ODBC voicemail retrieve_file.\n");
4397 }
else if (!SQL_SUCCEEDED(res)) {
4399 goto bail_with_handle;
4401 if (strcasecmp(coltitle,
"msgnum") && strcasecmp(coltitle,
"dir")) {
4402 fprintf(f,
"%s=%s\n", coltitle, rowdata);
4408 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4422 odbc_update_msg_id(dir, msgnum, msg_id);
4425 if (SQL_SUCCEEDED(res)) {
4426 if (storage_conversion_to_disk) {
4432 SCOPE_CALL(-1, odbc_update_set_audmagic, dir, msgnum);
4434 if (storage_conversion_to_odbc) {
4441 SCOPE_CALL(-1, odbc_store_message, dir, mailboxuser, mailboxcontext, msgnum);
4457static int odbc_last_message_index(
char *dir)
4462 char *sql = MAKE_SQL_PTRA(
"SELECT msgnum FROM %s WHERE dir=? order by msgnum desc");
4464 char *argv[] = { dir };
4465 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
4480 res = SQLFetch(stmt);
4481 if (!SQL_SUCCEEDED(res)) {
4482 if (res == SQL_NO_DATA) {
4483 ast_trace(-1,
"Directory '%s' has no messages and therefore no index was retrieved.\n", dir);
4487 goto bail_with_handle;
4490 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata,
sizeof(rowdata),
NULL);
4491 if (!SQL_SUCCEEDED(res)) {
4493 goto bail_with_handle;
4496 if (sscanf(rowdata,
"%30d", &x) != 1) {
4501 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4518static int odbc_message_exists(
char *dir,
int msgnum)
4523 char *sql = MAKE_SQL_PTRA(
"SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?");
4526 char *argv[] = { dir, msgnums };
4527 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
4529 SCOPE_ENTER(3,
"dir: %s msgnum: %d\n", dir, msgnum);
4536 snprintf(msgnums,
sizeof(msgnums),
"%d", msgnum);
4543 res = SQLFetch(stmt);
4544 if (!SQL_SUCCEEDED(res)) {
4546 goto bail_with_handle;
4549 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata,
sizeof(rowdata),
NULL);
4550 if (!SQL_SUCCEEDED(res)) {
4552 goto bail_with_handle;
4555 if (sscanf(rowdata,
"%30d", &x) != 1) {
4560 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4576static int odbc_count_messages(
struct ast_vm_user *vmu,
char *dir)
4581 char *sql = MAKE_SQL_PTRA(
"SELECT COUNT(*) FROM %s WHERE dir=?");
4583 char *argv[] = { dir };
4584 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
4599 res = SQLFetch(stmt);
4600 if (!SQL_SUCCEEDED(res)) {
4602 goto bail_with_handle;
4605 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata,
sizeof(rowdata),
NULL);
4606 if (!SQL_SUCCEEDED(res)) {
4608 goto bail_with_handle;
4611 if (sscanf(rowdata,
"%30d", &x) != 1) {
4616 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4631#define DELETE_SQL_FMT "DELETE FROM %s WHERE dir=? AND msgnum=?"
4632static void odbc_delete_message(
const char *sdir,
int smsg)
4635 char *sql = MAKE_SQL_PTRA(DELETE_SQL_FMT);
4637 char *argv[] = {
NULL, msgnums };
4638 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
4640 SCOPE_ENTER(3,
"sdir: %s smsg: %d\n", sdir, smsg);
4649 snprintf(msgnums,
sizeof(msgnums),
"%d", smsg);
4654 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4659 char *src_fn = MAKE_FILE_PTRA(sdir, smsg);
4660 ast_trace(-1,
"Audio stored on disk. Deleting '%s'\n", src_fn);
4678#define COPY_SQL_FMT "INSERT INTO %s (dir, msgnum, msg_id, context, callerid, origtime, " \
4679 "duration, recording, flag, mailboxuser, mailboxcontext) " \
4680 "SELECT ?,?,msg_id,context,callerid,origtime,duration,recording,flag,?,? " \
4681 "FROM %s WHERE dir=? AND msgnum=?"
4682static void odbc_copy_message(
char *sdir,
int smsg,
char *ddir,
int dmsg,
char *dmailboxuser,
char *dmailboxcontext)
4685 char *sql = MAKE_SQL_PTRA2(COPY_SQL_FMT);
4689 char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums };
4690 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
4691 SCOPE_ENTER(3,
"sdir: %s smsg: %d duser: %s dcontext: %s ddir: %s dmsg: %d\n",
4692 sdir, smsg, dmailboxuser, dmailboxcontext, ddir, dmsg);
4694 SCOPE_CALL(-1, odbc_delete_message, ddir, dmsg);
4701 snprintf(msgnums,
sizeof(msgnums),
"%d", smsg);
4702 snprintf(msgnumd,
sizeof(msgnumd),
"%d", dmsg);
4706 ast_log(
AST_LOG_WARNING,
"SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
4708 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4712 char *src_fn = MAKE_FILE_PTRA(sdir, smsg);
4713 char *dst_fn = MAKE_FILE_PTRA(ddir, dmsg);
4715 ast_trace(-1,
"Audio stored on disk. Copying '%s' to '%s'\n", src_fn, dst_fn);
4725 const char *msgnums;
4730 const char *callerid;
4731 const char *origtime;
4732 const char *duration;
4733 const char *mailboxuser;
4734 const char *mailboxcontext;
4735 const char *category;
4740#define STORE_SQL_FMT_CAT "INSERT INTO %s (dir, msgnum, recording, context, callerid, " \
4741 "origtime, duration, mailboxuser, mailboxcontext, flag, msg_id, category) " \
4742 "VALUES (?,?,?,?,?,?,?,?,?,?,?,?)"
4743#define STORE_SQL_FMT "INSERT INTO %s (dir, msgnum, recording, context, callerid, "\
4744 "origtime, duration, mailboxuser, mailboxcontext, flag, msg_id) "\
4745 "VALUES (?,?,?,?,?,?,?,?,?,?,?)"
4747static SQLHSTMT odbc_insert_data_cb(
struct odbc_obj *obj,
void *vdata)
4749 struct insert_data *data = vdata;
4754 SCOPE_ENTER(3,
"dir: %s msgnums: %s msg_id: %s\n", data->dir, data->msgnums,
4757 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->
con, &stmt);
4758 if (!SQL_SUCCEEDED(res)) {
4763 delete_sql = MAKE_SQL_PTRA(DELETE_SQL_FMT);
4764 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->dir), 0, (
void *) data->dir, 0,
NULL);
4765 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msgnums), 0, (
void *) data->msgnums, 0,
NULL);
4767 if (!SQL_SUCCEEDED(res)) {
4768 ast_trace(-1,
"There wasn't an existing row. Good.\n");
4770 ast_trace(-1,
"There WAS an existing row. This is OK if we're replacing a message.\n");
4772 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4775 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->
con, &stmt);
4776 if (!SQL_SUCCEEDED(res)) {
4780 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->dir), 0, (
void *) data->dir, 0,
NULL);
4781 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msgnums), 0, (
void *) data->msgnums, 0,
NULL);
4782 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, data->datalen, 0, (
void *) data->data, data->datalen, &data->indlen);
4783 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->context), 0, (
void *) data->context, 0,
NULL);
4784 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->callerid), 0, (
void *) data->callerid, 0,
NULL);
4785 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->origtime), 0, (
void *) data->origtime, 0,
NULL);
4786 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->duration), 0, (
void *) data->duration, 0,
NULL);
4787 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxuser), 0, (
void *) data->mailboxuser, 0,
NULL);
4788 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxcontext), 0, (
void *) data->mailboxcontext, 0,
NULL);
4789 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->flag), 0, (
void *) data->flag, 0,
NULL);
4790 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msg_id), 0, (
void *) data->msg_id, 0,
NULL);
4792 insert_sql = MAKE_SQL_PTRA(STORE_SQL_FMT_CAT);
4793 SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (
void *) data->category, 0,
NULL);
4795 insert_sql = MAKE_SQL_PTRA(STORE_SQL_FMT);
4798 if (!SQL_SUCCEEDED(res)) {
4801 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4821static int odbc_store_message(
const char *dir,
const char *mailboxuser,
const char *mailboxcontext,
int msgnum)
4825 void *fdm = MAP_FAILED;
4829 char *fn = MAKE_FILE_PTRA(dir, msgnum);
4830 char *full_fn = MAKE_FILE_EXT_PTRA(dir, msgnum,
"txt");
4835 struct insert_data idata = { .msgnums = msgnums, .dir = dir, .mailboxuser = mailboxuser, .mailboxcontext = mailboxcontext,
4836 .context =
"", .callerid =
"", .origtime =
"", .duration =
"", .category =
"", .flag =
"", .msg_id =
"" };
4838 SCOPE_ENTER(3,
"dir: %s user: %s context: %s msgnum: %d msgtype: %s\n",
4839 dir, mailboxuser, mailboxcontext, msgnum, msgnum < 0 ?
"Greeting" :
"Message");
4848 c = strchr(fmt,
'|');
4851 if (!strcasecmp(fmt,
"wav49"))
4855 snprintf(msgnums,
sizeof(msgnums),
"%d", msgnum);
4858 ast_trace(-1,
"Opening '%s'\n", full_fn);
4862 ast_trace(-1,
"No information file found for '%s'. This is a greeting so this is OK.\n", full_fn);
4870 sprintf(full_fn,
"%s.%s", fn, fmt);
4872 ast_trace(-1,
"Audio stored on disk. No need to open '%s'\n", full_fn);
4874 ast_trace(-1,
"Opening '%s'\n", full_fn);
4875 fd = open(full_fn, O_RDWR);
4884 ast_trace(-1,
"Using information file '%s'\n", fn);
4889 idata.callerid =
"";
4892 idata.origtime =
"";
4895 idata.duration =
"";
4898 idata.category =
"";
4909 ast_trace(-1,
"Audio stored on disk. Not reading sound file '%s' but setting magic number.\n", full_fn);
4910 idata.data = AUDIO_ON_DISK_MAGIC;
4911 idata.datalen = idata.indlen = AUDIO_ON_DISK_MAGIC_LEN;
4913 ast_trace(-1,
"Reading sound file '%s'\n", full_fn);
4914 fdlen = lseek(fd, 0, SEEK_END);
4915 if (fdlen < 0 || lseek(fd, 0, SEEK_SET) < 0) {
4920 fdm = mmap(
NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
4921 if (fdm == MAP_FAILED) {
4927 idata.datalen = idata.indlen = fdlen;
4931 idata.origtime =
"0";
4935 idata.duration =
"0";
4939 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4949 if (fdm != MAP_FAILED)
4956#undef STORE_SQL_FMT_CAT
4971static void odbc_rename_message(
char *sdir,
int smsg,
char *mailboxuser,
char *mailboxcontext,
char *ddir,
int dmsg)
4974 char *sql = MAKE_SQL_PTRA(
"UPDATE %s SET dir=?, msgnum=? WHERE mailboxuser=? AND mailboxcontext=? AND dir=? AND msgnum=?");
4978 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
4979 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
4980 SCOPE_ENTER(3,
"sdir: %s smsg: %d user: %s context: %s ddir: %s dmsg: %d\n", sdir, smsg,
4981 mailboxuser, mailboxcontext, ddir, dmsg);
4983 SCOPE_CALL(-1, odbc_delete_message, ddir, dmsg);
4990 snprintf(msgnums,
sizeof(msgnums),
"%d", smsg);
4991 snprintf(msgnumd,
sizeof(msgnumd),
"%d", dmsg);
4997 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
5001 char *src_fn = MAKE_FILE_PTRA(sdir, smsg);
5002 char *dst_fn = MAKE_FILE_PTRA(ddir, dmsg);
5004 ast_trace(-1,
"Recordings stored on disk. Renaming '%s' to '%s'\n", src_fn, dst_fn);
5022static int odbc_remove_files(
char *dir,
int msgnum)
5024 char *fn = MAKE_FILE_PTRA(dir, msgnum);
5025 char *full_fn = MAKE_FILE_EXT_PTRA(dir, msgnum,
"txt");
5026 SCOPE_ENTER(3,
"dir: %s msgnum: %d\n", dir, msgnum);
5029 ast_trace(-1,
"Audio stored on disk. Keeping '%s' sound files\n", fn);
5031 ast_trace(-1,
"Audio stored in ODBC. Removing '%s' sound files\n", fn);
5036 ast_trace(-1,
"Removing '%s' information file\n", full_fn);
5056 struct dirent *vment =
NULL;
5061 if ((vmdir = opendir(dir))) {
5062 while ((vment = readdir(vmdir))) {
5063 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7,
".txt", 4)) {
5086 snprintf(stxt,
sizeof(stxt),
"%s.txt", sfn);
5087 snprintf(dtxt,
sizeof(dtxt),
"%s.txt", dfn);
5109 struct dirent *msgdirent;
5118 if (!(msgdir = opendir(dir))) {
5122 while ((msgdirent = readdir(msgdir))) {
5126 ast_debug(4,
"%s map[%d] = %d, count = %d\n", dir, msgdirint, map[msgdirint], stopcount);
5132 stopcount -= map[x];
5151static int copy(
char *infile,
char *outfile)
5159#ifdef HARDLINK_WHEN_POSSIBLE
5161 if (!link(infile, outfile)) {
5166 if ((ifd = open(infile, O_RDONLY)) < 0) {
5191 wrlen = write(ofd,
buf,
len);
5220 const char *origmailbox =
"", *
context =
"", *exten =
"";
5221 const char *
priority =
"", *callerchan =
"", *callerid =
"", *origdate =
"";
5222 const char *origtime =
"", *category =
"", *duration =
"";
5225 snprintf(frompath2,
sizeof(frompath2),
"%s.txt", frompath);
5226 snprintf(topath2,
sizeof(topath2),
"%s.txt", topath);
5231 for (tmp =
var; tmp; tmp = tmp->
next) {
5232 if (!strcasecmp(tmp->
name,
"origmailbox")) {
5233 origmailbox = tmp->
value;
5234 }
else if (!strcasecmp(tmp->
name,
"context")) {
5236 }
else if (!strcasecmp(tmp->
name,
"exten")) {
5238 }
else if (!strcasecmp(tmp->
name,
"priority")) {
5240 }
else if (!strcasecmp(tmp->
name,
"callerchan")) {
5241 callerchan = tmp->
value;
5242 }
else if (!strcasecmp(tmp->
name,
"callerid")) {
5243 callerid = tmp->
value;
5244 }
else if (!strcasecmp(tmp->
name,
"origdate")) {
5245 origdate = tmp->
value;
5246 }
else if (!strcasecmp(tmp->
name,
"origtime")) {
5247 origtime = tmp->
value;
5248 }
else if (!strcasecmp(tmp->
name,
"category")) {
5249 category = tmp->
value;
5250 }
else if (!strcasecmp(tmp->
name,
"duration")) {
5251 duration = tmp->
value;
5254 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);
5256 copy(frompath2, topath2);
5276 txtsize = (strlen(
file) + 5)*
sizeof(
char);
5284 snprintf(txt, txtsize,
"%s.txt",
file);
5292static 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)
5296 char fromdir[256], fromfile[256];
5298 const char *origcallerid, *origtime;
5299 char origcidname[80], origcidnum[80], origdate[80];
5306 snprintf(num,
sizeof(num),
"%d", msgnum);
5320 make_file(fromfile,
sizeof(fromfile), fromdir, msgnum - 1);
5321 if (strlen(fromfile) <
sizeof(fromfile) - 5) {
5322 strcat(fromfile,
".txt");
5325 ast_debug(1,
"Config load for message text file '%s' failed\n", fromfile);
5331 ast_callerid_split(origcallerid, origcidname,
sizeof(origcidname), origcidnum,
sizeof(origcidnum));
5336 if ((origtime =
ast_variable_retrieve(msg_cfg,
"message",
"origtime")) && sscanf(origtime,
"%30d", &inttime) == 1) {
5337 struct timeval tv = { inttime, };
5360 for (ptr = from; *ptr; ptr++) {
5361 if (*ptr ==
'"' || *ptr ==
'\\') {
5402 if (*
str > 126 || *
str < 32 || strchr(
"()<>@,:;/\"[]?.=", *
str)) {
5429 int first_section = 1;
5433 for (; *start; start++) {
5434 int need_encoding = 0;
5435 if (*start < 33 || *start > 126 || strchr(
"()<>@,:;/\"[]?.=_", *start)) {
5438 if ((first_section && need_encoding && preamble +
ast_str_strlen(tmp) > 70) ||
5439 (first_section && !need_encoding && preamble +
ast_str_strlen(tmp) > 72) ||
5441 (!first_section && !need_encoding &&
ast_str_strlen(tmp) > 72)) {
5447 if (need_encoding && *start ==
' ') {
5449 }
else if (need_encoding) {
5488 const char *fromfolder,
5495 int attach_user_voicemail,
5497 const char *category,
5508 char enc_cidnum[256] =
"", enc_cidname[256] =
"";
5510 char *greeting_attachment;
5516 if (!str1 || !str2) {
5528 gethostname(host,
sizeof(host) - 1);
5530 if (strchr(srcemail,
'@')) {
5533 snprintf(who,
sizeof(who),
"%s@%s", srcemail, host);
5536 greeting_attachment = strrchr(
ast_strdupa(attach),
'/');
5537 if (greeting_attachment) {
5538 *greeting_attachment++ =
'\0';
5541 snprintf(dur,
sizeof(dur),
"%d:%02d", duration / 60, duration % 60);
5543 fprintf(p,
"Date: %s" ENDL, date);
5553 prep_email_sub_vars(ast, vmu, msgnum + 1,
context,
mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category,
flag);
5575 fprintf(p,
"From: Asterisk PBX <%s>" ENDL, who);
5582 char *next = emailsbuf;
5600 fprintf(p,
"Subject: New greeting '%s' on %s." ENDL, greeting_attachment, date);
5605 prep_email_sub_vars(ast, vmu, msgnum + 1,
context,
mailbox, fromfolder, cidnum, cidname, dur, date, category,
flag);
5628 fprintf(p,
"Subject: New message %d in mailbox %s" ENDL, msgnum + 1,
mailbox);
5630 fprintf(p,
"Subject: New %s message %d in mailbox %s" ENDL,
flag, msgnum + 1,
mailbox);
5634 fprintf(p,
"Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1,
mailbox);
5636 fprintf(p,
"Subject: [PBX]: New %s message %d in mailbox %s" ENDL,
flag, msgnum + 1,
mailbox);
5640 fprintf(p,
"Message-ID: <Asterisk-%d-%u-%s-%d@%s>" ENDL, msgnum + 1,
5644 fprintf(p,
"X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
5647 fprintf(p,
"X-Asterisk-VM-Context: %s" ENDL,
context);
5651 fprintf(p,
"X-Asterisk-VM-Extension: %s" ENDL,
mailbox);
5654 fprintf(p,
"X-Asterisk-VM-Flag: %s" ENDL,
S_OR(
flag,
""));
5656 fprintf(p,
"X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
5657 fprintf(p,
"X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
5658 fprintf(p,
"X-Asterisk-VM-Duration: %d" ENDL, duration);
5660 fprintf(p,
"X-Asterisk-VM-Category: %s" ENDL, category);
5662 fprintf(p,
"X-Asterisk-VM-Category: " ENDL);
5664 fprintf(p,
"X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ?
"Message" : greeting_attachment);
5665 fprintf(p,
"X-Asterisk-VM-Orig-date: %s" ENDL, date);
5666 fprintf(p,
"X-Asterisk-VM-Orig-time: %ld" ENDL, (
long) time(
NULL));
5667 fprintf(p,
"X-Asterisk-VM-Message-ID: %s" ENDL, msg_id);
5670 fprintf(p,
"X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
5673 fprintf(p,
"X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
5675 fprintf(p,
"MIME-Version: 1.0" ENDL);
5676 if (attach_user_voicemail) {
5678 snprintf(bound,
sizeof(bound),
"----voicemail_%d%s%d%u", msgnum + 1,
mailbox,
5679 (
int) getpid(), (
unsigned int)
ast_random());
5681 fprintf(p,
"Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
5682 fprintf(p,
ENDL ENDL "This is a multi-part message in MIME format." ENDL ENDL);
5683 fprintf(p,
"--%s" ENDL, bound);
5685 fprintf(p,
"Content-Type: text/plain; charset=%s" ENDL "Content-Transfer-Encoding: 8bit" ENDL ENDL,
charset);
5687 fprintf(p,
"This message is to let you know that your greeting '%s' was changed on %s." ENDL
5688 "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL,
5689 greeting_attachment, date);
5694 prep_email_sub_vars(ast, vmu, msgnum + 1,
context,
mailbox, fromfolder, cidnum, cidname, dur, date, category,
flag);
5702 if ((next = strchr(line,
'\n'))) {
5705 fprintf(p,
"%s" ENDL, line);
5722 char fromdir[256], fromfile[256], origdate[80] =
"", origcallerid[80] =
"";
5726 make_file(fromfile,
sizeof(fromfile), fromdir, msgnum);
5727 if (strlen(fromfile) <
sizeof(fromfile) - 5) {
5728 strcat(fromfile,
".txt");
5737 if ((v =
ast_variable_retrieve(msg_cfg,
"message",
"origtime")) && sscanf(v,
"%30d", &inttime) == 1) {
5738 struct timeval tv = { inttime, };
5743 fprintf(p,
"Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just forwarded"
5744 " a %s long message (number %d)" ENDL "in mailbox %s from %s, on %s" ENDL
5745 "(originally sent by %s on %s)" ENDL "so you might want to check it when you get a"
5747 msgnum + 1,
mailbox, (cidname ? cidname : (cidnum ? cidnum :
"an unknown caller")),
5748 date, origcallerid, origdate);
5755 fprintf(p,
"Dear %s:" ENDL ENDL "\tJust wanted to let you know you were just left a "
5756 "%s long message (number %d)" ENDL "in mailbox %s from %s, on %s so you might" ENDL
5757 "want to check it when you get a chance. Thanks!" ENDL ENDL "\t\t\t\t--Asterisk"
5759 (cidname ? cidname : (cidnum ? cidnum :
"an unknown caller")), date);
5763 if (imap || attach_user_voicemail) {
5765 snprintf(filename,
sizeof(filename),
"msg%04d.%s", msgnum, format);
5766 ast_debug(5,
"creating second attachment filename %s\n", filename);
5768 snprintf(filename,
sizeof(filename),
"msgintro%04d.%s", msgnum, format);
5769 ast_debug(5,
"creating attachment filename %s\n", filename);
5772 snprintf(filename,
sizeof(filename),
"msg%04d.%s", msgnum, format);
5773 ast_debug(5,
"creating attachment filename %s, no second attachment.\n", filename);
5785 char *file_to_delete =
NULL, *dir_to_delete =
NULL;
5789 char altformat[80] =
"";
5793 char *mime_type = (!strcasecmp(format,
"ogg")) ?
"application/" :
"audio/x-";
5796 snprintf(fname,
sizeof(fname),
"%s.%s", attach, format);
5799 c = strchr(altformat,
'|');
5804 snprintf(altfname,
sizeof(altfname),
"%s.%s", attach, altformat);
5818 res = snprintf(sox_gain_tmpdir,
sizeof(sox_gain_tmpdir),
"%s/vm-gain-XXXXXX", tmpdir);
5819 if (res >=
sizeof(sox_gain_tmpdir)) {
5820 ast_log(
LOG_ERROR,
"Failed to create temporary directory path %s: Out of buffer space\n", tmpdir);
5824 if (
mkdtemp(sox_gain_tmpdir)) {
5828 ast_debug(3,
"sox_gain_tmpdir: %s\n", sox_gain_tmpdir);
5831 dir_to_delete = sox_gain_tmpdir;
5833 res = snprintf(fname,
sizeof(fname),
"%s/output.%s", sox_gain_tmpdir, format);
5834 if (res >=
sizeof(fname)) {
5835 ast_log(
LOG_ERROR,
"Failed to create filename buffer for %s/output.%s: Too long\n", sox_gain_tmpdir, format);
5840 res = snprintf(sox_gain_cmd,
sizeof(sox_gain_cmd),
"sox -v %.4f %s.%s %s",
5841 vmu->
volgain, attach, format, fname);
5843 if (!strcasecmp(format,
"wav")) {
5845 res = snprintf(sox_gain_cmd,
sizeof(sox_gain_cmd),
"sox -v %.4f %s.%s -e signed-integer -b 16 %s",
5846 vmu->
volgain, attach, altformat, fname);
5848 res = snprintf(sox_gain_cmd,
sizeof(sox_gain_cmd),
"sox %s.%s -e signed-integer -b 16 %s",
5849 attach, altformat, fname);
5853 res = snprintf(sox_gain_cmd,
sizeof(sox_gain_cmd),
"sox -v %.4f %s.%s %s",
5854 vmu->
volgain, attach, altformat, fname);
5856 res = snprintf(sox_gain_cmd,
sizeof(sox_gain_cmd),
"sox %s.%s %s",
5857 attach, altformat, fname);
5862 if (res >=
sizeof(sox_gain_cmd)) {
5863 ast_log(
LOG_ERROR,
"Failed to generate sox command, out of buffer space\n");
5870 file_to_delete = fname;
5873 ast_log(
LOG_WARNING,
"Sox failed to re-encode %s: %s (have you installed support for all sox file formats?)\n",
5875 soxstatus == 1 ?
"Problem with command line options" :
"An error occurred during file processing");
5883 if (!file_to_delete) {
5884 res = snprintf(fname,
sizeof(fname),
"%s.%s", attach, format);
5885 if (res >=
sizeof(fname)) {
5886 ast_log(
LOG_ERROR,
"Failed to create filename buffer for %s.%s: Too long\n", attach, format);
5891 fprintf(p,
"--%s" ENDL, bound);
5893 fprintf(p,
"Content-Type: %s%s; name=\"%s\"" ENDL, mime_type, format, filename);
5895 fprintf(p,
"Content-Type: %s%s; name=\"%s.%s\"" ENDL, mime_type, format, greeting_attachment, format);
5896 fprintf(p,
"Content-Transfer-Encoding: base64" ENDL);
5897 fprintf(p,
"Content-Description: Voicemail sound attachment." ENDL);
5899 fprintf(p,
"Content-Disposition: attachment; filename=\"%s\"" ENDL ENDL, filename);
5901 fprintf(p,
"Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, format);
5906 if (file_to_delete) {
5907 unlink(file_to_delete);
5910 if (dir_to_delete) {
5911 rmdir(dir_to_delete);
5922 const char *fromfolder,
5929 int attach_user_voicemail,
5931 const char *category,
5936 char tmp[80] =
"/tmp/astmail-XXXXXX";
5950 if (!strcmp(format,
"wav49"))
5959 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);
5961 snprintf(tmp2,
sizeof(tmp2),
"( %s < %s ; rm -f %s ) &",
mailcmd, tmp, tmp);
5968static 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)
5970 char enc_cidnum[256], enc_cidname[256];
5975 char tmp[80] =
"/tmp/astmail-XXXXXX";
5981 if (!str1 || !str2) {
6000 gethostname(host,
sizeof(host)-1);
6001 if (strchr(srcemail,
'@')) {
6004 snprintf(who,
sizeof(who),
"%s@%s", srcemail, host);
6006 snprintf(dur,
sizeof(dur),
"%d:%02d", duration / 60, duration % 60);
6008 fprintf(p,
"Date: %s\n", date);
6017 prep_email_sub_vars(ast, vmu, msgnum + 1,
context,
mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category,
flag);
6039 fprintf(p,
"From: Asterisk PBX <%s>" ENDL, who);
6061 prep_email_sub_vars(ast, vmu, msgnum + 1,
context,
mailbox, fromfolder, cidnum, cidname, dur, date, category,
flag);
6084 fprintf(p,
"Subject: New VM" ENDL);
6086 fprintf(p,
"Subject: New %s VM" ENDL,
flag);
6096 prep_email_sub_vars(ast, vmu, msgnum + 1,
context,
mailbox, fromfolder, cidnum, cidname, dur, date, category,
flag);
6104 fprintf(p,
"New %s long %s msg in box %s\n"
6105 "from %s, on %s", dur,
flag,
mailbox, (cidname ? cidname : (cidnum ? cidnum :
"unknown")), date);
6109 snprintf(tmp2,
sizeof(tmp2),
"( %s < %s ; rm -f %s ) &",
mailcmd, tmp, tmp);
6176#define COUNT_MSGS_SQL_FMT "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'"
6177static int count_messages_in_folder(
struct odbc_obj *odbc,
const char *
context,
const char *
mailbox,
const char *folder,
int *messages)
6180 char sql[
sizeof(COUNT_MSGS_SQL_FMT) + odbc_table_len + strlen(
VM_SPOOL_DIR)
6183 SQLHSTMT stmt =
NULL;
6184 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
6195 res = SQLFetch(stmt);
6196 if (!SQL_SUCCEEDED(res)) {
6197 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
6200 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata,
sizeof(rowdata),
NULL);
6201 if (!SQL_SUCCEEDED(res)) {
6202 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
6206 *messages = atoi(rowdata);
6207 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
6211#undef COUNT_MSGS_SQL_FMT
6213static int inboxcount2(
const char *
mailbox,
int *urgentmsgs,
int *newmsgs,
int *oldmsgs)
6236 char *
next, *remaining = tmp;
6251 SCOPE_EXIT_RTN_VALUE(0,
"Urgent: %d New: %d Old: %d\n", urgentmsgs ? *urgentmsgs : 0, newmsgs ? *newmsgs : 0, oldmsgs ? *oldmsgs : 0);
6266 if (count_messages_in_folder(obj,
context, tmp,
"INBOX", newmsgs)
6267 || count_messages_in_folder(obj,
context, tmp,
"Old", oldmsgs)
6268 || count_messages_in_folder(obj,
context, tmp,
"Urgent", urgentmsgs)) {
6274 SCOPE_EXIT_RTN_VALUE(0,
"Urgent: %d New: %d Old: %d\n", urgentmsgs ? *urgentmsgs : 0, newmsgs ? *newmsgs : 0, oldmsgs ? *oldmsgs : 0);
6285#define MSGCOUNT_SQL_FMT_INBOX "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/INBOX' OR dir = '%s%s/%s/Urgent'"
6286#define MSGCOUNT_SQL_FMT "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'"
6287static int messagecount(
const char *mailbox_id,
const char *folder)
6294 SQLHSTMT stmt =
NULL;
6296 struct generic_prepare_struct gps = { .argc = 0 };
6297 SCOPE_ENTER(3,
"mb: %s folder: %s", mailbox_id, folder);
6314 if (!strcmp(folder,
"INBOX")) {
6329 res = SQLFetch(stmt);
6330 if (!SQL_SUCCEEDED(res)) {
6332 goto bail_with_handle;
6334 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata,
sizeof(rowdata),
NULL);
6335 if (!SQL_SUCCEEDED(res)) {
6337 goto bail_with_handle;
6339 nummsgs = atoi(rowdata);
6342 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
6349#undef MSGCOUNT_SQL_FMT
6350#undef MSGCOUNT_SQL_FMT_INBOX
6392 long duration,
struct ast_vm_user *recip,
char *fmt,
char *dir,
const char *
flag,
6393 const char *dest_folder)
6396 const char *frombox =
mbox(vmu, imbox);
6397 const char *userfolder;
6400 SCOPE_ENTER(3,
"mb: %s imb: %d msgnum: %d recip: %s dir: %s dest_folder: %s",
6406 userfolder =
"Urgent";
6408 userfolder = dest_folder;
6410 userfolder =
"INBOX";
6421 ast_trace(-1,
"fromdir: %s\n", fromdir);
6423 make_file(frompath,
sizeof(frompath), fromdir, msgnum);
6424 ast_trace(-1,
"frompath: %s\n", frompath);
6434 ast_trace(-1,
"recip msgnum: %d\n", recipmsgnum);
6439 make_file(topath,
sizeof(topath), todir, recipmsgnum);
6447 SCOPE_CALL(-1,
STORE, todir, recip->
mailbox, recip->
context, recipmsgnum, chan, recip, fmt, duration,
NULL,
NULL,
NULL);
6467#if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
6515 snprintf(fn,
sizeof(fn),
"%s%s/%s/%s",
VM_SPOOL_DIR,
c, m, folder);
6517 if (!(dir = opendir(fn)))
6520 while ((de = readdir(dir))) {
6521 if (!strncasecmp(de->d_name,
"msg", 3)) {
6525 }
else if (!strncasecmp(de->d_name + 8,
"txt", 3)) {
6547 char tmp[256], *tmp2 = tmp, *box, *
context;
6552 while ((box =
strsep(&tmp2,
",&"))) {
6553 if ((
context = strchr(box,
'@')))
6596 int tmpnew, tmpold, tmpurgent;
6601 while ((cur =
strsep(&mb,
", "))) {
6613 *urgentmsgs += tmpurgent;
6623 if ((
context = strchr(tmp,
'@'))) {
6650 *newmsgs += urgentmsgs;
6657 char arguments[255];
6658 char ext_context[256] =
"";
6659 int newvoicemails = 0, oldvoicemails = 0, urgentvoicemails = 0;
6675 if (!strncmp(mwi_msg->
cause,
"INV", 3))
6677 else if (!strncmp(mwi_msg->
cause,
"BLK", 3))
6687 if (
inboxcount2(ext_context, &urgentvoicemails, &newvoicemails, &oldvoicemails)) {
6690 snprintf(arguments,
sizeof(arguments),
"%s %s %s %d %d %d &",
6693 oldvoicemails, urgentvoicemails);
6694 ast_debug(1,
"Executing %s\n", arguments);
6719 snprintf(dst,
MSG_ID_LEN,
"%ld-%08x", (
long) time(
NULL), unique_counter);
6753 char ext_context[256] =
"";
6769 const char *category =
NULL;
6778 memset(&svm, 0,
sizeof(svm));
6790 duration = (int) (framelength / sample_rate);
6799 if (duration < recipient->minsecs) {
6800 ast_log(
LOG_NOTICE,
"Copying recording to voicemail %s@%s skipped because duration was shorter than "
6801 "minmessage of recipient\n", recdata->
mailbox, recdata->
context);
6811 snprintf(tmptxtfile,
sizeof(tmptxtfile),
"%s/XXXXXX", tmpdir);
6812 txtdes = mkstemp(tmptxtfile);
6822 txt = fdopen(txtdes,
"w+");
6828 "; Message Information file\n"
6851 date, (
long) time(
NULL),
6876 snprintf(ext_context,
sizeof(ext_context),
"%s@%s", recipient->
mailbox, recipient->
context);
6880 res =
inboxcount(ext_context, &newmsgs, &oldmsgs);
6887 if (!(vms = get_vm_state_by_mailbox(recipient->
mailbox, recipient->
context, 0))) {
6892 if (!(vms = create_vm_state_from_user(recipient))) {
6902 msgnum = newmsgs + oldmsgs;
6903 ast_debug(3,
"Messagecount set to %d\n", msgnum);
6904 snprintf(destination,
sizeof(destination),
"%simap/msg%s%04d",
VM_SPOOL_DIR, recipient->
mailbox, msgnum);
6908 if ((res = imap_check_limits(
NULL, vms, recipient, msgnum))) {
6919 ast_debug(3,
"mailbox = %d : inprocess = %d\n",
COUNT(recipient, dir),
6935 ast_log(
LOG_ERROR,
"Couldn't lock directory %s. Voicemail will be lost.\n", dir);
6943 make_file(destination,
sizeof(destination), dir, msgnum);
6945 make_file(tmpaudiofile,
sizeof(tmpaudiofile), tmpdir, msgnum);
6948 ast_log(
LOG_ERROR,
"Audio file failed to copy to tmp dir. Probably low disk space.\n");
6959 ast_log(
LOG_ERROR,
"Audio file failed to move to destination directory. Permissions/Overlap?\n");
6967 snprintf(desttxtfile,
sizeof(desttxtfile),
"%s.txt", destination);
6968 rename(tmptxtfile, desttxtfile);
6985 char cidnum[80], cidname[80];
6991 "origmailbox", recdata->
mailbox,
6998 "origtime", time(
NULL),
6999 "category",
S_OR(category,
""),
7000 "filename", tmptxtfile,
7001 "duration", duration,
7005 STORE(dir, recipient->
mailbox, recipient->
context, msgnum,
NULL, recipient, fmt, 0, vms,
"", msg_id);
7047 int newmsgs, oldmsgs;
7059 int sound_duration = 0;
7061 int greeting_only = 0;
7070 char ext_context[256] =
"";
7073 char ecodes[17] =
"#";
7078 const char *category =
NULL;
7080 const char *alldtmf =
"0123456789ABCD*#";
7092 tmpptr = strchr(
context,
'&');
7094 tmpptr = strchr(
ext,
'&');
7115 memset(&svm, 0,
sizeof(svm));
7130 if (strcmp(vmu->
context,
"default"))
7131 snprintf(ext_context,
sizeof(ext_context),
"%s@%s",
ext, vmu->
context);
7145 ast_trace(-1,
"prefile: %s\n", prefile);
7151 ast_trace(-1,
"tempfile: %s\n", tempfile);
7161 ast_trace(-1,
"new prefile: %s\n", prefile);
7181 strncat(ecodes,
"0",
sizeof(ecodes) - strlen(ecodes) - 1);
7186 strncat(ecodes,
"0",
sizeof(ecodes) - strlen(ecodes) - 1);
7194 strncat(ecodes,
"*",
sizeof(ecodes) - strlen(ecodes) - 1);
7198 strncat(ecodes,
"*",
sizeof(ecodes) - strlen(ecodes) - 1);
7202 for (code = alldtmf; *code; code++) {
7205 if (strchr(ecodes, e[0]) ==
NULL
7209 strncat(ecodes, e,
sizeof(ecodes) - strlen(ecodes) - 1);
7216#if defined(ODBC_STORAGE)
7218#elif defined(IMAP_STORAGE)
7232 if (success == -1) {
7234 ast_trace(-1,
"Greeting '%s' not retrieved from database, but found in file storage. Inserting into database\n", prefile);
7239 ast_trace(-1,
"%s doesn't exist, doing what we can\n", prefile);
7306 if (greeting_only) {
7307 ast_debug(3,
"Greetings only VM (maxmsg=0), Skipping voicemail recording\n");
7331 res =
inboxcount(ext_context, &newmsgs, &oldmsgs);
7338 if (!(vms = get_vm_state_by_mailbox(
ext,
context, 0))) {
7343 if (!(vms = create_vm_state_from_user(vmu))) {
7353 msgnum = newmsgs + oldmsgs;
7354 ast_debug(3,
"Messagecount set to %d\n", msgnum);
7359 if ((res = imap_check_limits(chan, vms, vmu, msgnum))) {
7374 snprintf(tmptxtfile,
sizeof(tmptxtfile),
"%s/XXXXXX", tmpdir);
7375 ast_trace(-1,
"Tempfile: %s\n", tmptxtfile);
7376 txtdes = mkstemp(tmptxtfile);
7400 snprintf(origtime,
sizeof(origtime),
"%ld", (
long) time(
NULL));
7412 "callerid", callerid,
7414 "origtime", origtime,
7415 "category",
S_OR(category,
""),
7416 "filename", tmptxtfile,
7421 txt = fdopen(txtdes,
"w+");
7431 "; Message Information file\n"
7453 date, (
long) time(
NULL),
7454 category ? category :
"",
7456 ast_trace(-1,
"Saving txt file mbox: %s msg_id: %s\n",
ext, msg_id);
7467 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);
7473 if (!strcmp(
flag,
"Urgent")) {
7478 fprintf(txt,
"flag=%s\n",
flag);
7479 if (sound_duration < vmu->
minsecs) {
7481 ast_verb(3,
"Recording was %d seconds long but needs to be at least %d - abandoning\n", sound_duration, vmu->
minsecs);
7489 fprintf(txt,
"duration=%d\n", duration);
7498 ast_debug(1,
"The recorded media file is gone, so we should remove the .txt file too!\n");
7518 snprintf(txtfile,
sizeof(txtfile),
"%s.txt", fn);
7520 ast_trace(-1,
"Renaming recordings '%s' -> fn '%s'\n", tmptxtfile, fn);
7524 ast_trace(-1,
"Renaming txt file '%s' -> fn '%s'\n", tmptxtfile, txtfile);
7525 rename(tmptxtfile, txtfile);
7535 snprintf(tmpdur,
sizeof(tmpdur),
"%d", duration);
7542 SCOPE_CALL(-1,
STORE, dir, vmu->
mailbox, vmu->
context, msgnum, chan, vmu, fmt, duration, vms,
flag, msg_id);
7550 exten =
strsep(&tmpptr,
"&");
7551 cntx = strchr(exten,
'@');
7556 memset(&recipu, 0,
sizeof(recipu));
7557 if ((recip =
find_user(&recipu, cntx, exten))) {
7589 }
else if (res > 0 && res !=
't')
7592 if (sound_duration < vmu->
minsecs)
7604 ast_debug(3,
"*** Checking if we can expunge, expungeonhangup set to %d\n", expungeonhangup);
7605 if (expungeonhangup == 1 && vms->mailstream !=
NULL) {
7607#ifdef HAVE_IMAP_TK2006
7608 if (LEVELUIDPLUS (vms->mailstream)) {
7609 mail_expunge_full(vms->mailstream, NIL, EX_UID);
7612 mail_expunge(vms->mailstream);
7621#if !defined(IMAP_STORAGE)
7634 for (x = 0, dest = 0; dest != stopcount && x <
MAXMSGLIMIT; x++) {
7670 snprintf(sequence,
sizeof(sequence),
"%ld", vms->msgArray[msg]);
7672 ast_debug(3,
"Copying sequence %s to mailbox %s\n", sequence,
mbox(vmu, box));
7676 mail_setflag(vms->mailstream, sequence,
"\\Seen");
7678 mail_clearflag(vms->mailstream, sequence,
"\\Seen");
7690 if (vms->mailstream && !mail_status(vms->mailstream,
mailbox, SA_UIDNEXT)) {
7691 if (mail_create(vms->mailstream,
mailbox) != NIL) {
7697 if (init_mailstream(vms, curr_mbox) || !vms->mailstream) {
7702 res = !mail_move(vms->mailstream, sequence, (
char *)
mbox(vmu, box));
7704 res = !mail_copy(vms->mailstream, sequence, (
char *)
mbox(vmu, box));
7716 const char *dbox =
mbox(vmu, box);
7718 SCOPE_ENTER(3,
"dir: %s msg: %d box: %d dbox: %s move? %d \n", dir, msg, box, dbox, move);
7730 ast_trace(-1,
"Deleting message %d\n", msg);
7732 for (i = 1; i <= x; i++) {
7735 make_file(dfn,
sizeof(dfn), ddir, i - 1);
7749 if (strcmp(sfn, dfn)) {
7750 ast_trace(-1,
"Copying message '%s' to '%s'\n", sfn, dfn);
7772 unsigned char buf[256];
7804 bytes += ast_adsi_logo(
buf);
7848 for (x = 0; x < 5; x++) {
7849 snprintf(num,
sizeof(num),
"%d", x);
7877 ast_debug(1,
"Done downloading scripts...\n");
7885 ast_debug(1,
"Restarting session...\n");
7921 unsigned char buf[256];
7923 unsigned char keys[8];
7928 for (x = 0; x < 8; x++)
7947 unsigned char buf[256];
7949 unsigned char keys[8];
7954 for (x = 0; x < 8; x++)
7969 unsigned char buf[256];
7971 unsigned char keys[8];
7977 for (x = 0; x < 5; x++) {
7999 unsigned char buf[256];
8006 char datetime[21] =
"";
8009 unsigned char keys[8];
8017 snprintf(fn2,
sizeof(fn2),
"%s.txt", vms->
fn);
8018 f = fopen(fn2,
"r");
8021 if (!fgets((
char *)
buf,
sizeof(
buf), f)) {
8025 char *stringp =
NULL;
8026 stringp = (
char *)
buf;
8030 if (!strcmp((
char *)
buf,
"callerid"))
8032 if (!strcmp((
char *)
buf,
"origdate"))
8040 for (x = 0; x < 5; x++)
8067 name =
"Unknown Caller";
8084 strcasecmp(vms->
curbox,
"INBOX") ?
" Messages" :
"");
8101 unsigned char buf[256];
8102 unsigned char keys[8];
8110 for (x = 0; x < 5; x++)
8152 unsigned char buf[256] =
"";
8153 char buf1[256] =
"",
buf2[256] =
"";
8155 unsigned char keys[8];
8158 char *newm = (vms->
newmessages == 1) ?
"message" :
"messages";
8159 char *oldm = (vms->
oldmessages == 1) ?
"message" :
"messages";
8165 strncat(
buf1,
" and",
sizeof(
buf1) - strlen(
buf1) - 1);
8168 snprintf(
buf2,
sizeof(
buf2),
"%s.", newm);
8172 snprintf(
buf2,
sizeof(
buf2),
"%s.", oldm);
8174 strcpy(
buf1,
"You have no messages.");
8182 for (x = 0; x < 6; x++)
8199 unsigned char buf[256] =
"";
8200 char buf1[256] =
"",
buf2[256] =
"";
8202 unsigned char keys[8];
8205 char *mess = (vms->
lastmsg == 0) ?
"message" :
"messages";
8211 for (x = 0; x < 6; x++)
8221 strcasecmp(vms->
curbox,
"INBOX") ?
" folder" :
"");
8226 strcpy(
buf2,
"no messages.");
8255 unsigned char buf[256];
8281 for (x = start; x < 5; x++) {
8287 snprintf(fn,
sizeof(fn),
"vm-%s",
mbox(
NULL, x));
8296 ast_verb(4,
"Failed to find file %s; falling back to INBOX\n", fn);
8324 for (x = start; x < 5; x++) {
8328 snprintf(fn,
sizeof(fn),
"vm-%s",
mbox(
NULL, x));
8364 while (((res <
'0') || (res >
'9')) &&
8365 (res !=
'#') && (res >= 0) &&
8380 isprint(res) ? res :
'?', isprint(res) ? res :
'?');
8403 int curmsg,
char *vm_fmts,
char *
context,
signed char record_gain,
long *duration,
8407 int retries = 0, prepend_duration = 0, already_recorded = 0;
8413 signed char zero_gain = 0;
8415 const char *msg_id =
NULL;
8417 const char *duration_str;
8421 make_file(msgfile,
sizeof(msgfile), curdir, curmsg);
8422 ast_trace(-1,
"msgfile: %s\n", msgfile);
8423 strcpy(textfile, msgfile);
8424 strcpy(backup, msgfile);
8425 strcpy(backup_textfile, msgfile);
8426 strncat(textfile,
".txt",
sizeof(textfile) - strlen(textfile) - 1);
8427 strncat(backup,
"-bak",
sizeof(backup) - strlen(backup) - 1);
8428 strncat(backup_textfile,
"-bak.txt",
sizeof(backup_textfile) - strlen(backup_textfile) - 1);
8431 *duration = atoi(duration_str);
8436 while ((cmd >= 0) && (cmd !=
't') && (cmd !=
'*')) {
8447 make_file(vms->introfn,
sizeof(vms->introfn), curdir, curmsg);
8448 strncat(vms->introfn,
"intro",
sizeof(vms->introfn));
8451 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);
8459 ast_trace(-1,
"Prepending to message %d\n", curmsg);
8461 make_file(msgfile,
sizeof(msgfile), curdir, curmsg);
8462 ast_trace(-1,
"msgfile: %s\n", msgfile);
8464 strcpy(textfile, msgfile);
8465 strncat(textfile,
".txt",
sizeof(textfile) - 1);
8476 if (already_recorded) {
8477 ast_trace(-1,
"Restoring '%s' to '%s'\n", backup, msgfile);
8479 copy(backup_textfile, textfile);
8482 ast_trace(-1,
"Backing up '%s' to '%s'\n", backup, msgfile);
8484 copy(textfile, backup_textfile);
8487 already_recorded = 1;
8492 cmd =
SCOPE_CALL_WITH_INT_RESULT(-1,
ast_play_and_prepend, chan,
NULL, msgfile, 0, vm_fmts, &prepend_duration,
NULL, 1,
silencethreshold,
maxsilence);
8505 *duration = atoi(duration_str);
8507 if (prepend_duration) {
8510 char duration_buf[12];
8512 *duration += prepend_duration;
8513 ast_trace(-1,
"Prepending duration: %d total duration: %ld\n", prepend_duration, *duration);
8515 snprintf(duration_buf,
sizeof(duration_buf),
"%ld", *duration);
8526 *vms->introfn =
'\0';
8535 already_recorded = 0;
8553 isprint(cmd) ? cmd :
'?', isprint(cmd) ? cmd :
'?');
8559 if (prepend_duration)
8560 *duration = prepend_duration;
8562 if (already_recorded && cmd == -1) {
8564 ast_trace(-1,
"Restoring '%s' to '%s'\n", backup, msgfile);
8566 rename(backup_textfile, textfile);
8569 if (cmd ==
't' || cmd ==
'S') {
8575static void queue_mwi_event(
const char *channel_id,
const char *box,
int urgent,
int new,
int old)
8584 ast_debug(3,
"Queueing event for mailbox %s New: %d Old: %d\n", box,
new + urgent, old);
8597 ast_debug(3,
"Found alias mapping: %s -> %s\n", mapping->
alias, box);
8623 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;
8624 const char *category;
8636 snprintf(todir,
sizeof(todir),
"%simap",
VM_SPOOL_DIR);
8638 make_file(fn,
sizeof(fn), todir, msgnum);
8639 snprintf(ext_context,
sizeof(ext_context),
"%s@%s", vmu->
mailbox, vmu->
context);
8658 char *msg_id =
NULL;
8664 snprintf(filename,
sizeof(filename),
"%s.txt", fn);
8672 if (attach_user_voicemail)
8676 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);
8678 if (attach_user_voicemail)
8683 sendpage(myserveremail, vmu->
pager, msgnum, vmu->
context, vmu->
mailbox,
mbox(vmu, 0), cidnum, cidname, duration, vmu, category,
flag);
8687 DELETE(todir, msgnum, fn, vmu);
8742 char ecodes[16] =
"#";
8743 int res = 0, cmd = 0;
8748 const char mailbox_context[256];
8749 int saved_messages = 0;
8750 int valid_extensions = 0;
8753 char urgent_str[7] =
"";
8754 int prompt_played = 0;
8762 ast_copy_string(urgent_str, urgent ?
"Urgent" :
"",
sizeof(urgent_str));
8772 while (!res && !valid_extensions) {
8773 int use_directory = 0;
8778 while ((cmd >= 0) && !
done ){
8808 isprint(cmd) ? cmd :
'?', isprint(cmd) ? cmd :
'?');
8811 if (cmd < 0 || cmd ==
't')
8815 if (use_directory) {
8818 struct ast_app* directory_app;
8821 if (directory_app) {
8822 char vmcontext[256];
8832 snprintf(vmcontext,
sizeof(vmcontext),
"%s,,v",
context ?
context :
"default");
8833 res =
pbx_exec(chan, directory_app, vmcontext);
8849 if (res || prompt_played > 4)
8851 if ((res =
ast_readstring(chan, username,
sizeof(username) - 1, 2000, 10000,
"#")) < 0)
8859 s =
strsep(&stringp,
"*");
8861 valid_extensions = 1;
8863 snprintf((
char*)mailbox_context,
sizeof(mailbox_context),
"%s@%s", s,
context ?
context :
"default");
8869 if (
inboxcount(mailbox_context, &newmsgs, &oldmsgs)) {
8870 ast_log(
LOG_ERROR,
"Problem in calculating number of voicemail messages available for extension %s\n", mailbox_context);
8873 valid_extensions = 0;
8877 if (!(dstvms = get_vm_state_by_mailbox(s,
context, 0))) {
8878 if (!(dstvms = create_vm_state_from_user(receiver))) {
8882 valid_extensions = 0;
8886 check_quota(dstvms, imapfolder);
8887 if (dstvms->quota_limit && dstvms->quota_usage >= dstvms->quota_limit) {
8888 ast_log(
LOG_NOTICE,
"Mailbox '%s' is exceeded quota %u >= %u\n", mailbox_context, dstvms->quota_usage, dstvms->quota_limit);
8890 valid_extensions = 0;
8899 if ((newmsgs + oldmsgs) >= capacity) {
8900 ast_log(
LOG_NOTICE,
"Mailbox '%s' is full with capacity of %d, prompting for another extension.\n", mailbox_context, capacity);
8902 valid_extensions = 0;
8923 valid_extensions = 0;
8941 s =
strsep(&stringp,
"*");
8944 if (valid_extensions)
8950 if (is_new_message == 1) {
8956 memset(&leave_options, 0,
sizeof(leave_options));
8964 int copy_msg_result = 0;
8968 const char *msg_id =
NULL;
8971 memcpy(&vmstmp, vms,
sizeof(vmstmp));
8975 make_file(filename,
sizeof(filename), dir, curmsg);
8976 strncat(filename,
".txt",
sizeof(filename) - strlen(filename) - 1);
8984 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);
8988 int attach_user_voicemail;
8992 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
8994 dstvms = create_vm_state_from_user(vmtmp);
8997 init_mailstream(dstvms, 0);
8998 if (!dstvms->mailstream) {
9001 copy_msg_result =
STORE(vmstmp.
curdir, vmtmp->mailbox, vmtmp->context, curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str, msg_id);
9008 myserveremail = vmtmp->serveremail;
9011 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox,
9015 vmstmp.
fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan,
9016 NULL, urgent_str, msg_id);
9018 copy_msg_result =
SCOPE_CALL_WITH_INT_RESULT(-1,
copy_message, chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str,
NULL);
9028 if (saved_messages > 0 && !copy_msg_result) {
9045 make_file(msgfile,
sizeof(msgfile), dir, curmsg);
9046 strcpy(textfile, msgfile);
9047 strcpy(backup, msgfile);
9048 strcpy(backup_textfile, msgfile);
9049 strncat(textfile,
".txt",
sizeof(textfile) - strlen(textfile) - 1);
9050 strncat(backup,
"-bak",
sizeof(backup) - strlen(backup) - 1);
9051 strncat(backup_textfile,
"-bak.txt",
sizeof(backup_textfile) - strlen(backup_textfile) - 1);
9054 rename(backup_textfile, textfile);
9061 make_file(msgfile,
sizeof(msgfile), dir, curmsg);
9062 strcpy(textfile, msgfile);
9063 strcpy(backup_textfile, msgfile);
9064 strncat(textfile,
".txt",
sizeof(textfile) - strlen(textfile) - 1);
9065 strncat(backup_textfile,
"-bak.txt",
sizeof(backup_textfile) - strlen(backup_textfile) - 1);
9066 rename(backup_textfile, textfile);
9141 if (time_now.tm_year == time_then.tm_year)
9142 snprintf(temp,
sizeof(temp),
"%d", time_now.tm_yday);
9144 snprintf(temp,
sizeof(temp),
"%d", (time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
9190 char *callerid, *
name;
9204 ast_debug(1,
"VM-CID: composite caller ID received: %s, context: %s\n", cid,
context);
9221 ast_verb(3,
"Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
9226 ast_verb(3,
"Playing envelope info: message from '%s'\n", callerid);
9229 res =
wait_file2(chan, vms,
"vm-from-extension");
9235 ast_debug(1,
"VM-CID: Numeric caller id: (%s)\n", callerid);
9241 ast_verb(3,
"Playing recorded name for CID number '%s' - '%s'\n", callerid,prefile);
9244 ast_verb(3,
"Played recorded name result '%d'\n", res);
9247 wait_file2(chan, vms,
"vm-from-phonenumber");
9256 ast_debug(1,
"VM-CID: From an unknown number\n");
9258 res =
wait_file2(chan, vms,
"vm-unknown-caller");
9269 if (duration ==
NULL)
9273 durations = atoi(duration);
9274 durationm = (durations / 60);
9276 ast_debug(1,
"VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
9278 if ((!res) && (durationm >= minduration)) {
9283 div_t num = div(durationm, 10);
9285 if (durationm == 1) {
9288 }
else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
9317 const char *origtime, *
context, *category, *duration, *
flag;
9332 snprintf(filename,
sizeof(filename),
"%s.txt", vms->
fn);
9353 ten = (vms->
curmsg + 1) / 10;
9354 one = (vms->
curmsg + 1) % 10;
9357 snprintf(nextmsg,
sizeof(nextmsg),
"digits/n-%d", vms->
curmsg + 1);
9360 snprintf(nextmsg,
sizeof(nextmsg),
"digits/n-%d", ten * 10);
9364 snprintf(nextmsg,
sizeof(nextmsg),
"digits/n-%d", one);
9406 res =
wait_file2(chan, vms,
"vm-meddelandet");
9473 isprint(res) ? res :
'?', isprint(res) ? res :
'?');
9480static int imap_remove_file(
char *dir,
int msgnum)
9488 snprintf(
intro,
sizeof(
intro),
"%sintro", fn);
9492 if ((msgnum < 0 && imapgreetings) || msgnum > -1) {
9497 snprintf(full_fn,
sizeof(full_fn),
"%s.txt", fn);
9505static int imap_delete_old_greeting (
char *dir,
struct vm_state *vms)
9507 char *
file, *filename;
9517 ast_log(
AST_LOG_ERROR,
"Failed to procure file name from directory passed. You should never see this.\n");
9532 for (i = 0; i < vms->mailstream->nmsgs; i++) {
9533 mail_fetchstructure(vms->mailstream, i + 1, &body);
9535 if (body->nested.part->next && body->nested.part->next->body.parameter->value) {
9536 char *attachment = body->nested.part->next->body.parameter->value;
9537 char copy[strlen(attachment) + 1];
9539 strcpy(
copy, attachment);
9542 filename =
strsep(&attachment,
".");
9543 if (!strcmp(filename,
file)) {
9544 snprintf(arg,
sizeof(arg),
"%d", i + 1);
9545 mail_setflag(vms->mailstream, arg,
"\\DELETED");
9553 mail_expunge(vms->mailstream);
9555 if (curr_mbox != -1) {
9557 if (init_mailstream(vms, curr_mbox) || !vms->mailstream) {
9566#elif !defined(IMAP_STORAGE)
9569 int count_msg, last_msg;
9570 SCOPE_ENTER(3,
"user: %s dir: %s msg: %d box %d\n",
9585 if (count_msg < 0) {
9610 if (last_msg < -1) {
9612 }
else if (vms->
lastmsg != last_msg) {
9613 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);
9624 int last_msg_idx = 0;
9627 int res = 0, nummsg;
9634 ast_trace(-1,
"No messages in mailbox\n");
9647 if (last_msg_idx != vms->
lastmsg) {
9652 for (x = 0; x < last_msg_idx + 1; x++) {
9661 if (strcmp(vms->
fn, fn2)) {
9678 ast_trace(-1,
"Unable to lock path. Not moving message to deleted folder.\n");
9697 for (x = vms->
curmsg + 1; x <= nummsg; x++) {
9711 for (x = last_msg_idx - 1; x >= 0; x--) {
9752 if (!strcasecmp(box,
"vm-INBOX") || !strcasecmp(box,
"vm-Old")){
9765 if (!strcasecmp(box,
"vm-INBOX") || !strcasecmp(box,
"vm-Old")) {
9778 if (!strcasecmp(box,
"vm-INBOX") || !strcasecmp(box,
"vm-Old")) {
9779 if (!strcasecmp(box,
"vm-INBOX"))
9794 if (!strcasecmp(box,
"vm-Family") || !strcasecmp(box,
"vm-Friends") || !strcasecmp(box,
"vm-Work")){
10153 snprintf(recname,
sizeof(recname),
"digits/1kvk");
10155 snprintf(recname,
sizeof(recname),
"digits/%dhk", vms->
urgentmessages);
10168 snprintf(recname,
sizeof(recname),
"digits/1kvk");
10170 snprintf(recname,
sizeof(recname),
"digits/%dhk", vms->
newmessages);
10185 snprintf(recname,
sizeof(recname),
"digits/1kvk");
10187 snprintf(recname,
sizeof(recname),
"digits/%dhk", vms->
oldmessages);
10263 }
else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
10264 if (num.rem == 2) {
10290 }
else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
10291 if (num.rem == 2) {
10901 static int deprecation_warning = 0;
10902 if (deprecation_warning++ % 10 == 0) {
10903 ast_log(
LOG_WARNING,
"cz is not a standard language code. Please switch to using cs instead.\n");
10971 if (skipadvanced) {
10986 if (!res && !skipadvanced)
11001 int curmsg_deleted;
11010 if (!curmsg_deleted) {
11060 if (skipadvanced) {
11081 if (!res && !skipadvanced)
11096 int curmsg_deleted;
11104 if (!curmsg_deleted) {
11175 char newpassword[80] =
"";
11176 char newpassword2[80] =
"";
11178 unsigned char buf[256];
11195 cmd =
play_record_review(chan,
"vm-rec-name", prefile,
maxgreet, fmtc, 0, vmu, &duration,
NULL,
NULL, record_gain, vms,
NULL,
NULL, 0);
11196 if (cmd < 0 || cmd ==
't' || cmd ==
'#')
11205 cmd =
play_record_review(chan,
"vm-rec-unv", prefile,
maxgreet, fmtc, 0, vmu, &duration,
NULL,
NULL, record_gain, vms,
NULL,
NULL, 0);
11206 if (cmd < 0 || cmd ==
't' || cmd ==
'#')
11212 cmd =
play_record_review(chan,
"vm-rec-busy", prefile,
maxgreet, fmtc, 0, vmu, &duration,
NULL,
NULL, record_gain, vms,
NULL,
NULL, 0);
11213 if (cmd < 0 || cmd ==
't' || cmd ==
'#')
11223 newpassword[1] =
'\0';
11226 newpassword[0] =
'\0';
11227 if (cmd < 0 || cmd ==
't' || cmd ==
'#')
11229 cmd =
ast_readstring(chan, newpassword + strlen(newpassword),
sizeof(newpassword) - 1, 2000, 10000,
"#");
11230 if (cmd < 0 || cmd ==
't' || cmd ==
'#')
11237 newpassword2[1] =
'\0';
11240 newpassword2[0] =
'\0';
11241 if (cmd < 0 || cmd ==
't' || cmd ==
'#')
11243 cmd =
ast_readstring(chan, newpassword2 + strlen(newpassword2),
sizeof(newpassword2) - 1, 2000, 10000,
"#");
11244 if (cmd < 0 || cmd ==
't' || cmd ==
'#')
11246 if (!strcmp(newpassword, newpassword2))
11262 ast_debug(1,
"User %s set password to %s of length %d\n", vms->
username, newpassword, (
int) strlen(newpassword));
11273 char newpassword[80] =
"";
11274 char newpassword2[80] =
"";
11276 unsigned char buf[256];
11289 while ((cmd >= 0) && (cmd !=
't')) {
11295 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);
11299 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);
11303 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);
11313 newpassword[1] =
'\0';
11316 newpassword[0] =
'\0';
11320 if ((cmd =
ast_readstring(chan, newpassword + strlen(newpassword),
sizeof(newpassword) - 1, 2000, 10000,
"#")) < 0) {
11333 newpassword2[1] =
'\0';
11336 newpassword2[0] =
'\0';
11341 if ((cmd =
ast_readstring(chan, newpassword2 + strlen(newpassword2),
sizeof(newpassword2) - 1, 2000, 10000,
"#")) < 0) {
11345 if (strcmp(newpassword, newpassword2)) {
11361 ast_debug(1,
"User %s set password to %s of length %d\n",
11362 vms->
username, newpassword, (
int) strlen(newpassword));
11389 isprint(cmd) ? cmd :
'?', isprint(cmd) ? cmd :
'?');
11419 unsigned char buf[256];
11433 while ((cmd >= 0) && (cmd !=
't')) {
11438 cmd =
play_record_review(chan,
"vm-rec-temp", prefile,
maxgreet, fmtc, 0, vmu, &duration,
NULL,
NULL, record_gain, vms,
NULL,
NULL, 0);
11446 cmd =
play_record_review(chan,
"vm-rec-temp", prefile,
maxgreet, fmtc, 0, vmu, &duration,
NULL,
NULL, record_gain, vms,
NULL,
NULL, 0);
11449 DELETE(prefile, -1, prefile, vmu);
11459 "vm-tempgreeting2" :
"vm-tempgreeting");
11470 isprint(cmd) ? cmd :
'?', isprint(cmd) ? cmd :
'?');
11496 if (!strcasecmp(vms->
vmbox,
"vm-INBOX") ||!strcasecmp(vms->
vmbox,
"vm-Old")){
11498 snprintf(vms->
fn,
sizeof(vms->
fn),
"vm-%ss", vms->
curbox);
11507 snprintf(vms->
fn,
sizeof(vms->
fn),
"vm-%s", vms->
curbox);
11523 if (!strcasecmp(vms->
fn,
"INBOX")) {
11551 snprintf(vms->
fn,
sizeof(vms->
fn),
"vm-%s", vms->
curbox);
11579 snprintf(vms->
fn,
sizeof(vms->
fn),
"vm-%s", vms->
curbox);
11601 snprintf(vms->
fn,
sizeof(vms->
fn),
"vm-%s", vms->
curbox);
11632 snprintf(vms->
fn,
sizeof(vms->
fn),
"vm-%s", vms->
curbox);
11656 snprintf(vms->
fn,
sizeof(vms->
fn),
"vm-%s", vms->
curbox);
11686 snprintf(vms->
fn,
sizeof(vms->
fn),
"vm-%s", vms->
curbox);
11710 snprintf(vms->
fn,
sizeof(vms->
fn),
"vm-%s", vms->
curbox);
11753 int skipuser,
int max_logins,
int silent)
11755 int useadsi = 0, valid = 0, logretries = 0;
11761 if (!skipuser && useadsi)
11770 while (!valid && (logretries < max_logins)) {
11780 ast_verb(3,
"Username not entered\n");
11783 }
else if (
mailbox[0] ==
'*') {
11785 ast_verb(4,
"Mailbox begins with '*', attempting jump to extension 'a'\n");
11790 ast_verb(4,
"Jump to extension 'a' failed; setting mailbox to NULL\n");
11798 char fullusername[80];
11801 strncat(fullusername,
mailbox,
sizeof(fullusername) - 1 - strlen(fullusername));
11806 memset(&vmus, 0,
sizeof(vmus));
11825 ast_verb(4,
"Password begins with '*', attempting jump to extension 'a'\n");
11832 ast_verb(4,
"Jump to extension 'a' failed; setting mailbox and user to NULL\n");
11842 if (passptr[0] ==
'-') passptr++;
11844 if (vmu && !strcmp(passptr,
password))
11853 if (skipuser || logretries >= max_logins) {
11874 if (!valid && (logretries >= max_logins)) {
11880 if (vmu && !skipuser) {
11889 const char *msg_id)
11938 memset(&vmus, 0,
sizeof(vmus));
11939 memset(&vms, 0,
sizeof(vms));
11942 goto play_msg_cleanup;
11954 goto play_msg_cleanup;
11966 goto play_msg_cleanup;
11982 vmstate_delete(&vms);
12032#define VMBOX_STRING_HEADER_FORMAT "%-32.32s %-32.32s %-16.16s %-16.16s %-16.16s %-16.16s\n"
12033#define VMBOX_STRING_DATA_FORMAT "%-32.32s %-32.32s %-16.16s %-16.16s %-16.16s %-16.16s\n"
12039 memset(&vmus, 0,
sizeof(vmus));
12040 memset(&vms, 0,
sizeof(vms));
12055#define VM_STRING_HEADER_FORMAT "%-8.8s %-32.32s %-32.32s %-9.9s %-6.6s %-30.30s\n"
12064 if (!mailbox_snapshot) {
12071 for (i = 0; i < mailbox_snapshot->
folders; i++) {
12074 msg->flag,
msg->msg_id);
12097 const char *from_context =
a->argv[3];
12098 const char *from_folder =
a->argv[4];
12099 const char *
id[] = {
a->argv[5] };
12100 const char *to_mailbox =
a->argv[6];
12101 const char *to_context =
a->argv[7];
12102 const char *to_folder =
a->argv[8];
12105 ast_cli(
a->fd,
"Error forwarding message %s from mailbox %s@%s %s to mailbox %s@%s %s\n",
12106 id[0],
from_mailbox, from_context, from_folder, to_mailbox, to_context, to_folder);
12108 ast_cli(
a->fd,
"Forwarded message %s from mailbox %s@%s %s to mailbox %s@%s %s\n",
12109 id[0],
from_mailbox, from_context, from_folder, to_mailbox, to_context, to_folder);
12118 const char *from_folder =
a->argv[4];
12119 const char *
id[] = {
a->argv[5] };
12120 const char *to_folder =
a->argv[6];
12123 ast_cli(
a->fd,
"Error moving message %s from mailbox %s@%s %s to %s\n",
12126 ast_cli(
a->fd,
"Moved message %s from mailbox %s@%s %s to %s\n",
12136 const char *folder =
a->argv[4];
12137 const char *
id[] = {
a->argv[5] };
12140 ast_cli(
a->fd,
"Error removing message %s from mailbox %s@%s %s\n",
12143 ast_cli(
a->fd,
"Removed message %s from mailbox %s@%s %s\n",
12151 const char *
word =
a->word;
12162 wordlen = strlen(
word);
12165 if (!strncasecmp(
word, vmu->
mailbox , wordlen)) {
12175 }
else if (pos == 4) {
12177 const char *box =
a->argv[3];
12178 wordlen = strlen(
word);
12200 e->
command =
"voicemail show mailbox";
12202 "Usage: voicemail show mailbox <mailbox> <context>\n"
12203 " Show contents of mailbox <mailbox>@<context>\n";
12211 if (
a->argc != 5) {
12241 const char *
word =
a->word;
12247 const char *
context =
"", *
mailbox =
"", *folder =
"", *
id =
"";
12250 if (pos > maxpos) {
12256 if (pos == 2 || (pos == 6 && maxpos == 8)) {
12258 wordlen = strlen(
word);
12261 if (!strncasecmp(
word, vmu->
mailbox , wordlen)) {
12271 }
else if (pos == 3 || pos == 7) {
12273 mailbox = (pos == 3) ?
a->argv[2] :
a->argv[6];
12274 wordlen = strlen(
word);
12287 }
else if (pos == 4 || pos == 8 || (pos == 6 && maxpos == 6) ) {
12290 wordlen = strlen(
word);
12297 }
else if (pos == 5) {
12303 folder =
a->argv[4];
12304 wordlen = strlen(
word);
12316 if (
id && !strncasecmp(
word,
msg->msg_id, wordlen) && ++which >
state) {
12334 e->
command =
"voicemail forward";
12336 "Usage: voicemail forward <from_mailbox> <from_context> <from_folder> <messageid> <to_mailbox> <to_context> <to_folder>\n"
12337 " Forward message <messageid> in mailbox <mailbox>@<context> <from_folder>\n"
12338 " to mailbox <mailbox>@<context> <to_folder>\n";
12346 if (
a->argc != 9) {
12361 e->
command =
"voicemail move";
12363 "Usage: voicemail move <mailbox> <context> <from_folder> <messageid> <to_folder>\n"
12364 " Move message <messageid> in mailbox <mailbox>&<context> from <from_folder> to <to_folder>\n";
12372 if (
a->argc != 7) {
12387 e->
command =
"voicemail remove";
12389 "Usage: voicemail remove <mailbox> <context> <from_folder> <messageid>\n"
12390 " Remove message <messageid> from <from_folder> in mailbox <mailbox>@<context>\n";
12398 if (
a->argc != 6) {
12417 char prefixstr[80] =
"";
12418 char ext_context[256]=
"";
12425 int silentexit = 0;
12427 signed char record_gain = 0;
12429 int play_folder = 0;
12458 if (
args.argc == 2) {
12468 record_gain = (
signed char) gain;
12488 if (play_folder > 9 || play_folder < 0) {
12490 "Invalid value '%s' provided for folder autoplay option. Defaulting to 'INBOX'\n",
12500 while (*(
args.argv0)) {
12501 if (*(
args.argv0) ==
's')
12503 else if (*(
args.argv0) ==
'p')
12568 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
12569 pthread_setspecific(ts_vmstate.key, &vms);
12571 vms.interactive = 1;
12575 vmstate_insert(&vms);
12576 init_vm_state(&vms);
12582 ast_channel_language_set(chan, vmu->
language);
12587 ast_trace(-1,
"Before open_mailbox\n");
12590 ast_trace(-1,
"open mailbox: %d\n", res);
12598 ast_trace(-1,
"open mailbox: %d\n", res);
12607 ast_trace(-1,
"open mailbox: %d\n", res);
12624 ast_trace(-1,
"open mailbox: %d\n", res);
12662 if ((cmd ==
't') || (cmd ==
'#')) {
12668 }
else if (cmd < 0) {
12677 ast_debug(3,
"Checking quotas: comparing %u to %u\n", vms.quota_usage, vms.quota_limit);
12678 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
12679 ast_debug(1,
"*** QUOTA EXCEEDED!!\n");
12696 isprint(cmd) ? cmd :
'?', isprint(cmd) ? cmd :
'?');
12700 while ((cmd > -1) && (cmd !=
't') && (cmd !=
'#')) {
12702 ast_trace(-1,
"Main menu: %d %c\n", cmd, (cmd >= 32 && cmd <= 126 ? cmd :
' '));
12718 isprint(cmd) ? cmd :
'?', isprint(cmd) ? cmd :
'?');
12721 }
else if (cmd > 0) {
12725 ast_trace(-1,
"close mailbox: %d\n", res);
12729 if (cmd != 11) in_urgent = 0;
12732 ast_trace(-1,
"open mailbox: %d\n", res);
12752 while ((cmd > -1) && (cmd !=
't') && (cmd !=
'#')) {
12759 ast_trace(-1,
"advanced options: %d\n", cmd);
12769 ast_verb(3,
"Callback Requested\n");
12772 ast_trace(-1,
"advanced options: %d\n", cmd);
12790 ast_trace(-1,
"advanced options: %d\n", cmd);
12817 ast_trace(-1,
"forward message: %d\n", cmd);
12860 isprint(cmd) ? cmd :
'?', isprint(cmd) ? cmd :
'?');
12883 ast_trace(-1,
"close mailbox: %d\n", res);
12888 ast_trace(-1,
"open mailbox: %d\n", res);
12891 ast_debug(1,
"No more new messages, opened INBOX and got %d Urgent messages\n", vms.
lastmsg + 1);
12918 ast_trace(-1,
"close mailbox: %d\n", res);
12923 ast_trace(-1,
"open mailbox: %d\n", res);
12926 ast_debug(1,
"No more urgent messages, opened INBOX and got %d new messages\n", vms.
lastmsg + 1);
12945 if (play_folder == 0) {
12952 else if (play_folder == 1)
12956 if (play_folder == 0) {
12963 else if (play_folder == 1)
12979 if (in_urgent == 1) {
12984 ast_trace(-1,
"close mailbox: %d\n", res);
12989 ast_trace(-1,
"open mailbox: %d\n", res);
12992 ast_debug(1,
"No more urgent messages, opened INBOX and got %d new messages\n", vms.
lastmsg + 1);
13014 ast_trace(-1,
"forward message: %d\n", res);
13027 ast_trace(-1,
"close mailbox: %d\n", res);
13032 ast_trace(-1,
"open mailbox: %d\n", res);
13035 ast_debug(1,
"No more urgent messages, opened INBOX and got %d new messages\n", vms.
lastmsg + 1);
13056 isprint(cmd) ? cmd :
'?', isprint(cmd) ? cmd :
'?');
13061 }
else if (cmd > 0) {
13062 box = cmd = cmd -
'0';
13066 ast_trace(-1,
"save to folder: %d\n", res);
13068#ifndef IMAP_STORAGE
13080 snprintf(vms.
fn,
sizeof(vms.
fn),
"vm-%s",
mbox(vmu, box));
13109 ast_trace(-1,
"close mailbox: %d\n", res);
13114 ast_trace(-1,
"open mailbox: %d\n", res);
13117 ast_debug(1,
"No more urgent messages, opened INBOX and got %d new messages\n", vms.
lastmsg + 1);
13166 ast_trace(-1,
"open mailbox: %d\n", res);
13177 if ((cmd ==
't') || (cmd ==
'#')) {
13205 int new = 0, old = 0, urgent = 0;
13206 snprintf(ext_context,
sizeof(ext_context),
"%s@%s", vms.
username, vmu->
context);
13214 ast_debug(3,
"*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n", deleted, expungeonhangup);
13215 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream !=
NULL) {
13217#ifdef HAVE_IMAP_TK2006
13218 if (LEVELUIDPLUS (vms.mailstream)) {
13219 mail_expunge_full(vms.mailstream, NIL, EX_UID);
13222 mail_expunge(vms.mailstream);
13228 vmstate_delete(&vms);
13235 pthread_setspecific(ts_vmstate.key,
NULL);
13253 memset(&leave_options, 0,
sizeof(leave_options));
13258 if (
args.argc == 2) {
13284 res =
ast_app_getdata(chan,
"vm-whichbox", temp,
sizeof(temp) - 1, 0);
13334 ast_log(
LOG_ERROR,
"Voicemail data file %s/%d.txt has no [message] category?\n", dir, msg);
13355 ast_log(
LOG_WARNING,
"Mailbox %s in context %s begins with '*' character. The '*' character,"
13356 "\n\twhen it is the first character in a mailbox or password, is used to jump to a"
13357 "\n\tpredefined extension 'a'. A mailbox or password beginning with '*' is not valid"
13358 "\n\tand will be ignored.\n", box,
context);
13365 ast_log(
LOG_WARNING,
"\nIt has been detected that you have defined mailbox '%s' in separate\
13366 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
13367 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
13368 \n\tamend your voicemail.conf file to avoid this situation.\n", box);
13398 int new = 0, old = 0, urgent = 0;
13409 if ((s =
strsep(&stringp,
","))) {
13412 "\n\tmust be reset in voicemail.conf.\n", box);
13417 if (stringp && (s =
strsep(&stringp,
","))) {
13420 if (stringp && (s =
strsep(&stringp,
","))) {
13423 if (stringp && (s =
strsep(&stringp,
","))) {
13443 imap_logout(mailbox_full);
13450#ifdef TEST_FRAMEWORK
13456 static const char options_string[] =
"attach=yes|attachfmt=wav49|"
13457 "serveremail=someguy@digium.com|fromstring=Voicemail System|tz=central|delete=yes|saycid=yes|"
13458 "sendvoicemail=yes|review=yes|tempgreetwarn=yes|messagewrap=yes|operator=yes|leaveurgent=yes|"
13459 "envelope=yes|moveheard=yes|sayduration=yes|saydurationm=5|forcename=yes|"
13460 "forcegreetings=yes|callback=somecontext|dialout=somecontext2|"
13461 "exitcontext=somecontext3|minsecs=10|maxsecs=100|nextaftercmd=yes|"
13462 "backupdeleted=50|volgain=1.3|passwordlocation=spooldir|emailbody="
13463 "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message|emailsubject="
13464 "[PBX]: New message \\\\${VM_MSGNUM}\\\\ in mailbox ${VM_MAILBOX}";
13466 static const char option_string2[] =
"imapuser=imapuser|imappassword=imappasswd|"
13467 "imapfolder=INBOX|imapvmshareid=6000|imapserver=imapserver|imapport=1234|imapflags=flagged";
13472 info->name =
"vmuser";
13473 info->category =
"/apps/app_voicemail/";
13474 info->summary =
"Vmuser unit test";
13475 info->description =
13476 "This tests passing all supported parameters to apply_options, the voicemail user config parser";
13494 if (strcasecmp(vmu->
attachfmt,
"wav49")) {
13498 if (strcasecmp(vmu->
fromstring,
"Voicemail System")) {
13502 if (strcasecmp(vmu->
serveremail,
"someguy@digium.com")) {
13506 if (!vmu->
emailsubject || strcasecmp(vmu->
emailsubject,
"[PBX]: New message \\${VM_MSGNUM}\\ in mailbox ${VM_MAILBOX}")) {
13510 if (!vmu->
emailbody || strcasecmp(vmu->
emailbody,
"Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message")) {
13514 if (strcasecmp(vmu->
zonetag,
"central")) {
13574 if (strcasecmp(vmu->
callback,
"somecontext")) {
13578 if (strcasecmp(vmu->
dialout,
"somecontext2")) {
13582 if (strcasecmp(vmu->
exit,
"somecontext3")) {
13613 if (strcasecmp(vmu->imapuser,
"imapuser")) {
13617 if (strcasecmp(vmu->imappassword,
"imappasswd")) {
13621 if (strcasecmp(vmu->imapfolder,
"INBOX")) {
13625 if (strcasecmp(vmu->imapvmshareid,
"6000")) {
13629 if (strcasecmp(vmu->imapserver,
"imapserver")) {
13633 if (strcasecmp(vmu->imapport,
"1234")) {
13637 if (strcasecmp(vmu->imapflags,
"flagged")) {
13667 ast_log(
LOG_ERROR,
"VM_INFO requires an argument (<mailbox>[@<context>],attribute[,folder])\n");
13677 ast_log(
LOG_ERROR,
"VM_INFO requires an argument (<mailbox>[@<context>],attribute[,folder])\n");
13681 memset(&svm, 0,
sizeof(svm));
13684 if (!strncasecmp(arg.attribute,
"exists", 5)) {
13691 if (!strncasecmp(arg.attribute,
"password", 8)) {
13693 }
else if (!strncasecmp(arg.attribute,
"fullname", 8)) {
13695 }
else if (!strncasecmp(arg.attribute,
"email", 5)) {
13697 }
else if (!strncasecmp(arg.attribute,
"pager", 5)) {
13699 }
else if (!strncasecmp(arg.attribute,
"language", 8)) {
13701 }
else if (!strncasecmp(arg.attribute,
"locale", 6)) {
13703 }
else if (!strncasecmp(arg.attribute,
"tz", 2)) {
13705 }
else if (!strncasecmp(arg.attribute,
"count", 5)) {
13714 ast_log(
LOG_ERROR,
"Unable to retrieve message count for mailbox %s\n", arg.mailbox_context);
13718 snprintf(
buf,
len,
"%d", res);
13720 ast_log(
LOG_ERROR,
"Unknown attribute '%s' for VM_INFO\n", arg.attribute);
13740 int silent = 0, skipuser = 0;
13766 }
else if (
mailbox[0] ==
'*') {
13779 const char *cat =
NULL;
13788 "=============================================================\n"
13789 "=== Configured Voicemail Users ==============================\n"
13790 "=============================================================\n"
13796 "=== Mailbox ...\n"
13802 "=== ---------------------------------------------------------\n"
13807 "=============================================================\n"
13826 wordlen = strlen(
word);
13847#define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
13849 int users_counter = 0;
13853 e->
command =
"voicemail show users [for]";
13855 "Usage: voicemail show users [for <context>]\n"
13856 " Lists all mailboxes currently set up\n";
13862 if ((
a->argc < 3) || (
a->argc > 5) || (
a->argc == 4))
13864 if (
a->argc == 5) {
13865 if (strcmp(
a->argv[3],
"for"))
13872 ast_cli(
a->fd,
"You must specify a specific context to show users from realtime!\n");
13880 ast_cli(
a->fd,
"There are no voicemail users currently defined\n");
13903 int newmsgs = 0, oldmsgs = 0;
13904 char count[12], tmp[256] =
"";
13909 snprintf(count,
sizeof(count),
"%d", newmsgs);
13915 ast_cli(
a->fd,
"%d voicemail users configured.\n", users_counter);
13923#define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
13928 e->
command =
"voicemail show zones";
13930 "Usage: voicemail show zones\n"
13931 " Lists zone message formats\n";
13947 ast_cli(
a->fd,
"There are no voicemail zones currently defined\n");
13960#define ALIASES_OUTPUT_FORMAT "%-32s %-32s\n"
13965 e->
command =
"voicemail show aliases";
13967 "Usage: voicemail show aliases\n"
13968 " Lists mailbox aliases\n";
13978 ast_cli(
a->fd,
"Aliases are not enabled\n");
14000 e->
command =
"voicemail reload";
14002 "Usage: voicemail reload\n"
14003 " Reload voicemail configuration\n";
14012 ast_cli(
a->fd,
"Reloading voicemail configuration...\n");
14031 int new = 0, old = 0, urgent = 0;
14041 if (imap_poll_logout) {
14057 struct timespec ts = { 0, };
14058 struct timeval wait;
14067 ts.tv_sec = wait.tv_sec;
14068 ts.tv_nsec = wait.tv_usec * 1000;
14079static void imap_logout(
const char *mailbox_id)
14092 memset(&vmus, 0,
sizeof(vmus));
14098 vms = get_vm_state_by_imapuser(vmu->imapuser, 0);
14107 vms->mailstream = mail_close(vms->mailstream);
14110 vmstate_delete(vms);
14113static int imap_close_subscribed_mailbox(
struct ast_mwi_state *mwi_state,
void *data)
14136 imap_close_subscribed_mailbox(mwi_state,
NULL);
14210 const char* event_name,
14211 const char* actionid
14219 if((s ==
NULL) || (vmu ==
NULL) || (event_name ==
NULL) || (actionid ==
NULL)) {
14239 ast_log(
LOG_ERROR,
"Could not get mailbox count. user[%s], context[%s]\n",
14247 "VMContext: %s\r\n"
14248 "VoiceMailbox: %s\r\n"
14252 "ServerEmail: %s\r\n"
14253 "FromString: %s\r\n"
14254 "MailCommand: %s\r\n"
14260 "ExitContext: %s\r\n"
14261 "SayDurationMinimum: %d\r\n"
14262 "SayEnvelope: %s\r\n"
14264 "AttachMessage: %s\r\n"
14265 "AttachmentFormat: %s\r\n"
14266 "DeleteMessage: %s\r\n"
14267 "VolumeGain: %.2f\r\n"
14268 "CanReview: %s\r\n"
14269 "CanMarkUrgent: %s\r\n"
14270 "CallOperator: %s\r\n"
14271 "MaxMessageCount: %d\r\n"
14272 "MaxMessageLength: %d\r\n"
14273 "NewMessageCount: %d\r\n"
14274 "OldMessageCount: %d\r\n"
14277 "IMAPServer: %s\r\n"
14279 "IMAPFlags: %s\r\n"
14335 const char* event_name,
14336 const char* actionid)
14340 int nummessages = 0;
14345 if (!mailbox_snapshot) {
14353 for (i = 0; i < mailbox_snapshot->
folders; i++) {
14398 (at = strchr(mwi_state->
uniqueid,
'@')) &&
14402 (at = strchr(mwi_state->
uniqueid,
'@')) &&
14403 strcmp(
context, at + 1) == 0) ||
14406 (at = strchr(mwi_state->
uniqueid,
'@')) &&
14408 strcmp(
context, at + 1) == 0)
14428 char actionid[128];
14440 actionid[0] =
'\0';
14442 snprintf(actionid,
sizeof(actionid),
"ActionID: %s\r\n",
id);
14446 memset(&svm, 0,
sizeof(svm));
14450 astman_send_ack(s, m,
"There is no voicemail user of the given info.");
14474 char actionid[128];
14478 actionid[0] =
'\0';
14480 snprintf(actionid,
sizeof(actionid),
"ActionID: %s\r\n",
id);
14486 astman_send_ack(s, m,
"There are no voicemail users currently defined.");
14515 char actionid[128];
14526 actionid[0] =
'\0';
14528 snprintf(actionid,
sizeof(actionid),
"ActionID: %s\r\n",
id);
14532 memset(&svm, 0,
sizeof(svm));
14536 astman_send_ack(s, m,
"There is no voicemail user matching the given user.");
14716 if (!
str->used ||
str->str[
str->used - 1] !=
'\r') {
14750 ast_log(
LOG_ERROR,
"Config file users.conf is in an invalid format. Avoiding.\n");
14765 ast_log(
LOG_ERROR,
"Config file users.conf is in an invalid format. Avoiding.\n");
14783#ifdef TEST_FRAMEWORK
14795 size_t from_len = strlen(
alias) + 1;
14796 size_t to_len = strlen(
mailbox) + 1;
14798 mapping =
ao2_alloc(
sizeof(*mapping) + from_len + to_len,
NULL);
14838 char storage[strlen(
var->value) + 1];
14845 strcpy(storage,
var->value);
14870 if (strcasecmp(cat,
"general") == 0
14872 || strcasecmp(cat,
"zonemessages") == 0) {
14889 char *q, *stringp, *tmp;
14891 unsigned int tmpadsi[4];
14893 long tps_queue_low;
14894 long tps_queue_high;
14950 strcpy(odbc_database,
"asterisk");
14955 strcpy(odbc_table,
"voicemessages");
14959 odbc_table_len = strlen(odbc_table);
14995 if (sscanf(
val,
"%30d", &x) == 1)
15064 expungeonhangup = 0;
15066 expungeonhangup = 1;
15068 expungeonhangup = 1;
15095 imap_poll_logout = 0;
15103 mail_parameters(NIL, SET_READTIMEOUT, (
void *) (atol(
val)));
15105 mail_parameters(NIL, SET_READTIMEOUT, (
void *) 60L);
15109 mail_parameters(NIL, SET_WRITETIMEOUT, (
void *) (atol(
val)));
15111 mail_parameters(NIL, SET_WRITETIMEOUT, (
void *) 60L);
15115 mail_parameters(NIL, SET_OPENTIMEOUT, (
void *) (atol(
val)));
15117 mail_parameters(NIL, SET_OPENTIMEOUT, (
void *) 60L);
15121 mail_parameters(NIL, SET_CLOSETIMEOUT, (
void *) (atol(
val)));
15123 mail_parameters(NIL, SET_CLOSETIMEOUT, (
void *) 60L);
15139 ast_debug(1,
"Enabled SMDI voicemail notification\n");
15143 ast_debug(1,
"No SMDI interface set, trying default (/dev/ttyS0)\n");
15147 ast_log(
AST_LOG_ERROR,
"No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
15162 if (sscanf(
val,
"%30d", &x) == 1) {
15168 static int maxmessage_deprecate = 0;
15169 if (maxmessage_deprecate == 0) {
15170 maxmessage_deprecate = 1;
15173 if (sscanf(
val,
"%30d", &x) == 1) {
15182 if (sscanf(
val,
"%30d", &x) == 1) {
15191 static int maxmessage_deprecate = 0;
15192 if (maxmessage_deprecate == 0) {
15193 maxmessage_deprecate = 1;
15196 if (sscanf(
val,
"%30d", &x) == 1) {
15213 ast_log(
LOG_ERROR,
"Error processing format string, defaulting to format 'wav'\n");
15221 if (sscanf(
val,
"%30d", &x) == 1) {
15229 if (sscanf(
val,
"%30d", &x) == 1) {
15238 if (sscanf(
val,
"%30d", &x) == 1) {
15247 if (sscanf(
val,
"%30d", &x) == 1) {
15265 ast_debug(1,
"VM_CID Internal context string: %s\n",
val);
15269 q =
strsep(&stringp,
",");
15270 while ((*q ==
' ')||(*q ==
'\t'))
15280 ast_debug(1,
"VM Review Option disabled globally\n");
15288 ast_debug(1,
"VM leave urgent messages disabled globally\n");
15295 ast_debug(1,
"VM Temporary Greeting Reminder Option disabled globally\n");
15298 ast_debug(1,
"VM Temporary Greeting Reminder Option enabled globally\n");
15302 ast_debug(1,
"VM next message wrap disabled globally\n");
15308 ast_debug(1,
"VM Operator break disabled globally\n");
15314 ast_debug(1,
"VM CID Info before msg disabled globally\n");
15320 ast_debug(1,
"Send Voicemail msg disabled globally\n");
15326 ast_debug(1,
"ENVELOPE before msg enabled globally\n");
15332 ast_debug(1,
"Move Heard enabled globally\n");
15338 ast_debug(1,
"Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
15344 ast_debug(1,
"Duration info before msg enabled globally\n");
15351 if (sscanf(
val,
"%30d", &x) == 1) {
15359 ast_debug(1,
"We are not going to skip to the next msg after save/delete\n");
15425 val =
"voicemail.conf";
15427 if (!(strcmp(
val,
"spooldir"))) {
15447 strcpy(
charset,
"ISO-8859-1");
15473 sscanf(
val,
"%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
15474 for (x = 0; x < 4; x++) {
15475 memcpy(&
adsifdn[x], &tmpadsi[x], 1);
15479 sscanf(
val,
"%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
15480 for (x = 0; x < 4; x++) {
15481 memcpy(&
adsisec[x], &tmpadsi[x], 1);
15510 if (sscanf(
val,
"%30ld", &tps_queue_high) != 1 || tps_queue_high <= 0) {
15515 tps_queue_low = -1;
15517 if (sscanf(
val,
"%30ld", &tps_queue_low) != 1 ||
15518 tps_queue_low < -1 || tps_queue_high < tps_queue_low) {
15520 tps_queue_low = -1;
15530 if (!strcasecmp(cat,
"general")) {
15543 switch (
current->passwordlocation) {
15584 ast_debug(2,
"About to try retrieving name file %s\n", dir);
15630 ast_log(
LOG_NOTICE,
"Failed reading voicemail password from %s, using secret from config file\n", secretfn);
15689#ifdef TEST_FRAMEWORK
15704 static const char TEST_CONTEXT[] =
"very_long_unique_context_so_that_nobody_will_ever_have_the_same_one_configured_3141592653";
15712 .
write = fake_write,
15718 info->name =
"vmsayname_exec";
15719 info->category =
"/apps/app_voicemail/";
15720 info->summary =
"Vmsayname unit test";
15721 info->description =
15722 "This tests passing various parameters to vmsayname";
15729 NULL,
NULL, 0, 0,
"TestChannel1"))) {
15730 goto exit_vmsayname_test;
15736 goto exit_vmsayname_test;
15756 goto exit_vmsayname_test;
15761 goto exit_vmsayname_test;
15766 if ((res = symlink(dir, dir2))) {
15768 goto exit_vmsayname_test;
15783exit_vmsayname_test:
15806 struct test_files *tmp =
ast_alloca(
sizeof(
struct test_files) * 3);
15808 const char origweasels[] =
"tt-weasels";
15809 const char testcontext[] =
"test";
15810 const char testmailbox[] =
"00000000";
15811 const char testspec[] =
"00000000@test";
15813 int new, old, urgent;
15814 const char *folders[3] = {
"Old",
"Urgent",
"INBOX" };
15815 const int folder2mbox[3] = { 1, 11, 0 };
15816 const int expected_results[3][12] = {
15818 { 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 },
15819 { 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
15820 { 1, 1, 1, 1, 0, 2, 1, 1, 1, 1, 1, 2 },
15825 info->name =
"test_voicemail_msgcount";
15826 info->category =
"/apps/app_voicemail/";
15827 info->summary =
"Test Voicemail status checks";
15828 info->description =
15829 "Verify that message counts are correct when retrieved through the public API";
15836 snprintf(syscmd,
sizeof(syscmd),
"rm -rf \"%s%s/%s\"",
VM_SPOOL_DIR, testcontext, testmailbox);
15839 syserr > 0 ? strerror(syserr) :
"unable to fork()");
15850 memset(&svm, 0,
sizeof(svm));
15851 if (!(vmu =
find_user(&svm, testcontext, testmailbox)) &&
15861 memset(&vms, 0,
sizeof(vms));
15864 for (i = 0; i < 3; i++) {
15865 create_dirpath(tmp[i].dir,
sizeof(tmp[i].dir), testcontext, testmailbox, folders[i]);
15867 snprintf(tmp[i].txtfile,
sizeof(tmp[i].txtfile),
"%s.txt", tmp[i].
file);
15870 snprintf(syscmd,
sizeof(syscmd),
"cp \"%s/sounds/en/%s.gsm\" \"%s/%s/%s/%s/msg0000.gsm\"",
ast_config_AST_DATA_DIR, origweasels,
15874 syserr > 0 ? strerror(syserr) :
"unable to fork()");
15883 if ((txt = fopen(tmp[i].txtfile,
"w+"))) {
15884 fprintf(txt,
"; just a stub\n[message]\nflag=%s\n", strcmp(folders[i],
"Urgent") ?
"" :
"Urgent");
15892 STORE(tmp[i].dir, testmailbox, testcontext, 0, chan, vmu,
"gsm", 600, &vms, strcmp(folders[i],
"Urgent") ?
"" :
"Urgent",
NULL);
15895 for (j = 0; j < 3; j++) {
15904 new = old = urgent = 0;
15908 }
else if (old != expected_results[i][3 + 0] ||
new != expected_results[i][3 + 2]) {
15910 testspec, old, expected_results[i][3 + 0],
new, expected_results[i][3 + 2]);
15914 new = old = urgent = 0;
15918 }
else if (old != expected_results[i][6 + 0] ||
15919 urgent != expected_results[i][6 + 1] ||
15920 new != expected_results[i][6 + 2] ) {
15921 ast_test_status_update(
test,
"inboxcount2(%s) returned old=%d (expected %d), urgent=%d (expected %d), and new=%d (expected %d)\n",
15922 testspec, old, expected_results[i][6 + 0], urgent, expected_results[i][6 + 1],
new, expected_results[i][6 + 2]);
15926 new = old = urgent = 0;
15927 for (j = 0; j < 3; j++) {
15930 testspec, folders[j],
ast_app_messagecount(testspec, folders[j]), expected_results[i][9 + j]);
15936 for (i = 0; i < 3; i++) {
15956 snprintf(syscmd,
sizeof(syscmd),
"rm -rf \"%s%s/%s\"",
VM_SPOOL_DIR, testcontext, testmailbox);
15959 syserr > 0 ? strerror(syserr) :
"unable to fork()");
15970 char testcontext[] =
"test";
15971 char testmailbox[] =
"00000000";
15972 char from[] =
"test@example.net", cidnum[] =
"1234", cidname[] =
"Mark Spencer", format[] =
"gsm";
15973 char attach[256], attach2[256];
15974 char buf[256] =
"";
15982 enum { INT, FLAGVAL, STATIC, STRPTR }
type;
15989 {
"plain jane config", STATIC, vmus.
password, .u.strval =
"1234" },
15990 {
"emailsubject", STRPTR, vmus.
emailsubject, .u.strval =
"Oogly boogly\xf8koogly with what appears to be UTF-8" },
15991 {
"emailbody", STRPTR, vmus.
emailbody, .u.strval =
"This is a test\n\twith multiple\nlines\nwithin\n" },
15992 {
"serveremail", STATIC, vmus.
serveremail, .u.strval =
"\"\xf8Something\xe8that\xd8seems to have UTF-8 chars\" <test@example.net>" },
15993 {
"attachment flag", FLAGVAL, &vmus.
flags, .u.intval =
VM_ATTACH },
15994 {
"attach2", STRPTR, attach2, .u.strval =
"" },
15995 {
"attach", STRPTR, attach, .u.strval =
"" },
16001 info->name =
"test_voicemail_notify_endl";
16002 info->category =
"/apps/app_voicemail/";
16003 info->summary =
"Test Voicemail notification end-of-line";
16004 info->description =
16005 "Verify that notification emails use a consistent end-of-line character";
16014 if (!(vmu =
find_user(&vmus, testcontext, testmailbox)) &&
16020 if (vmu != &vmus && !(vmu =
find_user(&vmus, testcontext, testmailbox))) {
16032 for (which = 0; which <
ARRAY_LEN(test_items); which++) {
16035 if (ftruncate(fileno(
file), 0)) {
16042 if (test_items[which].
type == INT) {
16043 *((
int *) test_items[which].location) = test_items[which].u.intval;
16044 }
else if (test_items[which].
type == FLAGVAL) {
16050 }
else if (test_items[which].
type == STATIC) {
16051 strcpy(test_items[which].location, test_items[which].u.strval);
16052 }
else if (test_items[which].
type == STRPTR) {
16053 test_items[which].location = test_items[which].u.strval;
16056 make_email_file(
file, from, vmu, 0, testcontext, testmailbox,
"INBOX", cidnum, cidname, attach, attach2, format, 999, 1, chan,
NULL, 0,
NULL,
NULL);
16060 (strlen(
buf) > 1 &&
16062 buf[strlen(
buf) - 2] !=
'\r'
16064 buf[strlen(
buf) - 2] ==
'\r'
16067 ||
buf[strlen(
buf) - 1] !=
'\n') {
16090 info->name =
"test_voicemail_load_config";
16091 info->category =
"/apps/app_voicemail/";
16092 info->summary =
"Test loading Voicemail config";
16093 info->description =
16094 "Verify that configuration is loaded consistently. "
16095 "This is to test regressions of ASTERISK-18838 where it was noticed that "
16096 "some options were loaded after the mailboxes were instantiated, causing "
16097 "those options not to be set correctly.";
16107 if (!(
file = fdopen(fd,
"w"))) {
16112 fputs(
"[general]\ncallback=somecontext\nlocale=de_DE.UTF-8\ntz=european\n[test]",
file);
16113 fputs(
"00000001 => 9999,Mr. Test,,,callback=othercontext|locale=nl_NL.UTF-8|tz=central\n",
file);
16114 fputs(
"00000002 => 9999,Mrs. Test\n",
file);
16122 load_config_from_memory(1, cfg,
NULL);
16125#define CHECK(u, attr, value) else if (strcmp(u->attr, value)) { \
16126 ast_test_status_update(test, "mailbox %s should have %s '%s', but has '%s'\n", \
16127 u->mailbox, #attr, value, u->attr); res = AST_TEST_FAIL; break; }
16131 if (!strcmp(vmu->
mailbox,
"00000001")) {
16133 CHECK(vmu, callback,
"othercontext")
16134 CHECK(vmu,
locale, "nl_NL.UTF-8")
16135 CHECK(vmu,
zonetag, "central")
16136 } else
if (!strcmp(vmu->
mailbox, "00000002")) {
16138 CHECK(vmu, callback,
"somecontext")
16139 CHECK(vmu,
locale, "de_DE.UTF-8")
16140 CHECK(vmu,
zonetag, "european")
16159 const char testcontext[] =
"test";
16160 const char testmailbox[] =
"00000000";
16161 const char vminfo_cmd[] =
"VM_INFO";
16162 char vminfo_buf[256], vminfo_args[256];
16165 int test_counter = 0;
16168 char *vminfo_test_args;
16169 char *vminfo_expected;
16173 {
"00000000@test,badparam",
"", -1 },
16174 {
"00000000@test",
"", -1 },
16175 {
"00000000@test,exists",
"1", 0 },
16176 {
"11111111@test,exists",
"0", 0 },
16177 {
"00000000@test,email",
"vm-info-test@example.net", 0 },
16178 {
"11111111@test,email",
"", 0 },
16179 {
"00000000@test,fullname",
"Test Framework Mailbox", 0 },
16180 {
"00000000@test,pager",
"vm-info-pager-test@example.net", 0 },
16181 {
"00000000@test,locale",
"en_US", 0 },
16182 {
"00000000@test,tz",
"central", 0 },
16183 {
"00000000@test,language",
"en", 0 },
16184 {
"00000000@test,password",
"9876", 0 },
16189 info->name =
"test_voicemail_vm_info";
16190 info->category =
"/apps/app_voicemail/";
16191 info->summary =
"VM_INFO unit test";
16192 info->description =
16193 "This tests passing various parameters to VM_INFO";
16226 for (test_counter = 0; test_counter <
ARRAY_LEN(test_items); test_counter++) {
16227 ast_copy_string(vminfo_args, test_items[test_counter].vminfo_test_args,
sizeof(vminfo_args));
16228 test_ret =
acf_vm_info(chan, vminfo_cmd, vminfo_args, vminfo_buf,
sizeof(vminfo_buf));
16229 if (strcmp(vminfo_buf, test_items[test_counter].vminfo_expected)) {
16230 ast_test_status_update(
test,
"VM_INFO respose was: '%s', but expected: '%s'\n", vminfo_buf, test_items[test_counter].vminfo_expected);
16233 if (!(test_ret == test_items[test_counter].vminfo_ret)) {
16234 ast_test_status_update(
test,
"VM_INFO return code was: '%i', but expected '%i'\n", test_ret, test_items[test_counter].vminfo_ret);
16292#ifdef TEST_FRAMEWORK
16303#ifdef TEST_FRAMEWORK
16304 ast_uninstall_vm_test_functions();
16335 prnt(where,
"Alias: %s Mailbox: %s", mapping->
alias, mapping->
mailbox);
16365 alias_mailbox_mapping_hash_fn,
NULL, alias_mailbox_mapping_cmp_fn);
16367 ast_log(
LOG_ERROR,
"Unable to create alias_mailbox_mappings container\n");
16373 ast_log(
LOG_ERROR,
"Unable to register alias_mailbox_mappings container\n");
16380 mailbox_alias_mapping_hash_fn,
NULL, mailbox_alias_mapping_cmp_fn);
16382 ast_log(
LOG_ERROR,
"Unable to create mailbox_alias_mappings container\n");
16390 ast_log(
LOG_ERROR,
"Unable to register mailbox_alias_mappings container\n");
16423#ifdef TEST_FRAMEWORK
16433 ast_log(
LOG_ERROR,
"Failure registering applications, functions or tests\n");
16456#ifdef TEST_FRAMEWORK
16457 ast_install_vm_test_functions(vm_test_create_user, vm_test_destroy_user);
16469 char destination[80] =
"";
16473 ast_verb(3,
"Destination number will be entered manually\n");
16474 while (retries < 3 && cmd !=
't') {
16475 destination[1] =
'\0';
16484 destination[0] = cmd;
16493 ast_verb(3,
"User hit '*' to cancel outgoing call\n");
16496 if ((cmd =
ast_readstring(chan, destination + strlen(destination),
sizeof(destination) - 1, 6000, 10000,
"#")) < 0)
16502 isprint(cmd) ? cmd :
'?', isprint(cmd) ? cmd :
'?');
16504 if (retries >= 3) {
16509 ast_verb(3,
"Destination number is CID number '%s'\n", num);
16514 if (destination[strlen(destination) -1 ] ==
'*')
16516 ast_verb(3,
"Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context,
ast_channel_context(chan));
16543 const char *origtime, *
context;
16554 snprintf(filename,
sizeof(filename),
"%s.txt", vms->
fn);
16589 while ((res > -1) && (res !=
't')) {
16613 ast_verb(3,
"Caller can not specify callback number - no dialout context available\n");
16635 ast_verb(3,
"Confirm CID number '%s' is number to use for callback\n", num);
16666 isprint(res) ? res :
'?', isprint(res) ? res :
'?');
16672 else if (res ==
'*')
16684 ast_verb(3,
"No CID number available, no reply sent\n");
16691 memset(&vmu2, 0,
sizeof(vmu2));
16698 ast_verb(3,
"Leaving voicemail for '%s' in context '%s'\n", num, vmu->
context);
16700 memset(&leave_options, 0,
sizeof(leave_options));
16711 ast_verb(3,
"No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->
context);
16725#ifndef IMAP_STORAGE
16728 vms->
heard[msg] = 1;
16736 int outsidecaller,
struct ast_vm_user *vmu,
int *duration,
int *sound_duration,
const char *unlockdir,
16742 int max_attempts = 3;
16745 int msg_exists = 0;
16746 signed char zero_gain = 0;
16748 char *acceptdtmf =
"#";
16749 char *canceldtmf =
"";
16750 int canceleddtmf = 0;
16751 SCOPE_ENTER(3,
"%s: rf: %s fmt: %s type: %s vmu: %s\n",
16752 ast_channel_name(chan), recordfile, fmt, outsidecaller ?
"msg" :
"greeting",
16757 if (duration ==
NULL) {
16761 if (!outsidecaller)
16762 snprintf(tempfile,
sizeof(tempfile),
"%s.tmp", recordfile);
16768 while ((cmd >= 0) && (cmd !=
't')) {
16777 ast_verb(3,
"Saving message as is\n");
16778 if (!outsidecaller) {
16779 ast_trace(-1,
"Renaming greeting '%s' to '%s'\n", tempfile, recordfile);
16782 if (!forwardintro) {
16785 if (!outsidecaller) {
16787 ast_trace(-1,
"Saving greeting '%s'\n", recordfile);
16788 SCOPE_CALL(-1,
STORE, recordfile, vmu->
mailbox, vmu->
context, -1, chan, vmu, fmt, *duration, vms,
flag, msg_id);
16796 ast_verb(3,
"Reviewing the message\n");
16797 ast_trace(-1,
"Reviewing '%s'\n", tempfile);
16804 ast_verb(3,
"Re-recording the message\n");
16806 ast_verb(3,
"Recording the message\n");
16808 if (recorded && outsidecaller) {
16809 if (forwardintro) {
16819 SCOPE_EXIT_RTN_VALUE(cmd,
"User hung up before message could be rerecorded. Deleted '%s'\n", tempfile);
16827 ast_trace(-1,
"Recording '%s'\n", tempfile);
16828 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);
16829 if (strchr(canceldtmf, cmd)) {
16837 if (!outsidecaller) {
16842 outsidecaller ?
"Saved message " :
"Deleted greeting \n", tempfile);
16846 }
else if (cmd ==
'*') {
16849 }
else if (vmu->review && sound_duration && (*sound_duration < 5)) {
16851 ast_verb(3,
"Message too short\n");
16855 }
else if (vmu->review && (cmd == 2 && sound_duration && *sound_duration < (
maxsilence + 3))) {
16857 ast_verb(3,
"Nothing recorded\n");
16874 ast_verb(3,
"marking message as Urgent\n");
16876 strcpy(
flag,
"Urgent");
16878 ast_verb(3,
"UNmarking message as Urgent\n");
16905 if (outsidecaller) {
16917 if (msg_exists || recorded) {
16918 ast_trace(-1,
"Reviewing '%s'\n", tempfile);
16923 ast_trace(-1,
"Saving '%s' to '%s'\n", tempfile, recordfile);
16927 }
else if (cmd ==
'4') {
16930 strcpy(
flag,
"Urgent");
16935 ast_trace(-1,
"Deleting '%s'\n", tempfile);
16979 if (attempts > max_attempts) {
16984 if (!outsidecaller && (cmd == -1 || cmd ==
't')) {
16986 ast_trace(-1,
"Deleting '%s' on hangup or timeout\n", tempfile);
16990 if (cmd !=
't' && outsidecaller)
17000 if (!(msg_snapshot =
ast_calloc(1,
sizeof(*msg_snapshot)))) {
17009 return msg_snapshot;
17020#ifdef TEST_FRAMEWORK
17022static int vm_test_destroy_user(
const char *
context,
const char *
mailbox)
17040static int vm_test_create_user(
const char *
context,
const char *
mailbox)
17067 int snapshot_index,
17083 snprintf(filename,
sizeof(filename),
"%s.txt", vms->
fn);
17107 filename,
id,
sizeof(
id), vmu, mailbox_index))) {
17138 switch (sort_val) {
17151 if (descending &&
val >= 0) {
17155 }
else if (!descending &&
val <= 0) {
17181 const char *folder,
17184 int combine_INBOX_and_OLD)
17191 int this_index_only = -1;
17198 ast_log(
LOG_WARNING,
"Cannot create a mailbox snapshot since no mailbox was specified\n");
17202 memset(&vmus, 0,
sizeof(vmus));
17208 this_index_only = i;
17212 if (this_index_only == -1) {
17223 if (!(mailbox_snapshot =
ast_calloc(1,
sizeof(*mailbox_snapshot)))) {
17237 for (i = 0; i < mailbox_snapshot->
folders; i++) {
17238 int msg_folder_index = i;
17245 if (!(this_index_only == -1 || this_index_only == i || (this_index_only == inbox_index && combine_INBOX_and_OLD && (i == old_index || i == urgent_index)))) {
17250 if (combine_INBOX_and_OLD && (i == old_index || i == urgent_index)) {
17251 msg_folder_index = inbox_index;
17254 memset(&vms, 0,
sizeof(vms));
17262 goto snapshot_cleanup;
17270 goto snapshot_cleanup;
17276 goto snapshot_cleanup;
17288 vmstate_delete(&vms);
17293 return mailbox_snapshot;
17301 for (i = 0; i < mailbox_snapshot->
folders; i++) {
17334 for (i = 0; i < num_msgs; ++i) {
17335 const char *
msg_id = msg_ids[i];
17338 const char *other_msg_id;
17344 snprintf(filename,
sizeof(filename),
"%s.txt", vms->
fn);
17355 if (!
ast_strlen_zero(other_msg_id) && !strcmp(other_msg_id, msg_id)) {
17360 msg_nums[i] = vms->
curmsg;
17381 int new = 0, old = 0, urgent = 0;
17382 char ext_context[1024];
17384 snprintf(ext_context,
sizeof(ext_context),
"%s@%s", vmu->
mailbox, vmu->
context);
17391 const char *from_context,
17392 const char *from_folder,
17393 const char *to_mailbox,
17394 const char *to_context,
17395 const char *to_folder,
17397 const char *msg_ids [],
17406 int from_folder_index;
17413 ast_log(
LOG_WARNING,
"Cannot forward message because either the from or to mailbox was not specified\n");
17418 ast_log(
LOG_WARNING,
"Invalid number of messages specified to forward: %zu\n", num_msgs);
17423 ast_log(
LOG_WARNING,
"Cannot forward message because the from_folder or to_folder was not specified\n");
17427 memset(&vmus, 0,
sizeof(vmus));
17428 memset(&to_vmus, 0,
sizeof(to_vmus));
17429 memset(&from_vms, 0,
sizeof(from_vms));
17432 if (from_folder_index == -1) {
17445 if (!(to_vmu =
find_user(&to_vmus, to_context, to_mailbox))) {
17446 ast_log(
LOG_WARNING,
"Can't find voicemail user to forward to (%s@%s)\n", to_mailbox, to_context);
17456 if ((res =
open_mailbox(&from_vms, vmu, from_folder_index)) < 0) {
17459 goto vm_forward_cleanup;
17464 if ((from_vms.
lastmsg + 1) < num_msgs) {
17465 ast_log(
LOG_WARNING,
"Folder %s has less than %zu messages\n", from_folder, num_msgs);
17467 goto vm_forward_cleanup;
17470 msg_nums =
ast_alloca(
sizeof(
int) * num_msgs);
17473 goto vm_forward_cleanup;
17477 for (i = 0; i < num_msgs; i++) {
17478 int cur_msg = msg_nums[i];
17483 snprintf(filename,
sizeof(filename),
"%s.txt", from_vms.
fn);
17495 duration = atoi(
value);
17501 from_vms.
deleted[cur_msg] = 1;
17510 goto vm_forward_cleanup;
17520 vmstate_delete(&from_vms);
17536 const char *oldfolder,
17537 const char *old_msg_ids [],
17538 const char *newfolder)
17542 int old_folder_index;
17543 int new_folder_index;
17555 ast_log(
LOG_WARNING,
"Invalid number of messages specified to move: %zu\n", num_msgs);
17560 ast_log(
LOG_WARNING,
"Cannot move message because either oldfolder or newfolder was not specified\n");
17567 memset(&vmus, 0,
sizeof(vmus));
17568 memset(&vms, 0,
sizeof(vms));
17570 if (old_folder_index == -1 || new_folder_index == -1) {
17583 if ((res =
open_mailbox(&vms, vmu, old_folder_index)) < 0) {
17586 goto vm_move_cleanup;
17591 if ((vms.
lastmsg + 1) < num_msgs) {
17592 ast_log(
LOG_WARNING,
"Folder %s has less than %zu messages\n", oldfolder, num_msgs);
17594 goto vm_move_cleanup;
17597 old_msg_nums =
ast_alloca(
sizeof(
int) * num_msgs);
17600 goto vm_move_cleanup;
17604 for (i = 0; i < num_msgs; ++i) {
17607 goto vm_move_cleanup;
17609 vms.
deleted[old_msg_nums[i]] = 1;
17615 goto vm_move_cleanup;
17625 vmstate_delete(&vms);
17640 const char *folder,
17641 const char *msgs[])
17657 ast_log(
LOG_WARNING,
"Invalid number of messages specified to remove: %zu\n", num_msgs);
17666 memset(&vmus, 0,
sizeof(vmus));
17667 memset(&vms, 0,
sizeof(vms));
17670 if (folder_index == -1) {
17685 if ((res =
open_mailbox(&vms, vmu, folder_index)) < 0) {
17688 goto vm_remove_cleanup;
17693 if ((vms.
lastmsg + 1) < num_msgs) {
17696 goto vm_remove_cleanup;
17699 msg_nums =
ast_alloca(
sizeof(
int) * num_msgs);
17702 goto vm_remove_cleanup;
17705 for (i = 0; i < num_msgs; i++) {
17706 vms.
deleted[msg_nums[i]] = 1;
17713 goto vm_remove_cleanup;
17723 vmstate_delete(&vms);
17738 const char *folder,
17739 const char *msg_id,
17764 ast_log(
LOG_WARNING,
"Cannot play message because no message number was specified\n");
17768 memset(&vmus, 0,
sizeof(vmus));
17769 memset(&vms, 0,
sizeof(vms));
17784 goto play2_msg_cleanup;
17790 goto play2_msg_cleanup;
17795 snprintf(filename,
sizeof(filename),
"%s.txt", vms.
fn);
17802 goto play2_msg_cleanup;
17805 duration = atoi(
value);
17818 cb(chan, vms.
fn, duration);
17819 }
else if ((
wait_file(chan, &vms, vms.
fn)) < 0) {
17837 vmstate_delete(&vms);
17858 .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 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 occurences 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 passowrd 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 actual_load_config(int reload, struct ast_config *cfg, struct ast_config *ucfg)
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 char userscontext[AST_MAX_EXTENSION]
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
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.
@ CONFIG_FLAG_WITHCOMMENTS
@ CONFIG_FLAG_FILEUNCHANGED
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.
const char * ast_config_option(struct ast_config *cfg, const char *cat, const char *var)
Retrieve a configuration variable within the configuration set.
struct ast_variable * ast_load_realtime(const char *family,...) attribute_sentinel
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
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::@185 * snapshots
const ast_string_field origtime
struct ast_vm_msg_snapshot::@184 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 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.