55 #ifdef USE_SYSTEM_IMAP
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__)
568 static char imapserver[48] =
"localhost";
569 static char imapport[8] =
"143";
570 static char imapflags[128];
571 static char imapfolder[64] =
"INBOX";
572 static char imapparentfolder[64];
573 static char greetingfolder[64] =
"INBOX";
574 static char authuser[32];
575 static char authpassword[42];
576 static int imapversion = 1;
578 static int expungeonhangup = 1;
579 static int imapgreetings;
580 static int imap_poll_logout;
581 static char delimiter;
592 static int init_mailstream(
struct vm_state *vms,
int box);
593 static void write_file(
char *filename,
char *buffer,
unsigned long len);
594 static char *get_header_by_tag(
char *
header,
char *tag,
char *buf,
size_t len);
595 static void vm_imap_delete(
char *file,
int msgnum,
struct ast_vm_user *vmu);
596 static char *get_user_by_mailbox(
char *
mailbox,
char *buf,
size_t len);
597 static struct vm_state *get_vm_state_by_imapuser(
const char *
user,
int interactive);
598 static struct vm_state *get_vm_state_by_mailbox(
const char *mailbox,
const char *context,
int interactive);
600 static void vmstate_insert(
struct vm_state *vms);
601 static void vmstate_delete(
struct vm_state *vms);
602 static void set_update(MAILSTREAM * stream);
603 static void init_vm_state(
struct vm_state *vms);
604 static int save_body(BODY *body,
struct vm_state *vms,
char *section,
char *format,
int is_intro);
605 static void get_mailbox_delimiter(
struct vm_state *vms, MAILSTREAM *stream);
606 static void mm_parsequota (MAILSTREAM *stream,
unsigned char *msg, QUOTALIST *pquota);
607 static void imap_mailbox_name(
char *spec,
size_t len,
struct vm_state *vms,
int box,
int target);
608 static int imap_store_file(
const char *dir,
const char *mailboxuser,
const char *mailboxcontext,
int msgnum,
struct ast_channel *chan,
struct ast_vm_user *vmu,
char *fmt,
int duration,
struct vm_state *vms,
const char *flag,
const char *msg_id);
609 static 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);
610 static void update_messages_by_imapuser(
const char *
user,
unsigned long number);
613 static int imap_remove_file (
char *dir,
int msgnum);
614 static int imap_retrieve_file (
const char *dir,
const int msgnum,
const char *mailbox,
const char *context);
615 static int imap_delete_old_greeting (
char *dir,
struct vm_state *vms);
616 static void check_quota(
struct vm_state *vms,
char *mailbox);
618 static void imap_logout(
const char *mailbox_id);
629 #define SMDI_MWI_WAIT_TIMEOUT 1000
631 #define COMMAND_TIMEOUT 5000
633 #define VOICEMAIL_DIR_MODE 0777
634 #define VOICEMAIL_FILE_MODE 0666
635 #define CHUNKSIZE 65536
637 #define VOICEMAIL_CONFIG "voicemail.conf"
638 #define ASTERISK_USERNAME "asterisk"
643 #define DEFAULT_LISTEN_CONTROL_FORWARD_KEY "#"
644 #define DEFAULT_LISTEN_CONTROL_REVERSE_KEY "*"
645 #define DEFAULT_LISTEN_CONTROL_PAUSE_KEY "0"
646 #define DEFAULT_LISTEN_CONTROL_RESTART_KEY "2"
647 #define DEFAULT_LISTEN_CONTROL_STOP_KEY "13456789"
648 #define VALID_DTMF "1234567890*#"
652 #define SENDMAIL "/usr/sbin/sendmail -t"
653 #define INTRO "vm-intro"
655 #define MAX_MAIL_BODY_CONTENT_SIZE 134217728L // 128 Mbyte
658 #define MAXMSGLIMIT 9999
660 #define MINPASSWORD 0
668 #define MAX_DATETIME_FORMAT 512
669 #define MAX_NUM_CID_CONTEXTS 10
671 #define VM_REVIEW (1 << 0)
672 #define VM_OPERATOR (1 << 1)
673 #define VM_SAYCID (1 << 2)
674 #define VM_SVMAIL (1 << 3)
675 #define VM_ENVELOPE (1 << 4)
676 #define VM_SAYDURATION (1 << 5)
677 #define VM_SKIPAFTERCMD (1 << 6)
678 #define VM_FORCENAME (1 << 7)
679 #define VM_FORCEGREET (1 << 8)
680 #define VM_PBXSKIP (1 << 9)
681 #define VM_DIRECTFORWARD (1 << 10)
682 #define VM_ATTACH (1 << 11)
683 #define VM_DELETE (1 << 12)
684 #define VM_ALLOCED (1 << 13)
685 #define VM_SEARCH (1 << 14)
686 #define VM_TEMPGREETWARN (1 << 15)
687 #define VM_MOVEHEARD (1 << 16)
688 #define VM_MESSAGEWRAP (1 << 17)
689 #define VM_FWDURGAUTO (1 << 18)
690 #define VM_EMAIL_EXT_RECS (1 << 19)
691 #define VM_MARK_URGENT (1 << 20)
692 #define VM_ODBC_AUDIO_ON_DISK (1 << 21)
694 #define ERROR_LOCK_PATH -100
695 #define ERROR_MAX_MSGS -101
696 #define OPERATOR_EXIT 300
698 #define MSGFILE_LEN (7)
706 GREETINGS_FOLDER = -1
709 enum vm_option_flags {
710 OPT_SILENT = (1 << 0),
711 OPT_BUSY_GREETING = (1 << 1),
712 OPT_UNAVAIL_GREETING = (1 << 2),
713 OPT_RECORDGAIN = (1 << 3),
714 OPT_PREPEND_MAILBOX = (1 << 4),
715 OPT_AUTOPLAY = (1 << 6),
716 OPT_DTMFEXIT = (1 << 7),
717 OPT_MESSAGE_Urgent = (1 << 8),
718 OPT_MESSAGE_PRIORITY = (1 << 9),
719 OPT_EARLYM_GREETING = (1 << 10),
720 OPT_BEEP = (1 << 11),
721 OPT_SILENT_IF_GREET = (1 << 12),
722 OPT_READONLY = (1 << 13),
725 enum vm_option_args {
726 OPT_ARG_RECORDGAIN = 0,
727 OPT_ARG_PLAYFOLDER = 1,
728 OPT_ARG_DTMFEXIT = 2,
729 OPT_ARG_BEEP_TONE = 3,
731 OPT_ARG_ARRAY_SIZE = 4,
734 enum vm_passwordlocation {
735 OPT_PWLOC_VOICEMAILCONF = 0,
736 OPT_PWLOC_SPOOLDIR = 1,
737 OPT_PWLOC_USERSCONF = 2,
756 static const char *
const mailbox_folders[] = {
785 #define force_reload_config() load_config_force(1, 1)
787 static int load_config(
int reload);
788 #ifdef TEST_FRAMEWORK
789 static int load_config_from_memory(
int reload,
struct ast_config *cfg,
struct ast_config *ucfg);
885 #define MAX_VM_MBOX_ID_LEN (AST_MAX_EXTENSION)
886 #define MAX_VM_CONTEXT_LEN (AST_MAX_CONTEXT)
888 #define MAX_VM_MAILBOX_LEN (MAX_VM_MBOX_ID_LEN + MAX_VM_CONTEXT_LEN)
893 char context[MAX_VM_CONTEXT_LEN];
894 char mailbox[MAX_VM_MBOX_ID_LEN];
901 char serveremail[80];
902 char fromstring[100];
923 char imappassword[80];
925 char imapvmshareid[80];
937 char msg_format[512];
940 #define VMSTATE_MAX_MSG_ARRAY 256
947 char curdir[PATH_MAX];
948 char vmbox[PATH_MAX];
950 char intro[PATH_MAX];
965 unsigned msg_array_max;
966 MAILSTREAM *mailstream;
975 char introfn[PATH_MAX];
976 unsigned int quota_limit;
977 unsigned int quota_usage;
983 static char odbc_database[80] =
"asterisk";
984 static char odbc_table[80] =
"voicemessages";
985 size_t odbc_table_len =
sizeof(odbc_table);
986 #define COUNT(a, b) odbc_count_messages(a,b)
987 #define LAST_MSG_INDEX(a) odbc_last_message_index(a)
988 #define RETRIEVE(a,b,c,d) odbc_retrieve_message(a,b)
989 #define DISPOSE(a,b) odbc_remove_files(a,b)
990 #define STORE(a,b,c,d,e,f,g,h,i,j,k) odbc_store_message(a,b,c,d)
991 #define EXISTS(a,b,c,d) (odbc_message_exists(a,b))
992 #define RENAME(a,b,c,d,e,f,g,h) (odbc_rename_message(a,b,c,d,e,f))
993 #define COPY(a,b,c,d,e,f,g,h) (odbc_copy_message(a,b,c,d,e,f))
994 #define DELETE(a,b,c,d) (odbc_delete_message(a,b))
995 #define UPDATE_MSG_ID(a, b, c, d, e, f) (odbc_update_msg_id((a), (b), (c)))
998 #define DISPOSE(a,b) (imap_remove_file(a,b))
999 #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))
1000 #define RETRIEVE(a,b,c,d) imap_retrieve_file(a,b,c,d)
1001 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
1002 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
1003 #define COPY(a,b,c,d,e,f,g,h) (copy_file(g,h));
1004 #define DELETE(a,b,c,d) (vm_imap_delete(a,b,d))
1005 #define UPDATE_MSG_ID(a, b, c, d, e, f) (vm_imap_update_msg_id((a), (b), (c), (d), (e), (f)))
1007 #define COUNT(a, b) count_messages(a,b)
1008 #define LAST_MSG_INDEX(a) last_message_index(a)
1009 #define RETRIEVE(a,b,c,d)
1010 #define DISPOSE(a,b)
1011 #define STORE(a,b,c,d,e,f,g,h,i,j,k)
1012 #define EXISTS(a,b,c,d) (ast_fileexists(c,NULL,d) > 0)
1013 #define RENAME(a,b,c,d,e,f,g,h) (rename_file(g,h));
1014 #define COPY(a,b,c,d,e,f,g,h) (copy_plain_file(g,h));
1015 #define DELETE(a,b,c,d) (vm_delete(c))
1016 #define UPDATE_MSG_ID(a, b, c, d, e, f)
1020 static char VM_SPOOL_DIR[PATH_MAX];
1022 static char ext_pass_cmd[128];
1023 static char ext_pass_check_cmd[128];
1025 static int my_umask;
1027 #define PWDCHANGE_INTERNAL (1 << 1)
1028 #define PWDCHANGE_EXTERNAL (1 << 2)
1029 static int pwdchange = PWDCHANGE_INTERNAL;
1032 #define tdesc "Comedian Mail (Voicemail System) with ODBC Storage"
1034 # ifdef IMAP_STORAGE
1035 # define tdesc "Comedian Mail (Voicemail System) with IMAP Storage"
1037 # define tdesc "Comedian Mail (Voicemail System)"
1043 static char *addesc =
"Comedian Mail";
1046 static char *voicemail_app =
"VoiceMail";
1049 static char *voicemailmain_app =
"VoiceMailMain";
1051 static char *vmauthenticate_app =
"VMAuthenticate";
1053 static char *playmsg_app =
"VoiceMailPlayMsg";
1055 static char *sayname_app =
"VMSayName";
1059 static char zonetag[80];
1060 static char locale[20];
1061 static int maxsilence;
1062 static int maxmsg = MAXMSG;
1063 static int maxdeletedmsg;
1064 static int silencethreshold = 128;
1066 static char mailcmd[160] =
SENDMAIL;
1067 static char externnotify[160];
1069 static char vmfmts[80] =
"wav";
1070 static double volgain;
1071 static int vmminsecs;
1072 static int vmmaxsecs;
1073 static int maxgreet;
1074 static int skipms = 3000;
1075 static int maxlogins = 3;
1077 static int passwordlocation;
1078 static char aliasescontext[MAX_VM_CONTEXT_LEN];
1085 #define DEFAULT_POLL_FREQ 30
1089 AST_MUTEX_DEFINE_STATIC(poll_lock);
1090 static ast_cond_t poll_cond = PTHREAD_COND_INITIALIZER;
1091 static pthread_t poll_thread = AST_PTHREADT_NULL;
1092 static unsigned char poll_thread_run;
1108 #define MAPPING_BUCKETS 511
1118 static char listen_control_forward_key[12];
1119 static char listen_control_reverse_key[12];
1120 static char listen_control_pause_key[12];
1121 static char listen_control_restart_key[12];
1122 static char listen_control_stop_key[12];
1125 static char vm_login[80] =
"vm-login";
1126 static char vm_newuser[80] =
"vm-newuser";
1127 static char vm_password[80] =
"vm-password";
1128 static char vm_newpassword[80] =
"vm-newpassword";
1129 static char vm_passchanged[80] =
"vm-passchanged";
1130 static char vm_reenterpassword[80] =
"vm-reenterpassword";
1131 static char vm_mismatch[80] =
"vm-mismatch";
1132 static char vm_invalid_password[80] =
"vm-invalid-password";
1133 static char vm_pls_try_again[80] =
"vm-pls-try-again";
1145 static char vm_prepend_timeout[80] =
"vm-then-pound";
1149 static int saydurationminfo = 2;
1155 static char cidinternalcontexts[MAX_NUM_CID_CONTEXTS][64];
1158 static char *emailbody;
1159 static char *emailsubject;
1160 static char *pagerbody;
1161 static char *pagersubject;
1162 static char fromstring[100];
1163 static char pagerfromstring[100];
1164 static char charset[32] =
"ISO-8859-1";
1166 static unsigned char adsifdn[4] =
"\x00\x00\x00\x0F";
1167 static unsigned char adsisec[4] =
"\x9B\xDB\xF7\xAC";
1168 static int adsiver = 1;
1169 static char emaildateformat[32] =
"%A, %B %d, %Y at %r";
1170 static char pagerdateformat[32] =
"%A, %B %d, %Y at %r";
1176 static int dialout(
struct ast_channel *chan,
struct ast_vm_user *vmu,
char *num,
char *outgoing_context);
1177 static int play_record_review(
struct ast_channel *chan,
char *playfile,
char *recordfile,
int maxtime,
1178 char *fmt,
int outsidecaller,
struct ast_vm_user *vmu,
int *duration,
int *sound_duration,
const char *unlockdir,
1179 signed char record_gain,
struct vm_state *vms,
char *flag,
const char *msg_id,
int forwardintro);
1181 static int vm_play_folder_name(
struct ast_channel *chan,
char *mbox);
1183 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);
1185 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);
1187 static void read_password_from_file(
const char *secretfn,
char *password,
int passwordlen);
1188 static int write_password_to_file(
const char *secretfn,
const char *password);
1189 static const char *substitute_escapes(
const char *value);
1191 static void notify_new_state(
struct ast_vm_user *vmu);
1212 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);
1215 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);
1216 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);
1217 static int vm_msg_remove(
const char *mailbox,
const char *context,
size_t num_msgs,
const char *folder,
const char *msgs[]);
1218 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);
1220 #ifdef TEST_FRAMEWORK
1221 static int vm_test_destroy_user(
const char *context,
const char *mailbox);
1222 static int vm_test_create_user(
const char *context,
const char *mailbox);
1237 static int separate_mailbox(
char *mailbox_id,
char **mailbox,
char **context)
1239 if (ast_strlen_zero(mailbox_id) || !mailbox || !context) {
1242 *context = mailbox_id;
1243 *mailbox = strsep(context,
"@");
1244 if (ast_strlen_zero(*mailbox)) {
1247 if (ast_strlen_zero(*context)) {
1248 *context =
"default";
1261 static int inprocess_hash_fn(
const void *obj,
const int flags)
1264 return atoi(i->mailbox);
1267 static int inprocess_cmp_fn(
void *obj,
void *arg,
int flags)
1270 if (strcmp(i->mailbox, j->mailbox)) {
1273 return !strcmp(i->context, j->context) ?
CMP_MATCH : 0;
1276 static int inprocess_count(
const char *context,
const char *mailbox,
int delta)
1278 int context_len = strlen(context) + 1;
1279 int mailbox_len = strlen(mailbox) + 1;
1281 arg->context = arg->mailbox + mailbox_len;
1284 ao2_lock(inprocess_container);
1285 if ((i = ao2_find(inprocess_container, arg, 0))) {
1287 ao2_unlock(inprocess_container);
1292 ast_log(LOG_WARNING,
"BUG: ref count decrement on non-existing object???\n");
1294 if (!(i = ao2_alloc(
sizeof(*i) + context_len + mailbox_len, NULL))) {
1295 ao2_unlock(inprocess_container);
1298 i->context = i->mailbox + mailbox_len;
1303 ao2_unlock(inprocess_container);
1308 #if !(defined(ODBC_STORAGE) || defined(IMAP_STORAGE))
1309 static int __has_voicemail(
const char *context,
const char *mailbox,
const char *folder,
int shortcircuit);
1321 for (; *input; input++) {
1326 if (bufptr == buf + buflen - 1) {
1353 static size_t get_msg_path_len(
const char *dir)
1355 if (ast_strlen_zero(dir)) {
1367 #define MAX_SOUND_EXTEN_LEN 12
1380 static size_t get_msg_path_ext_len(
const char *dir)
1382 if (ast_strlen_zero(dir)) {
1386 return strlen(dir) + 1 +
MSGFILE_LEN + MAX_SOUND_EXTEN_LEN + 1;
1410 #define MAKE_FILE_PTRA(dir, msgnum) \
1412 size_t __len = get_msg_path_len(dir); \
1415 __var = ast_strdupa(dir); \
1417 __var = ast_alloca(__len); \
1418 snprintf(__var, __len, "%s/msg%04d", dir, msgnum); \
1452 #define MAKE_FILE_EXT_PTRA(dir, msgnum, ext) \
1454 size_t __len = get_msg_path_ext_len(dir); \
1455 char *__var = ast_alloca(__len); \
1457 snprintf(__var, __len, "%s.%s", dir, ext); \
1459 snprintf(__var, __len, "%s/msg%04d.%s", dir, msgnum, ext); \
1480 ast_copy_flags(vmu, (&globalflags), AST_FLAGS_ALL);
1482 if (saydurationminfo) {
1483 vmu->saydurationm = saydurationminfo;
1499 if (maxdeletedmsg) {
1503 ast_free(vmu->
email);
1510 ast_copy_string(vmu->imapfolder, imapfolder,
sizeof(vmu->imapfolder));
1511 ast_copy_string(vmu->imapserver, imapserver,
sizeof(vmu->imapserver));
1528 if (!strcasecmp(var,
"attach")) {
1530 }
else if (!strcasecmp(var,
"attachfmt")) {
1532 }
else if (!strcasecmp(var,
"attachextrecs")) {
1534 }
else if (!strcasecmp(var,
"serveremail")) {
1536 }
else if (!strcasecmp(var,
"fromstring")) {
1538 }
else if (!strcasecmp(var,
"emailbody")) {
1541 }
else if (!strcasecmp(var,
"emailsubject")) {
1544 }
else if (!strcasecmp(var,
"language")) {
1546 }
else if (!strcasecmp(var,
"tz")) {
1548 }
else if (!strcasecmp(var,
"locale")) {
1551 }
else if (!strcasecmp(var,
"imapuser")) {
1553 vmu->imapversion = imapversion;
1554 }
else if (!strcasecmp(var,
"imapserver")) {
1556 vmu->imapversion = imapversion;
1557 }
else if (!strcasecmp(var,
"imapport")) {
1559 vmu->imapversion = imapversion;
1560 }
else if (!strcasecmp(var,
"imapflags")) {
1562 vmu->imapversion = imapversion;
1563 }
else if (!strcasecmp(var,
"imappassword") || !strcasecmp(var,
"imapsecret")) {
1565 vmu->imapversion = imapversion;
1566 }
else if (!strcasecmp(var,
"imapfolder")) {
1568 vmu->imapversion = imapversion;
1569 }
else if (!strcasecmp(var,
"imapvmshareid")) {
1570 ast_copy_string(vmu->imapvmshareid, value,
sizeof(vmu->imapvmshareid));
1571 vmu->imapversion = imapversion;
1573 }
else if (!strcasecmp(var,
"delete") || !strcasecmp(var,
"deletevoicemail")) {
1575 }
else if (!strcasecmp(var,
"saycid")){
1577 }
else if (!strcasecmp(var,
"sendvoicemail")){
1579 }
else if (!strcasecmp(var,
"review")){
1581 }
else if (!strcasecmp(var,
"leaveurgent")){
1583 }
else if (!strcasecmp(var,
"tempgreetwarn")){
1585 }
else if (!strcasecmp(var,
"messagewrap")){
1587 }
else if (!strcasecmp(var,
"operator")) {
1589 }
else if (!strcasecmp(var,
"envelope")){
1591 }
else if (!strcasecmp(var,
"moveheard")){
1593 }
else if (!strcasecmp(var,
"sayduration")){
1595 }
else if (!strcasecmp(var,
"saydurationm")){
1596 if (sscanf(value,
"%30d", &x) == 1) {
1597 vmu->saydurationm = x;
1599 ast_log(AST_LOG_WARNING,
"Invalid min duration for say duration\n");
1601 }
else if (!strcasecmp(var,
"forcename")){
1603 }
else if (!strcasecmp(var,
"forcegreetings")){
1605 }
else if (!strcasecmp(var,
"callback")) {
1607 }
else if (!strcasecmp(var,
"dialout")) {
1609 }
else if (!strcasecmp(var,
"exitcontext")) {
1611 }
else if (!strcasecmp(var,
"minsecs")) {
1612 if (sscanf(value,
"%30d", &x) == 1 && x >= 0) {
1615 ast_log(LOG_WARNING,
"Invalid min message length of %s. Using global value %d\n", value, vmminsecs);
1618 }
else if (!strcasecmp(var,
"maxmessage") || !strcasecmp(var,
"maxsecs")) {
1621 ast_log(AST_LOG_WARNING,
"Invalid max message length of %s. Using global value %d\n", value, vmmaxsecs);
1626 if (!strcasecmp(var,
"maxmessage"))
1627 ast_log(AST_LOG_WARNING,
"Option 'maxmessage' has been deprecated in favor of 'maxsecs'. Please make that change in your voicemail config.\n");
1628 }
else if (!strcasecmp(var,
"maxmsg")) {
1629 vmu->
maxmsg = atoi(value);
1632 ast_log(AST_LOG_WARNING,
"Invalid number of messages per folder maxmsg=%s. Using default value %d\n", value, MAXMSG);
1634 }
else if (vmu->
maxmsg > MAXMSGLIMIT) {
1635 ast_log(AST_LOG_WARNING,
"Maximum number of messages per folder is %d. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value);
1636 vmu->
maxmsg = MAXMSGLIMIT;
1638 }
else if (!strcasecmp(var,
"nextaftercmd")) {
1640 }
else if (!strcasecmp(var,
"backupdeleted")) {
1641 if (sscanf(value,
"%30d", &x) == 1)
1649 ast_log(AST_LOG_WARNING,
"Invalid number of deleted messages saved per mailbox backupdeleted=%s. Using default value %d\n", value, MAXMSG);
1652 ast_log(AST_LOG_WARNING,
"Maximum number of deleted messages saved per mailbox is %d. Cannot accept value backupdeleted=%s\n", MAXMSGLIMIT, value);
1655 }
else if (!strcasecmp(var,
"volgain")) {
1656 sscanf(value,
"%30lf", &vmu->
volgain);
1657 }
else if (!strcasecmp(var,
"passwordlocation")) {
1658 if (!strcasecmp(value,
"spooldir")) {
1663 }
else if (!strcasecmp(var,
"options")) {
1668 static char *vm_check_password_shell(
char *command,
char *buf,
size_t len)
1670 int fds[2], pid = 0;
1672 memset(buf, 0, len);
1675 snprintf(buf, len,
"FAILURE: Pipe failed: %s", strerror(errno));
1684 snprintf(buf, len,
"FAILURE: Fork failed");
1688 if (read(fds[0], buf, len) < 0) {
1689 ast_log(LOG_WARNING,
"read() failed: %s\n", strerror(errno));
1700 dup2(fds[1], STDOUT_FILENO);
1706 execv(arg.v[0], arg.v);
1707 printf(
"FAILURE: %s", strerror(errno));
1724 if (strlen(password) < minpassword)
1727 if (!ast_strlen_zero(password) && password[0] ==
'*')
1729 if (!ast_strlen_zero(ext_pass_check_cmd)) {
1730 char cmd[255], buf[255];
1732 ast_debug(1,
"Verify password policies for %s\n", password);
1734 snprintf(cmd,
sizeof(cmd),
"%s %s %s %s %s", ext_pass_check_cmd, vmu->
mailbox, vmu->
context, vmu->
password, password);
1735 if (vm_check_password_shell(cmd, buf,
sizeof(buf))) {
1737 if (!strncasecmp(buf,
"VALID", 5)) {
1738 ast_debug(3,
"Passed password check: '%s'\n", buf);
1740 }
else if (!strncasecmp(buf,
"FAILURE", 7)) {
1741 ast_log(AST_LOG_WARNING,
"Unable to execute password validation script: '%s'.\n", buf);
1744 ast_log(AST_LOG_NOTICE,
"Password doesn't match policies for user %s %s\n", vmu->
mailbox, password);
1765 if (!strcmp(vmu->
password, password)) {
1770 if (strlen(password) > 10) {
1790 while ((s = strsep(&stringp,
"|"))) {
1792 if ((var = strsep(&value,
"=")) && value) {
1805 for (; var; var = var->
next) {
1806 if (!strcasecmp(var->
name,
"vmsecret")) {
1808 }
else if (!strcasecmp(var->
name,
"secret") || !strcasecmp(var->
name,
"password")) {
1809 if (ast_strlen_zero(retval->
password)) {
1810 if (!ast_strlen_zero(var->
value) && var->
value[0] ==
'*') {
1811 ast_log(LOG_WARNING,
"Invalid password detected for mailbox %s. The password"
1812 "\n\tmust be reset in voicemail.conf.\n", retval->
mailbox);
1817 }
else if (!strcasecmp(var->
name,
"uniqueid")) {
1819 }
else if (!strcasecmp(var->
name,
"pager")) {
1821 }
else if (!strcasecmp(var->
name,
"email")) {
1822 ast_free(retval->
email);
1824 }
else if (!strcasecmp(var->
name,
"fullname")) {
1826 }
else if (!strcasecmp(var->
name,
"context")) {
1828 }
else if (!strcasecmp(var->
name,
"emailsubject")) {
1831 }
else if (!strcasecmp(var->
name,
"emailbody")) {
1835 }
else if (!strcasecmp(var->
name,
"imapuser")) {
1837 retval->imapversion = imapversion;
1838 }
else if (!strcasecmp(var->
name,
"imapserver")) {
1840 retval->imapversion = imapversion;
1841 }
else if (!strcasecmp(var->
name,
"imapport")) {
1843 retval->imapversion = imapversion;
1844 }
else if (!strcasecmp(var->
name,
"imapflags")) {
1846 retval->imapversion = imapversion;
1847 }
else if (!strcasecmp(var->
name,
"imappassword") || !strcasecmp(var->
name,
"imapsecret")) {
1849 retval->imapversion = imapversion;
1850 }
else if (!strcasecmp(var->
name,
"imapfolder")) {
1852 retval->imapversion = imapversion;
1853 }
else if (!strcasecmp(var->
name,
"imapvmshareid")) {
1855 retval->imapversion = imapversion;
1874 for (i = 0; i < strlen(key); ++i) {
1875 if (!strchr(VALID_DTMF, *local_key)) {
1876 ast_log(AST_LOG_WARNING,
"Invalid DTMF key \"%c\" used in voicemail configuration file\n", *local_key);
1899 if ((retval = (ivm ? ivm :
ast_calloc(1,
sizeof(*retval))))) {
1901 memset(retval, 0,
sizeof(*retval));
1910 if (!context && ast_test_flag((&globalflags),
VM_SEARCH)) {
1911 var = ast_load_realtime(
"voicemail",
"mailbox", mailbox, SENTINEL);
1913 var = ast_load_realtime(
"voicemail",
"mailbox", mailbox,
"context", context, SENTINEL);
1941 if (!context && !ast_test_flag((&globalflags),
VM_SEARCH))
1942 context =
"default";
1946 if (cur->imapversion != imapversion) {
1950 if (ast_test_flag((&globalflags),
VM_SEARCH) && !strcasecmp(mailbox, cur->mailbox))
1952 if (context && (!strcasecmp(context, cur->context)) && (!strcasecmp(mailbox, cur->mailbox)))
1957 if ((vmu = (ivm ? ivm :
ast_calloc(1,
sizeof(*vmu))))) {
1958 ast_free(vmu->
email);
1973 if (!vmu && !ast_strlen_zero(aliasescontext)) {
1975 char *search_string =
ast_alloca(MAX_VM_MAILBOX_LEN);
1977 snprintf(search_string, MAX_VM_MAILBOX_LEN,
"%s%s%s",
1979 ast_strlen_zero(context) ?
"" :
"@",
1982 mapping = ao2_find(alias_mailbox_mappings, search_string,
OBJ_SEARCH_KEY);
1984 char *search_mailbox = NULL;
1985 char *search_context = NULL;
1987 separate_mailbox(
ast_strdupa(mapping->mailbox), &search_mailbox, &search_context);
1989 vmu =
find_user(ivm, search_mailbox, search_context);
2006 static int reset_user_pw(
const char *context,
const char *mailbox,
const char *newpass)
2013 if ((!context || !strcasecmp(context, cur->
context)) &&
2014 (!strcasecmp(mailbox, cur->
mailbox)))
2026 "Context",
S_OR(context,
"default"),
2028 "NewPassword", newpass);
2040 return cfg && cfg != CONFIG_STATUS_FILEINVALID;
2055 char *category = NULL;
2056 const char *tmp = NULL;
2058 char secretfn[PATH_MAX] =
"";
2066 case OPT_PWLOC_SPOOLDIR:
2067 snprintf(secretfn,
sizeof(secretfn),
"%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->
context, vmu->
mailbox);
2068 if (write_password_to_file(secretfn, newpassword) == 0) {
2070 ast_verb(4,
"Writing voicemail password to file %s succeeded\n", secretfn);
2075 ast_log(LOG_WARNING,
"Writing voicemail password to file %s failed, falling back to config file\n", secretfn);
2078 case OPT_PWLOC_VOICEMAILCONF:
2081 if (!strcasecmp(category, vmu->
context)) {
2084 if (!(tmp = ast_variable_retrieve(cfg, category, vmu->
mailbox))) {
2085 ast_log(AST_LOG_WARNING,
"We could not find the mailbox.\n");
2088 value = strstr(tmp,
",");
2091 sprintf(
new,
"%s", newpassword);
2093 new =
ast_malloc((strlen(value) + strlen(newpassword) + 1));
2094 sprintf(
new,
"%s%s", newpassword, value);
2097 ast_log(AST_LOG_WARNING,
"Failed to get category structure.\n");
2108 ast_test_suite_event_notify(
"PASSWORDCHANGED",
"Message: voicemail.conf updated with new password\r\nPasswordSource: voicemail.conf");
2119 case OPT_PWLOC_USERSCONF:
2125 ast_debug(4,
"users.conf: %s\n", category);
2126 if (!strcasecmp(category, vmu->
mailbox)) {
2127 char new[strlen(newpassword) + 1];
2128 if (!ast_variable_retrieve(cfg, category,
"vmsecret")) {
2129 ast_debug(3,
"looks like we need to make vmsecret!\n");
2130 var = ast_variable_new(
"vmsecret", newpassword,
"");
2135 sprintf(
new,
"%s", newpassword);
2137 ast_debug(4,
"failed to get category!\n");
2144 ast_variable_append(cat, var);
2163 static void vm_change_password_shell(
struct ast_vm_user *vmu,
char *newpassword)
2166 snprintf(buf,
sizeof(buf),
"%s %s %s %s", ext_pass_cmd, vmu->
context, vmu->
mailbox, newpassword);
2167 ast_debug(1,
"External password: %s\n",buf);
2189 static int make_dir(
char *dest,
int len,
const char *context,
const char *ext,
const char *folder)
2191 return snprintf(dest, len,
"%s%s/%s/%s", VM_SPOOL_DIR, context, ext, folder);
2206 static int make_file(
char *dest,
const int len,
const char *dir,
const int num)
2208 return snprintf(dest, len,
"%s/msg%04d", dir, num);
2219 static int create_dirpath(
char *dest,
int len,
const char *context,
const char *ext,
const char *folder)
2221 mode_t mode = VOICEMAIL_DIR_MODE;
2224 make_dir(dest, len, context, ext, folder);
2226 ast_log(AST_LOG_WARNING,
"ast_mkdir '%s' failed: %s\n", dest, strerror(res));
2232 static const char *mbox(
struct ast_vm_user *vmu,
int id)
2235 if (vmu &&
id == 0) {
2236 return vmu->imapfolder;
2239 return (
id >= 0 &&
id < ARRAY_LEN(mailbox_folders)) ? mailbox_folders[id] :
"Unknown";
2242 static const char *vm_index_to_foldername(
int id)
2244 return mbox(NULL,
id);
2248 static int get_folder_by_name(
const char *name)
2252 for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
2253 if (strcasecmp(name, mailbox_folders[i]) == 0) {
2267 ast_free(vmu->
email);
2279 static void free_user_final(
struct ast_vm_user *vmu)
2285 if (!ast_strlen_zero(vmu->
mailbox)) {
2294 int arraysize = (vmu->
maxmsg > count_msg ? vmu->
maxmsg : count_msg);
2298 ast_free(vms->deleted);
2299 vms->deleted = NULL;
2302 ast_free(vms->heard);
2305 vms->dh_arraysize = 0;
2307 if (arraysize > 0) {
2308 if (!(vms->deleted =
ast_calloc(arraysize,
sizeof(
int)))) {
2311 if (!(vms->heard =
ast_calloc(arraysize,
sizeof(
int)))) {
2312 ast_free(vms->deleted);
2313 vms->deleted = NULL;
2316 vms->dh_arraysize = arraysize;
2325 static void vm_imap_delete(
char *file,
int msgnum,
struct ast_vm_user *vmu)
2329 unsigned long messageNum;
2332 if (msgnum < 0 && !imapgreetings) {
2337 if (!(vms = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 0))) {
2338 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);
2343 imap_delete_old_greeting(file, vms);
2349 messageNum = vms->msgArray[msgnum];
2350 if (messageNum == 0) {
2351 ast_log(LOG_WARNING,
"msgnum %d, mailbox message %lu is zero.\n", msgnum, messageNum);
2354 ast_debug(3,
"deleting msgnum %d, which is mailbox message %lu\n", msgnum, messageNum);
2356 snprintf (arg,
sizeof(arg),
"%lu", messageNum);
2357 ast_mutex_lock(&vms->lock);
2358 mail_setflag (vms->mailstream, arg,
"\\DELETED");
2359 mail_expunge(vms->mailstream);
2360 ast_mutex_unlock(&vms->lock);
2363 static 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)
2370 const char *duration_str;
2382 if (open_mailbox(vms, vmu, folder)) {
2388 close_mailbox(vms, vmu);
2396 cid =
ast_strdupa(ast_variable_retrieve(msg_cfg,
"message",
"callerid"));
2398 if (!ast_strlen_zero(cid)) {
2401 if (!ast_strlen_zero(cid_name)) {
2405 if (!ast_strlen_zero(cid_num)) {
2411 duration_str = ast_variable_retrieve(msg_cfg,
"message",
"duration");
2413 if (!ast_strlen_zero(duration_str)) {
2414 sscanf(duration_str,
"%30d", &duration);
2425 if (!imap_store_file(dir, vmu->
mailbox, vmu->
context, msgnum, chan, vmu, vmfmts,
2426 duration, vms, ast_variable_retrieve(msg_cfg,
"message",
"flag"), msg_id)) {
2427 if (folder != NEW_FOLDER) {
2430 vm_imap_delete(dir, msgnum, vmu);
2432 close_mailbox(vms, vmu);
2436 static int imap_retrieve_greeting(
const char *dir,
const int msgnum,
struct ast_vm_user *vmu)
2439 char *file, *filename;
2440 char dest[PATH_MAX];
2449 if (msgnum > -1 || !imapgreetings) {
2456 ast_debug(1,
"Failed to procure file name from directory passed.\n");
2462 if (!(vms_p = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 1)) &&
2463 !(vms_p = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 0))) {
2468 if (!(vms_p = create_vm_state_from_user(vmu))) {
2469 ast_log(LOG_NOTICE,
"Unable to create vm_state object!\n");
2475 *vms_p->introfn =
'\0';
2477 ast_mutex_lock(&vms_p->lock);
2480 curr_mbox = get_folder_by_name(vms_p->curbox);
2482 if (init_mailstream(vms_p, GREETINGS_FOLDER) || !vms_p->mailstream) {
2483 ast_log(AST_LOG_ERROR,
"IMAP mailstream is NULL or can't init_mailstream\n");
2484 ast_mutex_unlock(&vms_p->lock);
2489 for (i = 0; i < vms_p->mailstream->nmsgs; i++) {
2490 mail_fetchstructure(vms_p->mailstream, i + 1, &body);
2492 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
2493 char *attachment = body->nested.part->next->body.parameter->value;
2494 char copy[strlen(attachment) + 1];
2496 strcpy(copy, attachment);
2499 filename = strsep(&attachment,
".");
2500 if (!strcmp(filename, file)) {
2502 vms_p->msgArray[vms_p->curmsg] = i + 1;
2504 save_body(body, vms_p,
"2", attachment, 0);
2509 ast_log(AST_LOG_ERROR,
"There is no file attached to this IMAP message.\n");
2515 if (curr_mbox != -1) {
2517 if (init_mailstream(vms_p, curr_mbox) || !vms_p->mailstream) {
2518 ast_log(AST_LOG_ERROR,
"IMAP mailstream is NULL or can't init_mailstream\n");
2522 ast_mutex_unlock(&vms_p->lock);
2526 static int imap_retrieve_file(
const char *dir,
const int msgnum,
const char *mailbox,
const char *context)
2529 char *header_content;
2530 char *attachedfilefmt;
2533 char text_file[PATH_MAX];
2534 FILE *text_file_ptr;
2539 if (!(vmu =
find_user(NULL, context, mailbox))) {
2540 ast_log(LOG_WARNING,
"Couldn't find user with mailbox %s@%s\n", mailbox, context);
2545 if (imapgreetings) {
2546 res = imap_retrieve_greeting(dir, msgnum, vmu);
2557 if (!(vms = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 1)) && !(vms = get_vm_state_by_mailbox(vmu->
mailbox, vmu->
context, 0))) {
2565 ast_log(LOG_ERROR,
"Couldn't find a vm_state for mailbox %s!!! Oh no!\n", vmu->
mailbox);
2571 curr_mbox = get_folder_by_name(vms->curbox);
2572 if (curr_mbox < 0) {
2573 ast_debug(3,
"Mailbox folder curbox not set, defaulting to Inbox\n");
2576 init_mailstream(vms, curr_mbox);
2577 if (!vms->mailstream) {
2578 ast_log(AST_LOG_ERROR,
"IMAP mailstream for %s is NULL\n", vmu->
mailbox);
2583 make_file(vms->fn,
sizeof(vms->fn), dir, msgnum);
2584 snprintf(vms->introfn,
sizeof(vms->introfn),
"%sintro", vms->fn);
2592 ast_debug(3,
"Before mail_fetchheaders, curmsg is: %d, imap messages is %lu\n", msgnum, vms->msgArray[msgnum]);
2593 if (vms->msgArray[msgnum] == 0) {
2594 ast_log(LOG_WARNING,
"Trying to access unknown message\n");
2600 ast_mutex_lock(&vms->lock);
2601 header_content = mail_fetchheader (vms->mailstream, vms->msgArray[msgnum]);
2602 ast_mutex_unlock(&vms->lock);
2604 if (ast_strlen_zero(header_content)) {
2605 ast_log(LOG_ERROR,
"Could not fetch header for message number %ld\n", vms->msgArray[msgnum]);
2610 ast_mutex_lock(&vms->lock);
2611 mail_fetchstructure(vms->mailstream, vms->msgArray[msgnum], &body);
2612 ast_mutex_unlock(&vms->lock);
2615 if (body->nested.part && body->nested.part->next && body->nested.part->next->body.parameter->value) {
2616 attachedfilefmt =
ast_strdupa(body->nested.part->next->body.parameter->value);
2618 ast_log(LOG_ERROR,
"There is no file attached to this IMAP message.\n");
2625 strsep(&attachedfilefmt,
".");
2626 if (!attachedfilefmt) {
2627 ast_log(LOG_ERROR,
"File format could not be obtained from IMAP message attachment\n");
2632 save_body(body, vms,
"2", attachedfilefmt, 0);
2633 if (save_body(body, vms,
"3", attachedfilefmt, 1)) {
2634 *vms->introfn =
'\0';
2638 snprintf(text_file,
sizeof(text_file),
"%s.%s", vms->fn,
"txt");
2640 if (!(text_file_ptr = fopen(text_file,
"w"))) {
2641 ast_log(LOG_ERROR,
"Unable to open/create file %s: %s\n", text_file, strerror(errno));
2645 fprintf(text_file_ptr,
"%s\n",
"[message]");
2647 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Caller-ID-Name:", buf,
sizeof(buf))) {
2648 fprintf(text_file_ptr,
"callerid=\"%s\" ",
S_OR(buf,
""));
2650 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Caller-ID-Num:", buf,
sizeof(buf))) {
2651 fprintf(text_file_ptr,
"<%s>\n",
S_OR(buf,
""));
2653 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Context:", buf,
sizeof(buf))) {
2654 fprintf(text_file_ptr,
"context=%s\n",
S_OR(buf,
""));
2656 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Orig-time:", buf,
sizeof(buf))) {
2657 fprintf(text_file_ptr,
"origtime=%s\n",
S_OR(buf,
""));
2659 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Duration:", buf,
sizeof(buf))) {
2660 fprintf(text_file_ptr,
"duration=%s\n",
S_OR(buf,
""));
2662 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Category:", buf,
sizeof(buf))) {
2663 fprintf(text_file_ptr,
"category=%s\n",
S_OR(buf,
""));
2665 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Flag:", buf,
sizeof(buf))) {
2666 fprintf(text_file_ptr,
"flag=%s\n",
S_OR(buf,
""));
2668 if (get_header_by_tag(header_content,
"X-Asterisk-VM-Message-ID:", buf,
sizeof(buf))) {
2669 fprintf(text_file_ptr,
"msg_id=%s\n",
S_OR(buf,
""));
2671 fclose(text_file_ptr);
2678 static int folder_int(
const char *folder)
2684 if (!strcasecmp(folder, imapfolder)) {
2686 }
else if (!strcasecmp(folder,
"Old")) {
2688 }
else if (!strcasecmp(folder,
"Work")) {
2690 }
else if (!strcasecmp(folder,
"Family")) {
2692 }
else if (!strcasecmp(folder,
"Friends")) {
2694 }
else if (!strcasecmp(folder,
"Cust1")) {
2696 }
else if (!strcasecmp(folder,
"Cust2")) {
2698 }
else if (!strcasecmp(folder,
"Cust3")) {
2700 }
else if (!strcasecmp(folder,
"Cust4")) {
2702 }
else if (!strcasecmp(folder,
"Cust5")) {
2704 }
else if (!strcasecmp(folder,
"Urgent")) {
2711 static int __messagecount(
const char *context,
const char *mailbox,
const char *folder)
2719 int fold = folder_int(folder);
2728 if (ast_strlen_zero(mailbox))
2732 memset(&vmus, 0,
sizeof(vmus));
2733 vmu =
find_user(&vmus, context, mailbox);
2735 ast_log(AST_LOG_WARNING,
"Couldn't find mailbox %s in context %s\n", mailbox, context);
2740 if (vmu->imapuser[0] ==
'\0') {
2741 ast_log(AST_LOG_WARNING,
"IMAP user not set for mailbox %s\n", vmu->
mailbox);
2748 if (vmu->imapuser[0] ==
'\0') {
2749 ast_log(AST_LOG_WARNING,
"IMAP user not set for mailbox %s\n", vmu->
mailbox);
2755 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 1);
2757 vms_p = get_vm_state_by_mailbox(mailbox, context, 1);
2760 ast_debug(3,
"Returning before search - user is logged in\n");
2763 return urgent ? vms_p->urgentmessages : vms_p->newmessages;
2767 return vms_p->oldmessages;
2772 vms_p = get_vm_state_by_imapuser(vmu->imapuser, 0);
2774 vms_p = get_vm_state_by_mailbox(mailbox, context, 0);
2778 vms_p = create_vm_state_from_user(vmu);
2780 ret = init_mailstream(vms_p, fold);
2781 if (!vms_p->mailstream) {
2782 ast_log(AST_LOG_ERROR,
"Houston we have a problem - IMAP mailstream is NULL\n");
2787 ast_mutex_lock(&vms_p->lock);
2788 pgm = mail_newsearchpgm ();
2789 hdr = mail_newsearchheader (
"X-Asterisk-VM-Extension", (
char *)(!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
2790 hdr->next = mail_newsearchheader(
"X-Asterisk-VM-Context", (
char *)
S_OR(context,
"default"));
2792 if (fold != OLD_FOLDER) {
2804 if (fold == NEW_FOLDER) {
2816 vms_p->vmArrayIndex = 0;
2817 mail_search_full (vms_p->mailstream, NULL, pgm, NIL);
2818 if (fold == 0 && urgent == 0)
2819 vms_p->newmessages = vms_p->vmArrayIndex;
2821 vms_p->oldmessages = vms_p->vmArrayIndex;
2822 if (fold == 0 && urgent == 1)
2823 vms_p->urgentmessages = vms_p->vmArrayIndex;
2825 mail_free_searchpgm(&pgm);
2826 ast_mutex_unlock(&vms_p->lock);
2829 return vms_p->vmArrayIndex;
2831 ast_mutex_lock(&vms_p->lock);
2832 mail_ping(vms_p->mailstream);
2833 ast_mutex_unlock(&vms_p->lock);
2842 check_quota(vms, vmu->imapfolder);
2843 if (vms->quota_limit && vms->quota_usage >= vms->quota_limit) {
2844 ast_debug(1,
"*** QUOTA EXCEEDED!! %u >= %u\n", vms->quota_usage, vms->quota_limit);
2852 ast_debug(3,
"Checking message number quota: mailbox has %d messages, maximum is set to %d, current messages %d\n", msgnum, vmu->
maxmsg, inprocess_count(vmu->
mailbox, vmu->
context, 0));
2854 ast_log(LOG_WARNING,
"Unable to leave message since we will exceed the maximum number of messages allowed (%u >= %u)\n", msgnum, vmu->
maxmsg);
2873 static int messagecount(
const char *mailbox_id,
const char *folder)
2879 if (ast_strlen_zero(mailbox_id)
2880 || separate_mailbox(
ast_strdupa(mailbox_id), &mailbox, &context)) {
2884 if (ast_strlen_zero(folder) || !strcmp(folder,
"INBOX")) {
2885 count = __messagecount(context, mailbox,
"INBOX") + __messagecount(context, mailbox,
"Urgent");
2887 count = __messagecount(context, mailbox, folder);
2889 return count < 0 ? 0 : count;
2892 static int imap_store_file(
const char *dir,
const char *mailboxuser,
const char *mailboxcontext,
int msgnum,
struct ast_channel *chan,
struct ast_vm_user *vmu,
char *fmt,
int duration,
struct vm_state *vms,
const char *flag,
const char *msg_id)
2894 char *myserveremail = serveremail;
2896 char introfn[PATH_MAX];
2900 char tmp[80] =
"/tmp/astmail-XXXXXX";
2906 char *imap_flags = NIL;
2908 int box = NEW_FOLDER;
2910 snprintf(mailbox,
sizeof(mailbox),
"%s@%s", vmu->
mailbox, vmu->
context);
2911 msgcount = messagecount(mailbox,
"INBOX") + messagecount(mailbox,
"Old");
2915 if(!imapgreetings) {
2918 box = GREETINGS_FOLDER;
2922 if (imap_check_limits(chan, vms, vmu, msgcount)) {
2927 if (!ast_strlen_zero(flag) && !strcmp(flag,
"Urgent")) {
2928 ast_debug(3,
"Setting message flag \\\\FLAGGED.\n");
2929 imap_flags =
"\\FLAGGED";
2935 strsep(&stringp,
"|");
2945 snprintf(introfn,
sizeof(introfn),
"%sintro", fn);
2950 if (ast_strlen_zero(vmu->
email)) {
2960 if (!strcmp(fmt,
"wav49"))
2962 ast_debug(3,
"Storing file '%s', format '%s'\n", fn, fmt);
2967 ast_log(AST_LOG_WARNING,
"Unable to store '%s' (can't create temporary file)\n", fn);
2969 ast_free(vmu->
email);
2975 if (msgnum < 0 && imapgreetings) {
2976 if ((ret = init_mailstream(vms, GREETINGS_FOLDER))) {
2977 ast_log(AST_LOG_WARNING,
"Unable to open mailstream.\n");
2980 imap_delete_old_greeting(fn, vms);
2984 chan ?
S_COR(ast_channel_caller(chan)->
id.
number.valid, ast_channel_caller(chan)->
id.
number.str, NULL) : NULL,
2985 chan ?
S_COR(ast_channel_caller(chan)->
id.name.valid, ast_channel_caller(chan)->
id.name.str, NULL) : NULL,
2986 fn, introfn, fmt, duration, 1, chan, NULL, 1, flag, msg_id);
2991 ast_log(AST_LOG_ERROR,
"Can't allocate %ld bytes to read message\n", len + 1);
2994 *(vmu->
email) =
'\0';
2997 if (fread(buf, 1, len, p) != len) {
2999 ast_log(LOG_ERROR,
"Error while reading mail file: %s\n", tmp);
3003 ((
char *) buf)[len] =
'\0';
3004 INIT(&str, mail_string, buf, len);
3005 ret = init_mailstream(vms, box);
3007 imap_mailbox_name(mailbox,
sizeof(mailbox), vms, box, 1);
3008 ast_mutex_lock(&vms->lock);
3009 if(!mail_append_full(vms->mailstream, mailbox, imap_flags, NIL, &str))
3010 ast_log(LOG_ERROR,
"Error while sending the message to %s\n", mailbox);
3011 ast_mutex_unlock(&vms->lock);
3016 ast_log(LOG_ERROR,
"Could not initialize mailstream for %s\n", mailbox);
3025 *(vmu->
email) =
'\0';
3044 static int inboxcount2(
const char *mailbox_context,
int *urgentmsgs,
int *newmsgs,
int *oldmsgs)
3046 char tmp[PATH_MAX] =
"";
3059 ast_debug(3,
"Mailbox is set to %s\n", mailbox_context);
3061 if (ast_strlen_zero(mailbox_context))
3065 context = strchr(tmp,
'@');
3066 if (strchr(mailbox_context,
',')) {
3067 int tmpnew, tmpold, tmpurgent;
3070 while ((cur = strsep(&mb,
", "))) {
3071 if (!ast_strlen_zero(cur)) {
3072 if (
inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL))
3080 *urgentmsgs += tmpurgent;
3091 context =
"default";
3092 mailboxnc = (
char *) mailbox_context;
3098 ast_log(AST_LOG_ERROR,
"Couldn't find mailbox %s in context %s\n", mailboxnc, context);
3101 if ((count = __messagecount(context, mailboxnc, vmu->imapfolder)) < 0) {
3109 if ((count = __messagecount(context, mailboxnc,
"Old")) < 0) {
3115 if ((count = __messagecount(context, mailboxnc,
"Urgent")) < 0) {
3118 *urgentmsgs = count;
3133 static int has_voicemail(
const char *mailbox,
const char *folder)
3135 char tmp[256], *tmp2, *box, *
context;
3138 if (strchr(tmp2,
',') || strchr(tmp2,
'&')) {
3139 while ((box = strsep(&tmp2,
",&"))) {
3140 if (!ast_strlen_zero(box)) {
3147 if ((context = strchr(tmp,
'@'))) {
3150 context =
"default";
3152 return __messagecount(context, tmp, folder) > 0 ? 1 : 0;
3174 char messagestring[10];
3175 if (msgnum >= recip->
maxmsg) {
3176 ast_log(LOG_WARNING,
"Unable to copy mail, mailbox %s is full\n", recip->
mailbox);
3179 if (!(sendvms = get_vm_state_by_imapuser(vmu->imapuser, 0))) {
3180 ast_log(LOG_ERROR,
"Couldn't get vm_state for originator's mailbox!!\n");
3183 if (!get_vm_state_by_imapuser(recip->imapuser, 0)) {
3184 ast_log(LOG_ERROR,
"Couldn't get vm_state for destination mailbox!\n");
3187 snprintf(messagestring,
sizeof(messagestring),
"%ld", sendvms->msgArray[msgnum]);
3188 ast_mutex_lock(&sendvms->lock);
3189 if ((mail_copy(sendvms->mailstream, messagestring, (
char *) mbox(vmu, imbox)) == T)) {
3190 ast_mutex_unlock(&sendvms->lock);
3193 ast_mutex_unlock(&sendvms->lock);
3194 ast_log(LOG_WARNING,
"Unable to copy message from mailbox %s to mailbox %s\n", vmu->
mailbox, recip->
mailbox);
3198 static void imap_mailbox_name(
char *spec,
size_t len,
struct vm_state *vms,
int box,
int use_folder)
3200 char tmp[256], *t = tmp;
3201 size_t left =
sizeof(tmp);
3203 if (box == OLD_FOLDER) {
3204 ast_copy_string(vms->curbox, mbox(NULL, NEW_FOLDER),
sizeof(vms->curbox));
3209 if (box == NEW_FOLDER) {
3212 snprintf(vms->vmbox,
sizeof(vms->vmbox),
"vm-%s", mbox(NULL, box));
3219 if (!ast_strlen_zero(authuser))
3223 if (!ast_strlen_zero(imapflags) || !(ast_strlen_zero(vms->imapflags))) {
3233 if (box == NEW_FOLDER || box == OLD_FOLDER)
3234 snprintf(spec, len,
"%s%s", tmp, use_folder? vms->imapfolder:
"INBOX");
3235 else if (box == GREETINGS_FOLDER)
3236 snprintf(spec, len,
"%s%s", tmp, greetingfolder);
3238 if (!ast_strlen_zero(imapparentfolder)) {
3240 snprintf(spec, len,
"%s%s%c%s", tmp, imapparentfolder, delimiter, mbox(NULL, box));
3242 snprintf(spec, len,
"%s%s", tmp, mbox(NULL, box));
3247 static int init_mailstream(
struct vm_state *vms,
int box)
3249 MAILSTREAM *stream = NIL;
3254 ast_log(LOG_ERROR,
"vm_state is NULL!\n");
3257 ast_debug(3,
"vm_state user is:%s\n", vms->imapuser);
3258 if (vms->mailstream == NIL || !vms->mailstream) {
3261 stream = vms->mailstream;
3266 if (delimiter ==
'\0') {
3268 #ifdef USE_SYSTEM_IMAP
3269 #include <imap/linkage.c>
3270 #elif defined(USE_SYSTEM_CCLIENT)
3271 #include <c-client/linkage.c>
3273 #include "linkage.c"
3276 imap_mailbox_name(tmp,
sizeof(tmp), vms, 0, 1);
3277 ast_mutex_lock(&vms->lock);
3278 ast_mutex_lock(&mail_open_lock);
3279 stream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
3280 ast_mutex_unlock(&mail_open_lock);
3281 ast_mutex_unlock(&vms->lock);
3282 if (stream == NIL) {
3283 ast_log(LOG_ERROR,
"Can't connect to imap server %s\n", tmp);
3286 get_mailbox_delimiter(vms, stream);
3288 for (cp = vms->imapfolder; *cp; cp++)
3293 imap_mailbox_name(tmp,
sizeof(tmp), vms, box, 1);
3294 ast_debug(3,
"Before mail_open, server: %s, box:%d\n", tmp, box);
3295 ast_mutex_lock(&vms->lock);
3296 ast_mutex_lock(&mail_open_lock);
3297 vms->mailstream = mail_open (stream, tmp, debug ? OP_DEBUG : NIL);
3299 if (vms->mailstream && !mail_status(vms->mailstream, tmp, SA_UIDNEXT)) {
3300 mail_create(vms->mailstream, tmp);
3302 ast_mutex_unlock(&mail_open_lock);
3303 ast_mutex_unlock(&vms->lock);
3304 if (vms->mailstream == NIL) {
3324 ast_copy_string(vms->imapfolder, vmu->imapfolder,
sizeof(vms->imapfolder));
3325 ast_copy_string(vms->imapserver, vmu->imapserver,
sizeof(vms->imapserver));
3327 ast_copy_string(vms->imapflags, vmu->imapflags,
sizeof(vms->imapflags));
3328 vms->imapversion = vmu->imapversion;
3329 ast_debug(3,
"Before init_mailstream, user is %s\n", vmu->imapuser);
3331 if (init_mailstream(vms, box) || !vms->mailstream) {
3332 ast_log(AST_LOG_ERROR,
"Could not initialize mailstream\n");
3340 ast_debug(3,
"Mailbox name set to: %s, about to check quotas\n", mbox(vmu, box));
3341 check_quota(vms, (
char *) mbox(vmu, box));
3344 ast_mutex_lock(&vms->lock);
3345 pgm = mail_newsearchpgm();
3348 hdr = mail_newsearchheader(
"X-Asterisk-VM-Extension", (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : vmu->
mailbox));
3349 hdr->next = mail_newsearchheader(
"X-Asterisk-VM-Context", vmu->
context);
3355 if (box == NEW_FOLDER && urgent == 1) {
3360 }
else if (box == NEW_FOLDER && urgent == 0) {
3365 }
else if (box == OLD_FOLDER) {
3370 ast_debug(3,
"Before mail_search_full, user is %s\n", vmu->imapuser);
3372 vms->vmArrayIndex = 0;
3373 mail_search_full (vms->mailstream, NULL, pgm, NIL);
3374 vms->lastmsg = vms->vmArrayIndex - 1;
3375 mail_free_searchpgm(&pgm);
3380 if (box == 0 && !vms->dh_arraysize) {
3381 ast_log(LOG_WARNING,
"The code expects the old messages to be checked first, fix the code.\n");
3383 if (vm_allocate_dh(vms, vmu, box == 0 ? vms->vmArrayIndex + vms->oldmessages : vms->lastmsg)) {
3384 ast_mutex_unlock(&vms->lock);
3388 ast_mutex_unlock(&vms->lock);
3392 static void write_file(
char *filename,
char *buffer,
unsigned long len)
3396 if (!filename || !buffer) {
3400 if (!(output = fopen(filename,
"w"))) {
3401 ast_log(LOG_ERROR,
"Unable to open/create file %s: %s\n", filename, strerror(errno));
3405 if (fwrite(buffer, len, 1, output) != 1) {
3406 if (ferror(output)) {
3407 ast_log(LOG_ERROR,
"Short write while writing e-mail body: %s.\n", strerror(errno));
3413 static void update_messages_by_imapuser(
const char *
user,
unsigned long number)
3415 struct vm_state *vms = get_vm_state_by_imapuser(user, 1);
3417 if (!vms && !(vms = get_vm_state_by_imapuser(user, 0))) {
3421 ast_debug(3,
"saving mailbox message number %lu as message %d. Interactive set to %d\n", number, vms->vmArrayIndex, vms->interactive);
3424 if (vms->vmArrayIndex >= vms->msg_array_max) {
3425 long *new_mem =
ast_realloc(vms->msgArray, 2 * vms->msg_array_max *
sizeof(
long));
3429 vms->msgArray = new_mem;
3430 vms->msg_array_max *= 2;
3433 vms->msgArray[vms->vmArrayIndex++] = number;
3436 void mm_searched(MAILSTREAM *stream,
unsigned long number)
3438 char *mailbox = stream->mailbox, buf[1024] =
"", *user;
3440 if (!(user = get_user_by_mailbox(mailbox, buf,
sizeof(buf))))
3443 update_messages_by_imapuser(user, number);
3446 static struct ast_vm_user *find_user_realtime_imapuser(
const char *imapuser)
3458 var = ast_load_realtime(
"voicemail",
"imapuser", imapuser, NULL);
3471 void mm_exists(MAILSTREAM * stream,
unsigned long number)
3474 ast_debug(4,
"Entering EXISTS callback for message %ld\n", number);
3475 if (number == 0)
return;
3480 void mm_expunged(MAILSTREAM * stream,
unsigned long number)
3483 ast_debug(4,
"Entering EXPUNGE callback for message %ld\n", number);
3484 if (number == 0)
return;
3489 void mm_flags(MAILSTREAM * stream,
unsigned long number)
3492 ast_debug(4,
"Entering FLAGS callback for message %ld\n", number);
3493 if (number == 0)
return;
3498 void mm_notify(MAILSTREAM * stream,
char *
string,
long errflg)
3500 ast_debug(5,
"Entering NOTIFY callback, errflag is %ld, string is %s\n", errflg,
string);
3501 mm_log (
string, errflg);
3505 void mm_list(MAILSTREAM * stream,
int delim,
char *mailbox,
long attributes)
3507 if (delimiter ==
'\0') {
3511 ast_debug(5,
"Delimiter set to %c and mailbox %s\n", delim, mailbox);
3512 if (attributes & LATT_NOINFERIORS)
3514 if (attributes & LATT_NOSELECT)
3516 if (attributes & LATT_MARKED)
3518 if (attributes & LATT_UNMARKED)
3523 void mm_lsub(MAILSTREAM * stream,
int delim,
char *mailbox,
long attributes)
3525 ast_debug(5,
"Delimiter set to %c and mailbox %s\n", delim, mailbox);
3526 if (attributes & LATT_NOINFERIORS)
3528 if (attributes & LATT_NOSELECT)
3530 if (attributes & LATT_MARKED)
3532 if (attributes & LATT_UNMARKED)
3537 void mm_status(MAILSTREAM * stream,
char *mailbox, MAILSTATUS * status)
3546 if (status->flags & SA_MESSAGES) {
3549 if (status->flags & SA_RECENT) {
3552 if (status->flags & SA_UNSEEN) {
3555 if (status->flags & SA_UIDVALIDITY) {
3556 ast_str_append(&str, 0,
", %lu UID validity", status->uidvalidity);
3558 if (status->flags & SA_UIDNEXT) {
3567 void mm_log(
char *
string,
long errflg)
3569 switch ((
short) errflg) {
3571 ast_debug(1,
"IMAP Info: %s\n",
string);
3575 ast_log(AST_LOG_WARNING,
"IMAP Warning: %s\n",
string);
3578 ast_log(AST_LOG_ERROR,
"IMAP Error: %s\n",
string);
3584 void mm_dlog(
char *
string)
3586 ast_log(AST_LOG_NOTICE,
"%s\n",
string);
3590 void mm_login(NETMBX * mb,
char *user,
char *pwd,
long trial)
3594 ast_debug(4,
"Entering callback mm_login\n");
3599 if (!ast_strlen_zero(authpassword)) {
3603 if (!strcasecmp(mb->user, vmu->imapuser)) {
3609 if ((vmu = find_user_realtime_imapuser(mb->user))) {
3618 void mm_critical(MAILSTREAM * stream)
3623 void mm_nocritical(MAILSTREAM * stream)
3628 long mm_diskerror(MAILSTREAM * stream,
long errcode,
long serious)
3630 kill (getpid (), SIGSTOP);
3635 void mm_fatal(
char *
string)
3637 ast_log(AST_LOG_ERROR,
"IMAP access FATAL error: %s\n",
string);
3641 static void mm_parsequota(MAILSTREAM *stream,
unsigned char *msg, QUOTALIST *pquota)
3644 char *mailbox = stream->mailbox, *user;
3645 char buf[1024] =
"";
3646 unsigned long usage = 0, limit = 0;
3649 usage = pquota->usage;
3650 limit = pquota->limit;
3651 pquota = pquota->next;
3654 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)))) {
3655 ast_log(AST_LOG_ERROR,
"No state found.\n");
3659 ast_debug(3,
"User %s usage is %lu, limit is %lu\n", user, usage, limit);
3661 vms->quota_usage = usage;
3662 vms->quota_limit = limit;
3665 static char *get_header_by_tag(
char *
header,
char *tag,
char *buf,
size_t len)
3667 char *start, *eol_pnt;
3670 if (ast_strlen_zero(header) || ast_strlen_zero(tag))
3673 taglen = strlen(tag) + 1;
3677 if (!(start = strcasestr(header, tag)))
3681 memset(buf, 0, len);
3684 if ((eol_pnt = strchr(buf,
'\r')) || (eol_pnt = strchr(buf,
'\n')))
3689 static char *get_user_by_mailbox(
char *mailbox,
char *buf,
size_t len)
3691 char *start, *eol_pnt, *quote;
3693 if (ast_strlen_zero(mailbox))
3696 if (!(start = strstr(mailbox,
"/user=")))
3701 if (!(quote = strchr(buf,
'"'))) {
3702 if ((eol_pnt = strchr(buf,
'/')) || (eol_pnt = strchr(buf,
'}'))) {
3707 if ((eol_pnt = strchr(quote + 1,
'"'))) {
3718 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
3719 if ((vms_p = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms_p->imapuser, vmu->imapuser) && !strcmp(vms_p->username, vmu->
mailbox)) {
3722 ast_debug(5,
"Adding new vmstate for %s\n", vmu->imapuser);
3724 if (!(vms_p =
ast_calloc(1,
sizeof(*vms_p))))
3726 ast_copy_string(vms_p->imapuser, vmu->imapuser,
sizeof(vms_p->imapuser));
3727 ast_copy_string(vms_p->imapfolder, vmu->imapfolder,
sizeof(vms_p->imapfolder));
3728 ast_copy_string(vms_p->imapserver, vmu->imapserver,
sizeof(vms_p->imapserver));
3729 ast_copy_string(vms_p->imapport, vmu->imapport,
sizeof(vms_p->imapport));
3730 ast_copy_string(vms_p->imapflags, vmu->imapflags,
sizeof(vms_p->imapflags));
3733 vms_p->mailstream = NIL;
3734 vms_p->imapversion = vmu->imapversion;
3735 ast_debug(5,
"Copied %s to %s\n", vmu->imapuser, vms_p->imapuser);
3739 init_vm_state(vms_p);
3740 vmstate_insert(vms_p);
3744 static struct vm_state *get_vm_state_by_imapuser(
const char *user,
int interactive)
3746 struct vmstate *vlist = NULL;
3750 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
3751 if ((vms = pthread_getspecific(ts_vmstate.key)) && !strcmp(vms->imapuser, user)) {
3759 ast_debug(3,
"error: vms is NULL for %s\n", user);
3762 if (vlist->vms->imapversion != imapversion) {
3766 if (!strcmp(vlist->vms->imapuser, user) && (interactive == 2 || vlist->vms->interactive == interactive)) {
3773 ast_debug(3,
"%s not found in vmstates\n", user);
3778 static struct vm_state *get_vm_state_by_mailbox(
const char *mailbox,
const char *context,
int interactive)
3781 struct vmstate *vlist = NULL;
3782 const char *local_context =
S_OR(context,
"default");
3786 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
3787 if ((vms = pthread_getspecific(ts_vmstate.key)) &&
3788 !strcmp(vms->username,mailbox) && !strcmp(vms->context, local_context)) {
3796 ast_debug(3,
"error: vms is NULL for %s\n", mailbox);
3799 if (vlist->vms->imapversion != imapversion) {
3803 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);
3805 if (!strcmp(vlist->vms->username, mailbox) && !strcmp(vlist->vms->context, local_context) && vlist->vms->interactive == interactive) {
3813 ast_debug(3,
"%s not found in vmstates\n", mailbox);
3818 static void vmstate_insert(
struct vm_state *vms)
3826 if (vms->interactive == 1) {
3827 altvms = get_vm_state_by_mailbox(vms->username, vms->context, 0);
3829 ast_debug(3,
"Duplicate mailbox %s, copying message info...\n", vms->username);
3830 vms->newmessages = altvms->newmessages;
3831 vms->oldmessages = altvms->oldmessages;
3832 vms->vmArrayIndex = altvms->vmArrayIndex;
3834 vms->lastmsg = altvms->lastmsg;
3835 vms->curmsg = altvms->curmsg;
3837 vms->persist_vms = altvms;
3839 #ifdef REALLY_FAST_EVEN_IF_IT_MEANS_RESOURCE_LEAKS
3840 vms->mailstream = altvms->mailstream;
3842 vms->mailstream = NIL;
3853 ast_debug(3,
"Inserting vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
3860 static void vmstate_delete(
struct vm_state *vms)
3862 struct vmstate *vc = NULL;
3867 if (vms->interactive == 1 && (altvms = vms->persist_vms)) {
3868 ast_debug(3,
"Duplicate mailbox %s, copying message info...\n", vms->username);
3869 altvms->newmessages = vms->newmessages;
3870 altvms->oldmessages = vms->oldmessages;
3871 altvms->updated = 1;
3872 vms->mailstream = mail_close(vms->mailstream);
3878 ast_debug(3,
"Removing vm_state for user:%s, mailbox %s\n", vms->imapuser, vms->username);
3882 if (vc->vms == vms) {
3891 ast_mutex_destroy(&vc->vms->lock);
3892 ast_free(vc->vms->msgArray);
3893 vc->vms->msgArray = NULL;
3894 vc->vms->msg_array_max = 0;
3898 ast_log(AST_LOG_ERROR,
"No vmstate found for user:%s, mailbox %s\n", vms->imapuser, vms->username);
3902 static void set_update(MAILSTREAM * stream)
3905 char *mailbox = stream->mailbox, *user;
3906 char buf[1024] =
"";
3908 if (!(user = get_user_by_mailbox(mailbox, buf,
sizeof(buf))) || !(vms = get_vm_state_by_imapuser(user, 0))) {
3909 if (user && DEBUG_ATLEAST(3))
3910 ast_log(AST_LOG_WARNING,
"User %s mailbox not found for update.\n", user);
3914 ast_debug(3,
"User %s mailbox set for update.\n", user);
3919 static void init_vm_state(
struct vm_state *vms)
3921 vms->msg_array_max = VMSTATE_MAX_MSG_ARRAY;
3922 vms->msgArray =
ast_calloc(vms->msg_array_max,
sizeof(
long));
3923 if (!vms->msgArray) {
3925 vms->msg_array_max = 0;
3927 vms->vmArrayIndex = 0;
3928 ast_mutex_init(&vms->lock);
3931 static int save_body(BODY *body,
struct vm_state *vms,
char *section,
char *format,
int is_intro)
3935 char *fn = is_intro ? vms->introfn : vms->fn;
3936 unsigned long len = 0;
3937 unsigned long newlen = 0;
3940 if (!body || body == NIL)
3943 ast_mutex_lock(&vms->lock);
3944 body_content = mail_fetchbody(vms->mailstream, vms->msgArray[vms->curmsg], section, &len);
3945 ast_mutex_unlock(&vms->lock);
3946 if (len > MAX_MAIL_BODY_CONTENT_SIZE) {
3947 ast_log(AST_LOG_ERROR,
3948 "Msgno %ld, section %s. The body's content size %ld is huge (max %ld). User:%s, mailbox %s\n",
3949 vms->msgArray[vms->curmsg], section, len, MAX_MAIL_BODY_CONTENT_SIZE, vms->imapuser, vms->username);
3952 if (body_content != NIL && len) {
3953 snprintf(filename,
sizeof(filename),
"%s.%s", fn, format);
3955 body_decoded = rfc822_base64((
unsigned char *) body_content, len, &newlen);
3957 if (!newlen || !body_decoded) {
3960 write_file(filename, (
char *) body_decoded, newlen);
3962 ast_debug(5,
"Body of message is NULL.\n");
3976 static void get_mailbox_delimiter(
struct vm_state *vms, MAILSTREAM *stream) {
3978 snprintf(tmp,
sizeof(tmp),
"{%s}",
S_OR(vms->imapserver, imapserver));
3979 mail_list(stream, tmp,
"*");
3989 static void check_quota(
struct vm_state *vms,
char *mailbox) {
3990 ast_mutex_lock(&vms->lock);
3991 mail_parameters(NULL, SET_QUOTA, (
void *) mm_parsequota);
3992 ast_debug(3,
"Mailbox name set to: %s, about to check quotas\n", mailbox);
3993 if (vms && vms->mailstream != NULL) {
3994 imap_getquotaroot(vms->mailstream, mailbox);
3996 ast_log(AST_LOG_WARNING,
"Mailstream not available for mailbox: %s\n", mailbox);
3998 ast_mutex_unlock(&vms->lock);
4010 case AST_LOCK_TIMEOUT:
4017 #define MSG_ID_LEN 256
4020 static int msg_id_incrementor;
4040 #define MAKE_SQL_PTRA(__sql_fmt) \
4043 char *__sql = ast_alloca(strlen(__sql_fmt) + odbc_table_len); \
4044 sprintf(__sql, __sql_fmt, odbc_table); \
4058 #define MAKE_SQL_PTRA2(__sql_fmt) \
4061 char *__sql = ast_alloca(strlen(__sql_fmt) + (odbc_table_len * 2)); \
4062 sprintf(__sql, __sql_fmt, odbc_table, odbc_table); \
4066 struct generic_prepare_struct {
4072 static SQLHSTMT generic_prepare(
struct odbc_obj *obj,
void *data)
4074 struct generic_prepare_struct *gps = data;
4078 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->
con, &stmt);
4079 if (!SQL_SUCCEEDED(res)) {
4080 ast_log(AST_LOG_WARNING,
"SQL Alloc Handle failed!\n");
4084 if (!SQL_SUCCEEDED(res)) {
4085 ast_log(AST_LOG_WARNING,
"SQL Prepare failed![%s]\n", gps->sql);
4086 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4089 for (i = 0; i < gps->argc; i++)
4090 SQLBindParameter(stmt, i + 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(gps->argv[i]), 0, gps->argv[i], 0, NULL);
4095 static void odbc_update_msg_id(
char *dir,
int msg_num,
char *msg_id)
4098 char *sql = MAKE_SQL_PTRA(
"UPDATE %s SET msg_id=? WHERE dir=? AND msgnum=?");
4100 char msg_num_str[20];
4101 char *argv[] = { msg_id, dir, msg_num_str };
4102 struct generic_prepare_struct gps = { .sql = sql, .argc = 3, .argv = argv };
4103 SCOPE_ENTER(3,
"dir: %s msg_num: %d msg_id: %s\n", dir, msg_num, msg_id);
4107 SCOPE_EXIT_LOG_RTN(LOG_WARNING,
"Unable to update message ID for message %d in %s\n", msg_num, dir);
4110 snprintf(msg_num_str,
sizeof(msg_num_str),
"%d", msg_num);
4113 ast_log(LOG_WARNING,
"SQL Execute error!\n[%s]\n\n", sql);
4115 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4121 #define AUDIO_ON_DISK_MAGIC "AUDMAGIC"
4122 #define AUDIO_ON_DISK_MAGIC_LEN 8
4124 static void odbc_update_set_audmagic(
char *dir,
int msg_num)
4127 char *sql = MAKE_SQL_PTRA(
"UPDATE %s SET recording=? WHERE dir=? AND msgnum=?");
4129 SQLLEN datalen = AUDIO_ON_DISK_MAGIC_LEN;
4130 SQLLEN indlen = datalen;
4132 char msg_num_str[20];
4133 SCOPE_ENTER(3,
"dir: %s msg_num: %d\n", dir, msg_num);
4137 SCOPE_EXIT_LOG_RTN(LOG_WARNING,
"Unable to request obj for message %d in %s\n", msg_num, dir);
4140 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->
con, &stmt);
4141 if (!SQL_SUCCEEDED(res)) {
4143 SCOPE_EXIT_LOG_RTN(LOG_WARNING,
"Unable to allocate stmt for message %d in %s\n", msg_num, dir);
4146 snprintf(msg_num_str,
sizeof(msg_num_str),
"%d", msg_num);
4148 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY,
4149 datalen, 0, (
void *) AUDIO_ON_DISK_MAGIC,
4152 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR,
4153 strlen(dir), 0, (
void *) dir, 0, NULL);
4155 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR,
4156 strlen(msg_num_str), 0, (
void *) msg_num_str, 0, NULL);
4159 if (!SQL_SUCCEEDED(res)) {
4160 ast_log(LOG_WARNING,
"Unable to execute stmt for message %d in %s\n", msg_num, dir);
4163 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4167 SCOPE_EXIT_RTN(
"Done\n");
4170 static int odbc_store_message(
const char *dir,
const char *mailboxuser,
const char *mailboxcontext,
int msgnum);
4186 static int odbc_retrieve_message(
char *dir,
int msgnum)
4192 void *fdm = MAP_FAILED;
4193 SQLSMALLINT colcount = 0;
4195 char *sql = MAKE_SQL_PTRA(
"SELECT * FROM %s WHERE dir=? AND msgnum=?");
4200 SQLSMALLINT datatype;
4201 SQLSMALLINT decimaldigits;
4202 SQLSMALLINT nullable;
4207 char *fn = MAKE_FILE_PTRA(dir, msgnum);
4208 char *full_fn = MAKE_FILE_EXT_PTRA(dir, msgnum,
"txt");
4210 char *mailboxuser = NULL;
4211 char *mailboxcontext = NULL;
4212 char msg_id[MSG_ID_LEN] =
"";
4213 char *argv[] = { dir, msgnums };
4214 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
4216 int storage_conversion_to_disk = 0;
4217 int storage_conversion_to_odbc = 0;
4218 SCOPE_ENTER(3,
"dir: %s msgnum: %d msgtype: %s\n", dir, msgnum, msgnum < 0 ?
"Greeting" :
"Message");
4222 SCOPE_EXIT_LOG_RTN_VALUE(-1, AST_LOG_WARNING,
"Failed to obtain database object for '%s'!\n", odbc_database);
4226 c = strchr(fmt,
'|');
4229 if (!strcasecmp(fmt,
"wav49"))
4232 snprintf(msgnums,
sizeof(msgnums),
"%d", msgnum);
4234 ast_trace(-1,
"Opening '%s' for writing\n", full_fn);
4235 if (!(f = fopen(full_fn,
"w+"))) {
4236 ast_log(AST_LOG_WARNING,
"Failed to open/create '%s'\n", full_fn);
4240 sprintf(full_fn,
"%s.%s", fn, fmt);
4244 ast_log(AST_LOG_WARNING,
"SQL Execute error!\n[%s]\n\n", sql);
4248 res = SQLFetch(stmt);
4249 if (!SQL_SUCCEEDED(res)) {
4250 if (res != SQL_NO_DATA) {
4251 ast_log(AST_LOG_WARNING,
"SQL Fetch error!\n[%s]\n\n", sql);
4253 goto bail_with_handle;
4256 res = SQLNumResultCols(stmt, &colcount);
4257 if (!SQL_SUCCEEDED(res)) {
4258 ast_log(AST_LOG_WARNING,
"SQL Column Count error!\n[%s]\n\n", sql);
4259 goto bail_with_handle;
4262 fprintf(f,
"[message]\n");
4263 for (x = 0; x < colcount; x++) {
4266 collen =
sizeof(coltitle);
4267 res = SQLDescribeCol(stmt, x + 1, (
unsigned char *) coltitle,
sizeof(coltitle), &collen,
4268 &datatype, &colsize, &decimaldigits, &nullable);
4269 if (!SQL_SUCCEEDED(res)) {
4270 ast_log(AST_LOG_WARNING,
"SQL Describe Column error!\n[%s]\n\n", sql);
4271 goto bail_with_handle;
4274 if (!strcasecmp(coltitle,
"recording")) {
4278 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, 0, &colsize2);
4280 ast_trace(-1,
"Audio size: %ld\n", colsize2);
4281 if (colsize2 == AUDIO_ON_DISK_MAGIC_LEN) {
4282 res = SQLGetData(stmt, x + 1, SQL_BINARY, rowdata, AUDIO_ON_DISK_MAGIC_LEN, NULL);
4283 if (memcmp(rowdata, AUDIO_ON_DISK_MAGIC, AUDIO_ON_DISK_MAGIC_LEN) != 0) {
4284 ast_log(AST_LOG_WARNING,
"Invalid audio magic number '0x%02X%02X%02X%02X%02X%02X%02X%02X' for '%s'\n",
4285 rowdata[0], rowdata[1], rowdata[2], rowdata[3], rowdata[4], rowdata[5], rowdata[6],
4286 rowdata[7], full_fn);
4287 goto bail_with_handle;
4289 ast_trace(-1,
"Audio is stored on disk. No need to write '%s'\n", full_fn);
4291 storage_conversion_to_odbc = 1;
4297 ast_trace(-1,
"Opening '%s' for writing\n", full_fn);
4298 fd = open(full_fn, O_RDWR | O_CREAT | O_TRUNC, VOICEMAIL_FILE_MODE);
4300 ast_log(AST_LOG_WARNING,
"Failed to open '%s' for writing: %s\n", full_fn, strerror(errno));
4301 goto bail_with_handle;
4304 storage_conversion_to_disk = 1;
4307 lseek(fd, fdlen - 1, SEEK_SET);
4308 if (write(fd, tmp, 1) != 1) {
4314 for (offset = 0; offset < colsize2; offset += CHUNKSIZE) {
4315 if ((fdm = mmap(NULL, CHUNKSIZE, PROT_READ | PROT_WRITE, MAP_SHARED, fd, offset)) == MAP_FAILED) {
4316 ast_log(AST_LOG_WARNING,
"Could not mmap the output file: %s (%d)\n", strerror(errno), errno);
4317 goto bail_with_handle;
4319 res = SQLGetData(stmt, x + 1, SQL_BINARY, fdm, CHUNKSIZE, NULL);
4320 munmap(fdm, CHUNKSIZE);
4321 if (!SQL_SUCCEEDED(res)) {
4322 ast_log(AST_LOG_WARNING,
"SQL Get Data error!\n[%s]\n\n", sql);
4324 goto bail_with_handle;
4327 if (truncate(full_fn, fdlen) < 0) {
4328 ast_log(LOG_WARNING,
"Unable to truncate '%s': %s\n", full_fn, strerror(errno));
4330 ast_trace(-1,
"Wrote %d bytes to '%s'\n", (
int)fdlen, full_fn);
4332 res = SQLGetData(stmt, x + 1, SQL_CHAR, rowdata,
sizeof(rowdata), NULL);
4333 if (res == SQL_NULL_DATA && !strcasecmp(coltitle,
"msg_id")) {
4339 ast_trace(-1,
"msg_id was NULL. Generating new one: %s\n", msg_id);
4340 snprintf(rowdata,
sizeof(rowdata),
"%s", msg_id);
4341 }
else if (!strcasecmp(coltitle,
"mailboxuser")) {
4343 }
else if (!strcasecmp(coltitle,
"mailboxcontext")) {
4345 }
else if (res == SQL_NULL_DATA && !strcasecmp(coltitle,
"category")) {
4347 ast_trace(-1,
"Ignoring null category column in ODBC voicemail retrieve_file.\n");
4349 }
else if (!SQL_SUCCEEDED(res)) {
4350 ast_log(AST_LOG_WARNING,
"SQL Get Data error! coltitle=%s\n[%s]\n\n", coltitle, sql);
4351 goto bail_with_handle;
4353 if (strcasecmp(coltitle,
"msgnum") && strcasecmp(coltitle,
"dir")) {
4354 fprintf(f,
"%s=%s\n", coltitle, rowdata);
4360 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4373 if (!ast_strlen_zero(msg_id)) {
4374 odbc_update_msg_id(dir, msgnum, msg_id);
4377 if (SQL_SUCCEEDED(res)) {
4378 if (storage_conversion_to_disk) {
4384 SCOPE_CALL(-1, odbc_update_set_audmagic, dir, msgnum);
4386 if (storage_conversion_to_odbc) {
4393 SCOPE_CALL(-1, odbc_store_message, dir, mailboxuser, mailboxcontext, msgnum);
4397 SCOPE_EXIT_RTN_VALUE(x - 1,
"Done. msg_id: %s RC: %d\n", msg_id, x - 1);
4409 static int odbc_last_message_index(
char *dir)
4414 char *sql = MAKE_SQL_PTRA(
"SELECT msgnum FROM %s WHERE dir=? order by msgnum desc");
4416 char *argv[] = { dir };
4417 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
4419 SCOPE_ENTER(3,
"dir: %s\n", dir);
4423 SCOPE_EXIT_LOG_RTN_VALUE(-1, AST_LOG_WARNING,
"Failed to obtain database object for '%s'!\n", odbc_database);
4428 ast_log(AST_LOG_WARNING,
"SQL Execute error!\n[%s]\n\n", sql);
4432 res = SQLFetch(stmt);
4433 if (!SQL_SUCCEEDED(res)) {
4434 if (res == SQL_NO_DATA) {
4435 ast_trace(-1,
"Directory '%s' has no messages and therefore no index was retrieved.\n", dir);
4437 ast_log(AST_LOG_WARNING,
"SQL Fetch error!\n[%s]\n\n", sql);
4439 goto bail_with_handle;
4442 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata,
sizeof(rowdata), NULL);
4443 if (!SQL_SUCCEEDED(res)) {
4444 ast_log(AST_LOG_WARNING,
"SQL Get Data error!\n[%s]\n\n", sql);
4445 goto bail_with_handle;
4448 if (sscanf(rowdata,
"%30d", &x) != 1) {
4449 ast_log(AST_LOG_WARNING,
"Failed to read message index!\n");
4453 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4458 SCOPE_EXIT_RTN_VALUE(x,
"Done. Last message index: %d\n", x);
4470 static int odbc_message_exists(
char *dir,
int msgnum)
4475 char *sql = MAKE_SQL_PTRA(
"SELECT COUNT(*) FROM %s WHERE dir=? AND msgnum=?");
4478 char *argv[] = { dir, msgnums };
4479 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
4481 SCOPE_ENTER(3,
"dir: %s msgnum: %d\n", dir, msgnum);
4485 SCOPE_EXIT_LOG_RTN_VALUE(0, AST_LOG_WARNING,
"Failed to obtain database object for '%s'!\n", odbc_database);
4488 snprintf(msgnums,
sizeof(msgnums),
"%d", msgnum);
4491 ast_log(AST_LOG_WARNING,
"SQL Execute error!\n[%s]\n\n", sql);
4495 res = SQLFetch(stmt);
4496 if (!SQL_SUCCEEDED(res)) {
4497 ast_log(AST_LOG_WARNING,
"SQL Fetch error!\n[%s]\n\n", sql);
4498 goto bail_with_handle;
4501 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata,
sizeof(rowdata), NULL);
4502 if (!SQL_SUCCEEDED(res)) {
4503 ast_log(AST_LOG_WARNING,
"SQL Get Data error!\n[%s]\n\n", sql);
4504 goto bail_with_handle;
4507 if (sscanf(rowdata,
"%30d", &x) != 1) {
4508 ast_log(AST_LOG_WARNING,
"Failed to read message count!\n");
4512 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4516 SCOPE_EXIT_RTN_VALUE(x,
"Done. Msg %s\n", x ?
"exists" :
"does not exist");
4528 static int odbc_count_messages(
struct ast_vm_user *vmu,
char *dir)
4533 char *sql = MAKE_SQL_PTRA(
"SELECT COUNT(*) FROM %s WHERE dir=?");
4535 char *argv[] = { dir };
4536 struct generic_prepare_struct gps = { .sql = sql, .argc = 1, .argv = argv };
4538 SCOPE_ENTER(3,
"dir: %s\n", dir);
4542 SCOPE_EXIT_LOG_RTN_VALUE(-1, AST_LOG_WARNING,
"Failed to obtain database object for '%s'!\n", odbc_database);
4547 ast_log(AST_LOG_WARNING,
"SQL Execute error!\n[%s]\n\n", sql);
4551 res = SQLFetch(stmt);
4552 if (!SQL_SUCCEEDED(res)) {
4553 ast_log(AST_LOG_WARNING,
"SQL Fetch error!\n[%s]\n\n", sql);
4554 goto bail_with_handle;
4557 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata,
sizeof(rowdata), NULL);
4558 if (!SQL_SUCCEEDED(res)) {
4559 ast_log(AST_LOG_WARNING,
"SQL Get Data error!\n[%s]\n\n", sql);
4560 goto bail_with_handle;
4563 if (sscanf(rowdata,
"%30d", &x) != 1) {
4564 ast_log(AST_LOG_WARNING,
"Failed to read message count!\n");
4568 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4572 SCOPE_EXIT_RTN_VALUE(x,
"Done. Count %d\n", x);
4583 #define DELETE_SQL_FMT "DELETE FROM %s WHERE dir=? AND msgnum=?"
4584 static void odbc_delete_message(
const char *sdir,
int smsg)
4587 char *sql = MAKE_SQL_PTRA(DELETE_SQL_FMT);
4589 char *argv[] = { NULL, msgnums };
4590 struct generic_prepare_struct gps = { .sql = sql, .argc = 2, .argv = argv };
4592 SCOPE_ENTER(3,
"sdir: %s smsg: %d\n", sdir, smsg);
4596 SCOPE_EXIT_LOG_RTN(AST_LOG_WARNING,
"Failed to obtain database object for '%s'!\n", odbc_database);
4601 snprintf(msgnums,
sizeof(msgnums),
"%d", smsg);
4604 ast_log(AST_LOG_WARNING,
"SQL Execute error!\n[%s]\n\n", sql);
4606 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4611 char *src_fn = MAKE_FILE_PTRA(sdir, smsg);
4612 ast_trace(-1,
"Audio stored on disk. Deleting '%s'\n", src_fn);
4616 SCOPE_EXIT_RTN(
"Done\n");
4630 #define COPY_SQL_FMT "INSERT INTO %s (dir, msgnum, msg_id, context, callerid, origtime, " \
4631 "duration, recording, flag, mailboxuser, mailboxcontext) " \
4632 "SELECT ?,?,msg_id,context,callerid,origtime,duration,recording,flag,?,? " \
4633 "FROM %s WHERE dir=? AND msgnum=?"
4634 static void odbc_copy_message(
char *sdir,
int smsg,
char *ddir,
int dmsg,
char *dmailboxuser,
char *dmailboxcontext)
4637 char *sql = MAKE_SQL_PTRA2(COPY_SQL_FMT);
4641 char *argv[] = { ddir, msgnumd, dmailboxuser, dmailboxcontext, sdir, msgnums };
4642 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
4643 SCOPE_ENTER(3,
"sdir: %s smsg: %d duser: %s dcontext: %s ddir: %s dmsg: %d\n",
4644 sdir, smsg, dmailboxuser, dmailboxcontext, ddir, dmsg);
4646 SCOPE_CALL(-1, odbc_delete_message, ddir, dmsg);
4650 SCOPE_EXIT_LOG_RTN(AST_LOG_WARNING,
"Failed to obtain database object for '%s'!\n", odbc_database);
4653 snprintf(msgnums,
sizeof(msgnums),
"%d", smsg);
4654 snprintf(msgnumd,
sizeof(msgnumd),
"%d", dmsg);
4658 ast_log(AST_LOG_WARNING,
"SQL Execute error!\n[%s] (You probably don't have MySQL 4.1 or later installed)\n\n", sql);
4660 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4664 char *src_fn = MAKE_FILE_PTRA(sdir, smsg);
4665 char *dst_fn = MAKE_FILE_PTRA(ddir, dmsg);
4667 ast_trace(-1,
"Audio stored on disk. Copying '%s' to '%s'\n", src_fn, dst_fn);
4671 SCOPE_EXIT_RTN(
"Done\n");
4675 struct insert_data {
4677 const char *msgnums;
4681 const char *context;
4682 const char *callerid;
4683 const char *origtime;
4684 const char *duration;
4685 const char *mailboxuser;
4686 const char *mailboxcontext;
4687 const char *category;
4692 #define STORE_SQL_FMT_CAT "INSERT INTO %s (dir, msgnum, recording, context, callerid, " \
4693 "origtime, duration, mailboxuser, mailboxcontext, flag, msg_id, category) " \
4694 "VALUES (?,?,?,?,?,?,?,?,?,?,?,?)"
4695 #define STORE_SQL_FMT "INSERT INTO %s (dir, msgnum, recording, context, callerid, "\
4696 "origtime, duration, mailboxuser, mailboxcontext, flag, msg_id) "\
4697 "VALUES (?,?,?,?,?,?,?,?,?,?,?)"
4699 static SQLHSTMT odbc_insert_data_cb(
struct odbc_obj *obj,
void *vdata)
4701 struct insert_data *data = vdata;
4706 SCOPE_ENTER(3,
"dir: %s msgnums: %s msg_id: %s\n", data->dir, data->msgnums,
4709 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->
con, &stmt);
4710 if (!SQL_SUCCEEDED(res)) {
4711 SCOPE_EXIT_LOG_RTN_VALUE(NULL, AST_LOG_WARNING,
"SQL Alloc Handle failed!\n");
4715 delete_sql = MAKE_SQL_PTRA(DELETE_SQL_FMT);
4716 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->dir), 0, (
void *) data->dir, 0, NULL);
4717 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msgnums), 0, (
void *) data->msgnums, 0, NULL);
4719 if (!SQL_SUCCEEDED(res)) {
4720 ast_trace(-1,
"There wasn't an existing row. Good.\n");
4722 ast_trace(-1,
"There WAS an existing row. This is OK if we're replacing a message.\n");
4724 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4727 res = SQLAllocHandle(SQL_HANDLE_STMT, obj->
con, &stmt);
4728 if (!SQL_SUCCEEDED(res)) {
4729 SCOPE_EXIT_LOG_RTN_VALUE(NULL, AST_LOG_WARNING,
"SQL Alloc Handle failed!\n");
4732 SQLBindParameter(stmt, 1, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->dir), 0, (
void *) data->dir, 0, NULL);
4733 SQLBindParameter(stmt, 2, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msgnums), 0, (
void *) data->msgnums, 0, NULL);
4734 SQLBindParameter(stmt, 3, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_LONGVARBINARY, data->datalen, 0, (
void *) data->data, data->datalen, &data->indlen);
4735 SQLBindParameter(stmt, 4, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->context), 0, (
void *) data->context, 0, NULL);
4736 SQLBindParameter(stmt, 5, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->callerid), 0, (
void *) data->callerid, 0, NULL);
4737 SQLBindParameter(stmt, 6, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->origtime), 0, (
void *) data->origtime, 0, NULL);
4738 SQLBindParameter(stmt, 7, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->duration), 0, (
void *) data->duration, 0, NULL);
4739 SQLBindParameter(stmt, 8, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxuser), 0, (
void *) data->mailboxuser, 0, NULL);
4740 SQLBindParameter(stmt, 9, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->mailboxcontext), 0, (
void *) data->mailboxcontext, 0, NULL);
4741 SQLBindParameter(stmt, 10, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->flag), 0, (
void *) data->flag, 0, NULL);
4742 SQLBindParameter(stmt, 11, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->msg_id), 0, (
void *) data->msg_id, 0, NULL);
4743 if (!ast_strlen_zero(data->category)) {
4744 insert_sql = MAKE_SQL_PTRA(STORE_SQL_FMT_CAT);
4745 SQLBindParameter(stmt, 12, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_CHAR, strlen(data->category), 0, (
void *) data->category, 0, NULL);
4747 insert_sql = MAKE_SQL_PTRA(STORE_SQL_FMT);
4750 if (!SQL_SUCCEEDED(res)) {
4751 ast_log(AST_LOG_WARNING,
"SQL Execute error!\n[%s]\n", insert_sql);
4753 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4757 SCOPE_EXIT_RTN_VALUE(stmt,
"%s\n", stmt ?
"Success" :
"Failed");
4773 static int odbc_store_message(
const char *dir,
const char *mailboxuser,
const char *mailboxcontext,
int msgnum)
4777 void *fdm = MAP_FAILED;
4781 char *fn = MAKE_FILE_PTRA(dir, msgnum);
4782 char *full_fn = MAKE_FILE_EXT_PTRA(dir, msgnum,
"txt");
4787 struct insert_data idata = { .msgnums = msgnums, .dir = dir, .mailboxuser = mailboxuser, .mailboxcontext = mailboxcontext,
4788 .context =
"", .callerid =
"", .origtime =
"", .duration =
"", .category =
"", .flag =
"", .msg_id =
"" };
4790 SCOPE_ENTER(3,
"dir: %s user: %s context: %s msgnum: %d msgtype: %s\n",
4791 dir, mailboxuser, mailboxcontext, msgnum, msgnum < 0 ?
"Greeting" :
"Message");
4795 SCOPE_EXIT_LOG_RTN_VALUE(-1, AST_LOG_WARNING,
"Failed to obtain database object for '%s'!\n", odbc_database);
4800 c = strchr(fmt,
'|');
4803 if (!strcasecmp(fmt,
"wav49"))
4806 ast_trace(-1,
"Formats: %s Using format: '%s'\n", vmfmts, fmt);
4807 snprintf(msgnums,
sizeof(msgnums),
"%d", msgnum);
4809 ast_trace(-1,
"Base path: '%s'\n", fn);
4810 ast_trace(-1,
"Opening '%s'\n", full_fn);
4814 ast_trace(-1,
"No information file found for '%s'. This is a greeting so this is OK.\n", full_fn);
4816 ast_log(AST_LOG_WARNING,
"Failed to open '%s'\n", full_fn);
4822 sprintf(full_fn,
"%s.%s", fn, fmt);
4824 ast_trace(-1,
"Audio stored on disk. No need to open '%s'\n", full_fn);
4826 ast_trace(-1,
"Opening '%s'\n", full_fn);
4827 fd = open(full_fn, O_RDWR);
4829 ast_log(AST_LOG_WARNING,
"Open of sound file '%s' failed: %s\n", full_fn, strerror(errno));
4836 ast_trace(-1,
"Using information file '%s'\n", fn);
4837 if (!(idata.context = ast_variable_retrieve(cfg,
"message",
"context"))) {
4840 if (!(idata.callerid = ast_variable_retrieve(cfg,
"message",
"callerid"))) {
4841 idata.callerid =
"";
4843 if (!(idata.origtime = ast_variable_retrieve(cfg,
"message",
"origtime"))) {
4844 idata.origtime =
"";
4846 if (!(idata.duration = ast_variable_retrieve(cfg,
"message",
"duration"))) {
4847 idata.duration =
"";
4849 if (!(idata.category = ast_variable_retrieve(cfg,
"message",
"category"))) {
4850 idata.category =
"";
4852 if (!(idata.flag = ast_variable_retrieve(cfg,
"message",
"flag"))) {
4855 if (!(idata.msg_id = ast_variable_retrieve(cfg,
"message",
"msg_id"))) {
4861 ast_trace(-1,
"Audio stored on disk. Not reading sound file '%s' but setting magic number.\n", full_fn);
4862 idata.data = AUDIO_ON_DISK_MAGIC;
4863 idata.datalen = idata.indlen = AUDIO_ON_DISK_MAGIC_LEN;
4865 ast_trace(-1,
"Reading sound file '%s'\n", full_fn);
4866 fdlen = lseek(fd, 0, SEEK_END);
4867 if (fdlen < 0 || lseek(fd, 0, SEEK_SET) < 0) {
4868 ast_log(AST_LOG_WARNING,
"Failed to process sound file '%s': %s\n", full_fn, strerror(errno));
4872 fdm = mmap(NULL, fdlen, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
4873 if (fdm == MAP_FAILED) {
4874 ast_log(AST_LOG_WARNING,
"Memory map failed for sound file '%s'!\n", full_fn);
4879 idata.datalen = idata.indlen = fdlen;
4882 if (ast_strlen_zero(idata.origtime)) {
4883 idata.origtime =
"0";
4886 if (ast_strlen_zero(idata.duration)) {
4887 idata.duration =
"0";
4891 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4901 if (fdm != MAP_FAILED)
4905 SCOPE_EXIT_RTN_VALUE(res,
"%s\n", res ?
"Failed" :
"Success");
4907 #undef STORE_SQL_FMT
4908 #undef STORE_SQL_FMT_CAT
4923 static void odbc_rename_message(
char *sdir,
int smsg,
char *mailboxuser,
char *mailboxcontext,
char *ddir,
int dmsg)
4926 char *sql = MAKE_SQL_PTRA(
"UPDATE %s SET dir=?, msgnum=? WHERE mailboxuser=? AND mailboxcontext=? AND dir=? AND msgnum=?");
4930 char *argv[] = { ddir, msgnumd, mailboxuser, mailboxcontext, sdir, msgnums };
4931 struct generic_prepare_struct gps = { .sql = sql, .argc = 6, .argv = argv };
4932 SCOPE_ENTER(3,
"sdir: %s smsg: %d user: %s context: %s ddir: %s dmsg: %d\n", sdir, smsg,
4933 mailboxuser, mailboxcontext, ddir, dmsg);
4935 SCOPE_CALL(-1, odbc_delete_message, ddir, dmsg);
4939 SCOPE_EXIT_LOG_RTN(AST_LOG_WARNING,
"Failed to obtain database object for '%s'!\n", odbc_database);
4942 snprintf(msgnums,
sizeof(msgnums),
"%d", smsg);
4943 snprintf(msgnumd,
sizeof(msgnumd),
"%d", dmsg);
4947 ast_log(AST_LOG_WARNING,
"SQL Execute error!\n[%s]\n\n", sql);
4949 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
4953 char *src_fn = MAKE_FILE_PTRA(sdir, smsg);
4954 char *dst_fn = MAKE_FILE_PTRA(ddir, dmsg);
4956 ast_trace(-1,
"Recordings stored on disk. Renaming '%s' to '%s'\n", src_fn, dst_fn);
4960 SCOPE_EXIT_RTN(
"Done.\n");
4974 static int odbc_remove_files(
char *dir,
int msgnum)
4976 char *fn = MAKE_FILE_PTRA(dir, msgnum);
4977 char *full_fn = MAKE_FILE_EXT_PTRA(dir, msgnum,
"txt");
4978 SCOPE_ENTER(3,
"dir: %s msgnum: %d\n", dir, msgnum);
4981 ast_trace(-1,
"Audio stored on disk. Keeping '%s' sound files\n", fn);
4983 ast_trace(-1,
"Audio stored in ODBC. Removing '%s' sound files\n", fn);
4988 ast_trace(-1,
"Removing '%s' information file\n", full_fn);
4990 SCOPE_EXIT_RTN_VALUE(0,
"Done.\n");
4993 #ifndef IMAP_STORAGE
5008 struct dirent *vment = NULL;
5011 return ERROR_LOCK_PATH;
5013 if ((vmdir = opendir(dir))) {
5014 while ((vment = readdir(vmdir))) {
5015 if (strlen(vment->d_name) > 7 && !strncmp(vment->d_name + 7,
".txt", 4)) {
5035 char stxt[PATH_MAX];
5036 char dtxt[PATH_MAX];
5038 snprintf(stxt,
sizeof(stxt),
"%s.txt", sfn);
5039 snprintf(dtxt,
sizeof(dtxt),
"%s.txt", dfn);
5059 unsigned char map[MAXMSGLIMIT] =
"";
5061 struct dirent *msgdirent;
5070 if (!(msgdir = opendir(dir))) {
5074 while ((msgdirent = readdir(msgdir))) {
5075 if (sscanf(msgdirent->d_name,
"msg%30d.%3s", &msgdirint, extension) == 2 && !strcmp(extension,
"txt") && msgdirint < MAXMSGLIMIT) {
5078 ast_debug(4,
"%s map[%d] = %d, count = %d\n", dir, msgdirint, map[msgdirint], stopcount);
5083 for (x = 0; x < MAXMSGLIMIT && stopcount; x++) {
5084 stopcount -= map[x];
5092 #ifndef IMAP_STORAGE
5103 static int copy(
char *infile,
char *outfile)
5111 #ifdef HARDLINK_WHEN_POSSIBLE
5113 if (!link(infile, outfile)) {
5118 if ((ifd = open(infile, O_RDONLY)) < 0) {
5119 ast_log(AST_LOG_WARNING,
"Unable to open %s in read-only mode: %s\n", infile, strerror(errno));
5123 if ((ofd = open(outfile, O_WRONLY | O_TRUNC | O_CREAT, VOICEMAIL_FILE_MODE)) < 0) {
5124 ast_log(AST_LOG_WARNING,
"Unable to open %s in write-only mode: %s\n", outfile, strerror(errno));
5132 len = read(ifd, buf,
sizeof(buf));
5139 ast_log(AST_LOG_WARNING,
"Read failed on %s: %s\n", infile, strerror(errno));
5143 wrlen = write(ofd, buf, len);
5144 if (errno == ENOMEM || errno == ENOSPC || wrlen != len) {
5145 ast_log(AST_LOG_WARNING,
"Write failed on %s (%d of %d): %s\n", outfile, wrlen, len, strerror(errno));
5170 char frompath2[PATH_MAX], topath2[PATH_MAX];
5172 const char *origmailbox =
"", *context =
"", *exten =
"";
5173 const char *priority =
"", *callerchan =
"", *callerid =
"", *origdate =
"";
5174 const char *origtime =
"", *category =
"", *duration =
"";
5177 snprintf(frompath2,
sizeof(frompath2),
"%s.txt", frompath);
5178 snprintf(topath2,
sizeof(topath2),
"%s.txt", topath);
5181 var = ast_load_realtime(
"voicemail_data",
"filename", frompath, SENTINEL);
5183 for (tmp = var; tmp; tmp = tmp->
next) {
5184 if (!strcasecmp(tmp->
name,
"origmailbox")) {
5185 origmailbox = tmp->
value;
5186 }
else if (!strcasecmp(tmp->
name,
"context")) {
5187 context = tmp->
value;
5188 }
else if (!strcasecmp(tmp->
name,
"exten")) {
5190 }
else if (!strcasecmp(tmp->
name,
"priority")) {
5191 priority = tmp->
value;
5192 }
else if (!strcasecmp(tmp->
name,
"callerchan")) {
5193 callerchan = tmp->
value;
5194 }
else if (!strcasecmp(tmp->
name,
"callerid")) {
5195 callerid = tmp->
value;
5196 }
else if (!strcasecmp(tmp->
name,
"origdate")) {
5197 origdate = tmp->
value;
5198 }
else if (!strcasecmp(tmp->
name,
"origtime")) {
5199 origtime = tmp->
value;
5200 }
else if (!strcasecmp(tmp->
name,
"category")) {
5201 category = tmp->
value;
5202 }
else if (!strcasecmp(tmp->
name,
"duration")) {
5203 duration = tmp->
value;
5206 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);
5208 copy(frompath2, topath2);
5226 SCOPE_ENTER(3,
"file: %s\n", file);
5228 txtsize = (strlen(file) + 5)*
sizeof(
char);
5236 snprintf(txt, txtsize,
"%s.txt", file);
5237 ast_trace(-1,
"unlinking '%s'\n", txt);
5239 ast_trace(-1,
"deleting sound files '%s'\n", file);
5241 SCOPE_EXIT_RTN_VALUE(res,
"Done. RC: %d\n", res);
5244 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)
5248 char fromdir[256], fromfile[256];
5250 const char *origcallerid, *origtime;
5251 char origcidname[80], origcidnum[80], origdate[80];
5258 snprintf(num,
sizeof(num),
"%d", msgnum);
5263 ast_callerid_merge(callerid,
sizeof(callerid), cidname, cidnum, NULL) :
"an unknown caller");
5272 make_file(fromfile,
sizeof(fromfile), fromdir, msgnum - 1);
5273 if (strlen(fromfile) <
sizeof(fromfile) - 5) {
5274 strcat(fromfile,
".txt");
5277 ast_debug(1,
"Config load for message text file '%s' failed\n", fromfile);
5281 if ((origcallerid = ast_variable_retrieve(msg_cfg,
"message",
"callerid"))) {
5283 ast_callerid_split(origcallerid, origcidname,
sizeof(origcidname), origcidnum,
sizeof(origcidnum));
5288 if ((origtime = ast_variable_retrieve(msg_cfg,
"message",
"origtime")) && sscanf(origtime,
"%30d", &inttime) == 1) {
5289 struct timeval tv = { inttime, };
5292 ast_strftime_locale(origdate,
sizeof(origdate), emaildateformat, &tm,
S_OR(vmu->
locale, NULL));
5312 for (ptr = from; *ptr; ptr++) {
5313 if (*ptr ==
'"' || *ptr ==
'\\') {
5330 const struct vm_zone *z = NULL;
5334 if (!ast_strlen_zero(vmu->
zonetag)) {
5338 if (!strcmp(z->name, vmu->
zonetag))
5353 for (; *str; str++) {
5354 if (*str > 126 || *str < 32 || strchr(
"()<>@,:;/\"[]?.=", *str)) {
5380 struct ast_str *tmp = ast_str_alloca(80);
5381 int first_section = 1;
5385 for (; *start; start++) {
5386 int need_encoding = 0;
5387 if (*start < 33 || *start > 126 || strchr(
"()<>@,:;/\"[]?.=_", *start)) {
5390 if ((first_section && need_encoding && preamble +
ast_str_strlen(tmp) > 70) ||
5391 (first_section && !need_encoding && preamble +
ast_str_strlen(tmp) > 72) ||
5393 (!first_section && !need_encoding &&
ast_str_strlen(tmp) > 72)) {
5399 if (need_encoding && *start ==
' ') {
5401 }
else if (need_encoding) {
5440 const char *fromfolder,
5447 int attach_user_voicemail,
5449 const char *category,
5455 char host[MAXHOSTNAMELEN] =
"";
5460 char enc_cidnum[256] =
"", enc_cidname[256] =
"";
5462 char *greeting_attachment;
5468 if (!str1 || !str2) {
5480 gethostname(host,
sizeof(host) - 1);
5482 if (strchr(srcemail,
'@')) {
5485 snprintf(who,
sizeof(who),
"%s@%s", srcemail, host);
5488 greeting_attachment = strrchr(
ast_strdupa(attach),
'/');
5489 if (greeting_attachment) {
5490 *greeting_attachment++ =
'\0';
5493 snprintf(dur,
sizeof(dur),
"%d:%02d", duration / 60, duration % 60);
5495 fprintf(p,
"Date: %s" ENDL, date);
5498 ast_strftime_locale(date,
sizeof(date), emaildateformat, &tm,
S_OR(vmu->
locale, NULL));
5500 if (!ast_strlen_zero(fromstring) || !ast_strlen_zero(vmu->
fromstring)) {
5505 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
5513 fprintf(p,
"%s %s" ENDL, first_line ?
"From:" :
"",
ast_str_buffer(str2));
5518 fprintf(p,
"%s %s <%s>" ENDL, first_line ?
"From:" :
"",
ast_str_buffer(str2), who);
5524 ast_log(AST_LOG_WARNING,
"Cannot allocate the channel for variables substitution\n");
5527 fprintf(p,
"From: Asterisk PBX <%s>" ENDL, who);
5533 while ((email = strsep(&emailsbuf,
"|"))) {
5534 char *next = emailsbuf;
5544 fprintf(p,
" %s <%s>%s" ENDL,
ast_str_buffer(str2), email, next ?
"," :
"");
5552 fprintf(p,
"Subject: New greeting '%s' on %s." ENDL, greeting_attachment, date);
5553 }
else if (!ast_strlen_zero(emailsubject) || !ast_strlen_zero(vmu->
emailsubject)) {
5557 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
5565 fprintf(p,
"%s %s" ENDL, first_line ?
"Subject:" :
"",
ast_str_buffer(str2));
5570 fprintf(p,
"%s %s" ENDL, first_line ?
"Subject:" :
"",
ast_str_buffer(str2));
5576 ast_log(AST_LOG_WARNING,
"Cannot allocate the channel for variables substitution\n");
5578 }
else if (ast_test_flag((&globalflags),
VM_PBXSKIP)) {
5579 if (ast_strlen_zero(flag)) {
5580 fprintf(p,
"Subject: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
5582 fprintf(p,
"Subject: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
5585 if (ast_strlen_zero(flag)) {
5586 fprintf(p,
"Subject: [PBX]: New message %d in mailbox %s" ENDL, msgnum + 1, mailbox);
5588 fprintf(p,
"Subject: [PBX]: New %s message %d in mailbox %s" ENDL, flag, msgnum + 1, mailbox);
5592 fprintf(p,
"Message-ID: <Asterisk-%d-%u-%s-%d@%s>" ENDL, msgnum + 1,
5593 (
unsigned int) ast_random(), mailbox, (
int) getpid(), host);
5596 fprintf(p,
"X-Asterisk-VM-Message-Num: %d" ENDL, msgnum + 1);
5598 fprintf(p,
"X-Asterisk-VM-Server-Name: %s" ENDL, fromstring);
5599 fprintf(p,
"X-Asterisk-VM-Context: %s" ENDL, context);
5601 fprintf(p,
"X-Asterisk-VM-Extension: %s" ENDL, (!ast_strlen_zero(vmu->imapvmshareid) ? vmu->imapvmshareid : mailbox));
5603 fprintf(p,
"X-Asterisk-VM-Extension: %s" ENDL, mailbox);
5606 fprintf(p,
"X-Asterisk-VM-Flag: %s" ENDL,
S_OR(flag,
""));
5607 fprintf(p,
"X-Asterisk-VM-Priority: %d" ENDL, chan ? ast_channel_priority(chan) : 0);
5608 fprintf(p,
"X-Asterisk-VM-Caller-ID-Num: %s" ENDL, enc_cidnum);
5609 fprintf(p,
"X-Asterisk-VM-Caller-ID-Name: %s" ENDL, enc_cidname);
5610 fprintf(p,
"X-Asterisk-VM-Duration: %d" ENDL, duration);
5611 if (!ast_strlen_zero(category)) {
5612 fprintf(p,
"X-Asterisk-VM-Category: %s" ENDL, category);
5614 fprintf(p,
"X-Asterisk-VM-Category: " ENDL);
5616 fprintf(p,
"X-Asterisk-VM-Message-Type: %s" ENDL, msgnum > -1 ?
"Message" : greeting_attachment);
5617 fprintf(p,
"X-Asterisk-VM-Orig-date: %s" ENDL, date);
5618 fprintf(p,
"X-Asterisk-VM-Orig-time: %ld" ENDL, (
long) time(NULL));
5619 fprintf(p,
"X-Asterisk-VM-Message-ID: %s" ENDL, msg_id);
5621 if (!ast_strlen_zero(cidnum)) {
5622 fprintf(p,
"X-Asterisk-CallerID: %s" ENDL, enc_cidnum);
5624 if (!ast_strlen_zero(cidname)) {
5625 fprintf(p,
"X-Asterisk-CallerIDName: %s" ENDL, enc_cidname);
5627 fprintf(p,
"MIME-Version: 1.0" ENDL);
5628 if (attach_user_voicemail) {
5630 snprintf(bound,
sizeof(bound),
"----voicemail_%d%s%d%u", msgnum + 1, mailbox,
5631 (
int) getpid(), (
unsigned int) ast_random());
5633 fprintf(p,
"Content-Type: multipart/mixed; boundary=\"%s\"" ENDL, bound);
5634 fprintf(p, ENDL ENDL
"This is a multi-part message in MIME format." ENDL ENDL);
5635 fprintf(p,
"--%s" ENDL, bound);
5637 fprintf(p,
"Content-Type: text/plain; charset=%s" ENDL
"Content-Transfer-Encoding: 8bit" ENDL ENDL, charset);
5639 fprintf(p,
"This message is to let you know that your greeting '%s' was changed on %s." ENDL
5640 "Please do not delete this message, lest your greeting vanish with it." ENDL ENDL,
5641 greeting_attachment, date);
5642 }
else if (emailbody || vmu->
emailbody) {
5646 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
5654 if ((next = strchr(line,
'\n'))) {
5657 fprintf(p,
"%s" ENDL, line);
5659 }
while (!ast_strlen_zero(line));
5666 ast_log(AST_LOG_WARNING,
"Cannot allocate the channel for variables substitution\n");
5669 if (strcmp(vmu->
mailbox, mailbox)) {
5674 char fromdir[256], fromfile[256], origdate[80] =
"", origcallerid[80] =
"";
5678 make_file(fromfile,
sizeof(fromfile), fromdir, msgnum);
5679 if (strlen(fromfile) <
sizeof(fromfile) - 5) {
5680 strcat(fromfile,
".txt");
5683 if ((v = ast_variable_retrieve(msg_cfg,
"message",
"callerid"))) {
5689 if ((v = ast_variable_retrieve(msg_cfg,
"message",
"origtime")) && sscanf(v,
"%30d", &inttime) == 1) {
5690 struct timeval tv = { inttime, };
5693 ast_strftime_locale(origdate,
sizeof(origdate), emaildateformat, &tm,
S_OR(vmu->
locale, NULL));
5695 fprintf(p,
"Dear %s:" ENDL ENDL
"\tJust wanted to let you know you were just forwarded"
5696 " a %s long message (number %d)" ENDL
"in mailbox %s from %s, on %s" ENDL
5697 "(originally sent by %s on %s)" ENDL
"so you might want to check it when you get a"
5698 " chance. Thanks!" ENDL ENDL
"\t\t\t\t--Asterisk" ENDL ENDL, vmu->
fullname, dur,
5699 msgnum + 1, mailbox, (cidname ? cidname : (cidnum ? cidnum :
"an unknown caller")),
5700 date, origcallerid, origdate);
5707 fprintf(p,
"Dear %s:" ENDL ENDL
"\tJust wanted to let you know you were just left a "
5708 "%s long message (number %d)" ENDL
"in mailbox %s from %s, on %s so you might" ENDL
5709 "want to check it when you get a chance. Thanks!" ENDL ENDL
"\t\t\t\t--Asterisk"
5710 ENDL ENDL, vmu->
fullname, dur, msgnum + 1, mailbox,
5711 (cidname ? cidname : (cidnum ? cidnum :
"an unknown caller")), date);
5715 if (imap || attach_user_voicemail) {
5716 if (!ast_strlen_zero(attach2)) {
5717 snprintf(filename,
sizeof(filename),
"msg%04d.%s", msgnum, format);
5718 ast_debug(5,
"creating second attachment filename %s\n", filename);
5719 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 0, msgnum);
5720 snprintf(filename,
sizeof(filename),
"msgintro%04d.%s", msgnum, format);
5721 ast_debug(5,
"creating attachment filename %s\n", filename);
5722 add_email_attachment(p, vmu, format, attach2, greeting_attachment, mailbox, bound, filename, 1, msgnum);
5724 snprintf(filename,
sizeof(filename),
"msg%04d.%s", msgnum, format);
5725 ast_debug(5,
"creating attachment filename %s, no second attachment.\n", filename);
5726 add_email_attachment(p, vmu, format, attach, greeting_attachment, mailbox, bound, filename, 1, msgnum);
5733 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)
5735 char fname[PATH_MAX] =
"";
5736 char sox_gain_tmpdir[PATH_MAX];
5737 char *file_to_delete = NULL, *dir_to_delete = NULL;
5739 char altfname[PATH_MAX] =
"";
5741 char altformat[80] =
"";
5745 char *mime_type = (!strcasecmp(format,
"ogg")) ?
"application/" :
"audio/x-";
5748 snprintf(fname,
sizeof(fname),
"%s.%s", attach, format);
5751 c = strchr(altformat,
'|');
5755 ast_log(AST_LOG_WARNING,
"Failed to open file: %s: %s - trying first/alternate format %s\n", fname, strerror(errno), altformat);
5756 snprintf(altfname,
sizeof(altfname),
"%s.%s", attach, altformat);
5758 ast_log(AST_LOG_WARNING,
"Failed to open file: %s: %s - alternate format %s failure\n", altfname, strerror(errno), altformat);
5766 char tmpdir[PATH_MAX];
5770 res = snprintf(sox_gain_tmpdir,
sizeof(sox_gain_tmpdir),
"%s/vm-gain-XXXXXX", tmpdir);
5771 if (res >=
sizeof(sox_gain_tmpdir)) {
5772 ast_log(LOG_ERROR,
"Failed to create temporary directory path %s: Out of buffer space\n", tmpdir);
5776 if (mkdtemp(sox_gain_tmpdir)) {
5778 char sox_gain_cmd[PATH_MAX];
5780 ast_debug(3,
"sox_gain_tmpdir: %s\n", sox_gain_tmpdir);
5783 dir_to_delete = sox_gain_tmpdir;
5785 res = snprintf(fname,
sizeof(fname),
"%s/output.%s", sox_gain_tmpdir, format);
5786 if (res >=
sizeof(fname)) {
5787 ast_log(LOG_ERROR,
"Failed to create filename buffer for %s/output.%s: Too long\n", sox_gain_tmpdir, format);
5792 res = snprintf(sox_gain_cmd,
sizeof(sox_gain_cmd),
"sox -v %.4f %s.%s %s",
5793 vmu->
volgain, attach, format, fname);
5795 if (!strcasecmp(format,
"wav")) {
5797 res = snprintf(sox_gain_cmd,
sizeof(sox_gain_cmd),
"sox -v %.4f %s.%s -e signed-integer -b 16 %s",
5798 vmu->
volgain, attach, altformat, fname);
5800 res = snprintf(sox_gain_cmd,
sizeof(sox_gain_cmd),
"sox %s.%s -e signed-integer -b 16 %s",
5801 attach, altformat, fname);
5805 res = snprintf(sox_gain_cmd,
sizeof(sox_gain_cmd),
"sox -v %.4f %s.%s %s",
5806 vmu->
volgain, attach, altformat, fname);
5808 res = snprintf(sox_gain_cmd,
sizeof(sox_gain_cmd),
"sox %s.%s %s",
5809 attach, altformat, fname);
5814 if (res >=
sizeof(sox_gain_cmd)) {
5815 ast_log(LOG_ERROR,
"Failed to generate sox command, out of buffer space\n");
5822 file_to_delete = fname;
5823 ast_debug(3,
"VOLGAIN: Stored at: %s - Level: %.4f - Mailbox: %s\n", fname, vmu->
volgain, mailbox);
5825 ast_log(LOG_WARNING,
"Sox failed to re-encode %s: %s (have you installed support for all sox file formats?)\n",
5827 soxstatus == 1 ?
"Problem with command line options" :
"An error occurred during file processing");
5828 ast_log(LOG_WARNING,
"Voicemail attachment will have no volume gain.\n");
5835 if (!file_to_delete) {
5836 res = snprintf(fname,
sizeof(fname),
"%s.%s", attach, format);
5837 if (res >=
sizeof(fname)) {
5838 ast_log(LOG_ERROR,
"Failed to create filename buffer for %s.%s: Too long\n", attach, format);
5843 fprintf(p,
"--%s" ENDL, bound);
5845 fprintf(p,
"Content-Type: %s%s; name=\"%s\"" ENDL, mime_type, format, filename);
5847 fprintf(p,
"Content-Type: %s%s; name=\"%s.%s\"" ENDL, mime_type, format, greeting_attachment, format);
5848 fprintf(p,
"Content-Transfer-Encoding: base64" ENDL);
5849 fprintf(p,
"Content-Description: Voicemail sound attachment." ENDL);
5851 fprintf(p,
"Content-Disposition: attachment; filename=\"%s\"" ENDL ENDL, filename);
5853 fprintf(p,
"Content-Disposition: attachment; filename=\"%s.%s\"" ENDL ENDL, greeting_attachment, format);
5856 fprintf(p, ENDL ENDL
"--%s--" ENDL
"." ENDL, bound);
5858 if (file_to_delete) {
5859 unlink(file_to_delete);
5862 if (dir_to_delete) {
5863 rmdir(dir_to_delete);
5869 static int sendmail(
char *srcemail,
5874 const char *fromfolder,
5881 int attach_user_voicemail,
5883 const char *category,
5888 char tmp[80] =
"/tmp/astmail-XXXXXX";
5892 if (vmu && ast_strlen_zero(vmu->
email)) {
5893 ast_log(AST_LOG_WARNING,
"E-mail address missing for mailbox [%s]. E-mail will not be sent.\n", vmu->
mailbox);
5900 strsep(&stringp,
"|");
5902 if (!strcmp(format,
"wav49"))
5904 ast_debug(3,
"Attaching file '%s', format '%s', uservm is '%d', global is %u\n", attach, format, attach_user_voicemail, ast_test_flag((&globalflags),
VM_ATTACH));
5907 if ((p =
ast_file_mkftemp(tmp, VOICEMAIL_FILE_MODE & ~my_umask)) == NULL) {
5908 ast_log(AST_LOG_WARNING,
"Unable to launch '%s' (can't create temporary file)\n", mailcmd);
5911 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);
5913 snprintf(tmp2,
sizeof(tmp2),
"( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
5915 ast_debug(1,
"Sent mail to %s with command '%s'\n", vmu->
email, mailcmd);
5920 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)
5922 char enc_cidnum[256], enc_cidname[256];
5924 char host[MAXHOSTNAMELEN] =
"";
5927 char tmp[80] =
"/tmp/astmail-XXXXXX";
5928 char tmp2[PATH_MAX];
5933 if (!str1 || !str2) {
5946 if ((p =
ast_file_mkftemp(tmp, VOICEMAIL_FILE_MODE & ~my_umask)) == NULL) {
5947 ast_log(AST_LOG_WARNING,
"Unable to launch '%s' (can't create temporary file)\n", mailcmd);
5952 gethostname(host,
sizeof(host)-1);
5953 if (strchr(srcemail,
'@')) {
5956 snprintf(who,
sizeof(who),
"%s@%s", srcemail, host);
5958 snprintf(dur,
sizeof(dur),
"%d:%02d", duration / 60, duration % 60);
5960 fprintf(p,
"Date: %s\n", date);
5963 ast_strftime_locale(date,
sizeof(date), pagerdateformat,
vmu_tm(vmu, &tm),
S_OR(vmu->
locale, NULL));
5965 if (!ast_strlen_zero(pagerfromstring)) {
5969 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, enc_cidnum, enc_cidname, dur, date, category, flag);
5977 fprintf(p,
"%s %s" ENDL, first_line ?
"From:" :
"",
ast_str_buffer(str2));
5982 fprintf(p,
"%s %s <%s>" ENDL, first_line ?
"From:" :
"",
ast_str_buffer(str2), who);
5988 ast_log(AST_LOG_WARNING,
"Cannot allocate the channel for variables substitution\n");
5991 fprintf(p,
"From: Asterisk PBX <%s>" ENDL, who);
6000 fprintf(p,
"%s %s" ENDL, first_line ?
"To:" :
"",
ast_str_buffer(str2));
6005 fprintf(p,
"%s %s <%s>" ENDL, first_line ?
"To:" :
"",
ast_str_buffer(str2), pager);
6010 if (!ast_strlen_zero(pagersubject)) {
6013 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
6021 fprintf(p,
"%s %s" ENDL, first_line ?
"Subject:" :
"",
ast_str_buffer(str2));
6026 fprintf(p,
"%s %s" ENDL, first_line ?
"Subject:" :
"",
ast_str_buffer(str2));
6032 ast_log(AST_LOG_WARNING,
"Cannot allocate the channel for variables substitution\n");
6035 if (ast_strlen_zero(flag)) {
6036 fprintf(p,
"Subject: New VM\n\n");
6038 fprintf(p,
"Subject: New %s VM\n\n", flag);
6045 prep_email_sub_vars(ast, vmu, msgnum + 1, context, mailbox, fromfolder, cidnum, cidname, dur, date, category, flag);
6050 ast_log(AST_LOG_WARNING,
"Cannot allocate the channel for variables substitution\n");
6053 fprintf(p,
"New %s long %s msg in box %s\n"
6054 "from %s, on %s", dur, flag, mailbox, (cidname ? cidname : (cidnum ? cidnum :
"unknown")), date);
6058 snprintf(tmp2,
sizeof(tmp2),
"( %s < %s ; rm -f %s ) &", mailcmd, tmp, tmp);
6060 ast_debug(1,
"Sent page to %s with command '%s'\n", pager, mailcmd);
6082 return ast_strftime(s, len,
"%a %b %e %r UTC %Y", &tm);
6085 static int invent_message(
struct ast_channel *chan,
char *context,
char *ext,
int busy,
char *ecodes)
6089 char dest[PATH_MAX];
6091 snprintf(fn,
sizeof(fn),
"%s%s/%s/greet", VM_SPOOL_DIR, context, ext);
6093 if ((res =
create_dirpath(dest,
sizeof(dest), context, ext,
""))) {
6094 ast_log(AST_LOG_WARNING,
"Failed to make directory(%s)\n", fn);
6098 RETRIEVE(fn, -1, ext, context);
6125 #define COUNT_MSGS_SQL_FMT "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'"
6126 static int count_messages_in_folder(
struct odbc_obj *odbc,
const char *context,
const char *mailbox,
const char *folder,
int *messages)
6129 char sql[
sizeof(COUNT_MSGS_SQL_FMT) + odbc_table_len + strlen(VM_SPOOL_DIR)
6130 + strlen(context) + strlen(mailbox) + strlen(folder)];
6132 SQLHSTMT stmt = NULL;
6133 struct generic_prepare_struct gps = { .sql = sql, .argc = 0 };
6134 SCOPE_ENTER(3,
"context: %s mb: %s folder: %s", context, mailbox, folder);
6137 SCOPE_EXIT_RTN_VALUE(0,
"No messages pointer\n");
6140 snprintf(sql,
sizeof(sql), COUNT_MSGS_SQL_FMT, odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
6142 SCOPE_EXIT_LOG_RTN_VALUE(1, LOG_WARNING,
"SQL Execute error!\n[%s]\n\n", sql);
6144 res = SQLFetch(stmt);
6145 if (!SQL_SUCCEEDED(res)) {
6146 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
6147 SCOPE_EXIT_LOG_RTN_VALUE(1, LOG_WARNING,
"SQL Fetch error!\n[%s]\n\n", sql);
6149 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata,
sizeof(rowdata), NULL);
6150 if (!SQL_SUCCEEDED(res)) {
6151 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
6152 SCOPE_EXIT_LOG_RTN_VALUE(1, LOG_WARNING,
"SQL Get Data error!\n[%s]\n\n", sql);
6155 *messages = atoi(rowdata);
6156 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
6158 SCOPE_EXIT_RTN_VALUE(0,
"messages: %d\n", *messages);
6160 #undef COUNT_MSGS_SQL_FMT
6162 static int inboxcount2(
const char *mailbox,
int *urgentmsgs,
int *newmsgs,
int *oldmsgs)
6164 char tmp[PATH_MAX] =
"";
6167 SCOPE_ENTER(3,
"mb: %s", mailbox);
6177 if (ast_strlen_zero(mailbox)) {
6178 SCOPE_EXIT_RTN_VALUE(0,
"No mailbox\n");
6183 if (strchr(mailbox,
' ') || strchr(mailbox,
',')) {
6185 char *next, *remaining = tmp;
6186 while ((next = strsep(&remaining,
" ,"))) {
6187 if (
inboxcount2(next, urgentmsgs ? &u : NULL, &n, &o)) {
6188 SCOPE_EXIT_RTN_VALUE(-1,
"Failed to obtain message count for mailbox %s\n", next);
6200 SCOPE_EXIT_RTN_VALUE(0,
"Urgent: %d New: %d Old: %d\n", urgentmsgs ? *urgentmsgs : 0, newmsgs ? *newmsgs : 0, oldmsgs ? *oldmsgs : 0);
6203 context = strchr(tmp,
'@');
6208 context =
"default";
6212 SCOPE_EXIT_LOG_RTN_VALUE(-1, AST_LOG_WARNING,
"Failed to obtain database object for '%s'!\n", odbc_database);
6215 if (count_messages_in_folder(obj, context, tmp,
"INBOX", newmsgs)
6216 || count_messages_in_folder(obj, context, tmp,
"Old", oldmsgs)
6217 || count_messages_in_folder(obj, context, tmp,
"Urgent", urgentmsgs)) {
6218 ast_log(AST_LOG_WARNING,
"Failed to obtain message count for mailbox %s@%s\n",
6223 SCOPE_EXIT_RTN_VALUE(0,
"Urgent: %d New: %d Old: %d\n", urgentmsgs ? *urgentmsgs : 0, newmsgs ? *newmsgs : 0, oldmsgs ? *oldmsgs : 0);
6234 #define MSGCOUNT_SQL_FMT_INBOX "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/INBOX' OR dir = '%s%s/%s/Urgent'"
6235 #define MSGCOUNT_SQL_FMT "SELECT COUNT(*) FROM %s WHERE dir = '%s%s/%s/%s'"
6236 static int messagecount(
const char *mailbox_id,
const char *folder)
6243 SQLHSTMT stmt = NULL;
6245 struct generic_prepare_struct gps = { .argc = 0 };
6246 SCOPE_ENTER(3,
"mb: %s folder: %s", mailbox_id, folder);
6249 if (ast_strlen_zero(mailbox_id)
6250 || separate_mailbox(
ast_strdupa(mailbox_id), &mailbox, &context)) {
6251 SCOPE_EXIT_RTN_VALUE(0,
"Couldn't parse mailbox\n");
6254 if (ast_strlen_zero(folder)) {
6260 SCOPE_EXIT_LOG_RTN_VALUE(0, AST_LOG_WARNING,
"Failed to obtain database object for '%s'!\n", odbc_database);
6263 if (!strcmp(folder,
"INBOX")) {
6264 gps.sql =
ast_alloca(
sizeof(MSGCOUNT_SQL_FMT_INBOX) + odbc_table_len + (strlen(VM_SPOOL_DIR) + strlen(context) + strlen(mailbox) * 2));
6265 sprintf(gps.sql, MSGCOUNT_SQL_FMT_INBOX, odbc_table, VM_SPOOL_DIR, context, mailbox, VM_SPOOL_DIR, context, mailbox);
6267 gps.sql =
ast_alloca(
sizeof(MSGCOUNT_SQL_FMT) + odbc_table_len + strlen(VM_SPOOL_DIR) + strlen(context) + strlen(mailbox) + strlen(folder));
6268 sprintf(gps.sql, MSGCOUNT_SQL_FMT, odbc_table, VM_SPOOL_DIR, context, mailbox, folder);
6273 ast_log(AST_LOG_WARNING,
"SQL Execute error!\n[%s]\n\n", gps.sql);
6276 res = SQLFetch(stmt);
6277 if (!SQL_SUCCEEDED(res)) {
6278 ast_log(AST_LOG_WARNING,
"SQL Fetch error!\n[%s]\n\n", gps.sql);
6279 goto bail_with_handle;
6281 res = SQLGetData(stmt, 1, SQL_CHAR, rowdata,
sizeof(rowdata), NULL);
6282 if (!SQL_SUCCEEDED(res)) {
6283 ast_log(AST_LOG_WARNING,
"SQL Get Data error!\n[%s]\n\n", gps.sql);
6284 goto bail_with_handle;
6286 nummsgs = atoi(rowdata);
6289 SQLFreeHandle(SQL_HANDLE_STMT, stmt);
6293 SCOPE_EXIT_RTN_VALUE(nummsgs,
"Messages: %d\n", nummsgs);
6295 #undef MSGCOUNT_SQL_FMT
6296 #undef MSGCOUNT_SQL_FMT_INBOX
6312 while ((mailbox = strsep(&parse,
",&"))) {
6313 if (messagecount(mailbox, folder)) {
6320 #ifndef IMAP_STORAGE
6338 long duration,
struct ast_vm_user *recip,
char *fmt,
char *dir,
const char *flag,
6339 const char *dest_folder)
6341 char fromdir[PATH_MAX], todir[PATH_MAX], frompath[PATH_MAX], topath[PATH_MAX];
6342 const char *frombox = mbox(vmu, imbox);
6343 const char *userfolder;
6346 SCOPE_ENTER(3,
"mb: %s imb: %d msgnum: %d recip: %s dir: %s dest_folder: %s",
6351 if (!ast_strlen_zero(flag) && !strcmp(flag,
"Urgent")) {
6352 userfolder =
"Urgent";
6353 }
else if (!ast_strlen_zero(dest_folder)) {
6354 userfolder = dest_folder;
6356 userfolder =
"INBOX";
6360 ast_trace(-1,
"todir: %s\n", todir);
6367 ast_trace(-1,
"fromdir: %s\n", fromdir);
6369 make_file(frompath,
sizeof(frompath), fromdir, msgnum);
6370 ast_trace(-1,
"frompath: %s\n", frompath);
6373 ast_trace(-1,
"todir: %s\n", todir);
6376 SCOPE_EXIT_RTN_VALUE(ERROR_LOCK_PATH);
6379 recipmsgnum = LAST_MSG_INDEX(todir) + 1;
6380 ast_trace(-1,
"recip msgnum: %d\n", recipmsgnum);
6382 if (recipmsgnum < recip->maxmsg - (imbox ? 0 : inprocess_count(vmu->
mailbox, vmu->
context, 0))) {
6385 make_file(topath,
sizeof(topath), todir, recipmsgnum);
6386 ast_trace(-1,
"topath: %s\n", topath);
6388 exists = SCOPE_CALL_WITH_INT_RESULT(-1, EXISTS, fromdir, msgnum, frompath, chan ? ast_channel_language(chan) :
"");
6390 SCOPE_CALL(-1, COPY, fromdir, msgnum, todir, recipmsgnum, recip->
mailbox, recip->
context, frompath, topath);
6393 SCOPE_CALL(-1, STORE, todir, recip->
mailbox, recip->
context, recipmsgnum, chan, recip, fmt, duration, NULL, NULL, NULL);
6398 ast_log(AST_LOG_ERROR,
"Recipient mailbox %s@%s is full\n", recip->
mailbox, recip->
context);
6410 SCOPE_EXIT_RTN_VALUE(res,
"Done. RC: %d\n", res);
6413 #if !(defined(IMAP_STORAGE) || defined(ODBC_STORAGE))
6415 static int messagecount(
const char *mailbox_id,
const char *folder)
6420 if (ast_strlen_zero(mailbox_id)
6421 || separate_mailbox(
ast_strdupa(mailbox_id), &mailbox, &context)) {
6425 return __has_voicemail(context, mailbox, folder, 0) + (folder && strcmp(folder,
"INBOX") ? 0 : __has_voicemail(context, mailbox,
"Urgent", 0));
6428 static int __has_voicemail(
const char *context,
const char *mailbox,
const char *folder,
int shortcircuit)
6439 if (ast_strlen_zero(mailbox))
6442 if (ast_strlen_zero(folder))
6444 if (ast_strlen_zero(context))
6445 context =
"default";
6447 c = (
char *)context;
6448 m = (
char *)mailbox;
6450 if (!ast_strlen_zero(aliasescontext)) {
6451 char tmp[MAX_VM_MAILBOX_LEN];
6453 snprintf(tmp, MAX_VM_MAILBOX_LEN,
"%s@%s", mailbox, context);
6456 separate_mailbox(
ast_strdupa(mapping->mailbox), &m, &c);
6461 snprintf(fn,
sizeof(fn),
"%s%s/%s/%s", VM_SPOOL_DIR, c, m, folder);
6463 if (!(dir = opendir(fn)))
6466 while ((de = readdir(dir))) {
6467 if (!strncasecmp(de->d_name,
"msg", 3)) {
6471 }
else if (!strncasecmp(de->d_name + 8,
"txt", 3)) {
6493 char tmp[256], *tmp2 = tmp, *box, *context;
6495 if (ast_strlen_zero(folder)) {
6498 while ((box = strsep(&tmp2,
",&"))) {
6499 if ((context = strchr(box,
'@')))
6502 context =
"default";
6503 if (__has_voicemail(context, box, folder, 1))
6506 if (!strcmp(folder,
"INBOX") && __has_voicemail(context, box,
"Urgent", 1)) {
6521 static int inboxcount2(
const char *mailbox,
int *urgentmsgs,
int *newmsgs,
int *oldmsgs)
6527 if (ast_strlen_zero(mailbox)) {
6541 if (strchr(mailbox,
',')) {
6542 int tmpnew, tmpold, tmpurgent;
6547 while ((cur = strsep(&mb,
", "))) {
6548 if (!ast_strlen_zero(cur)) {
6549 if (
inboxcount2(cur, urgentmsgs ? &tmpurgent : NULL, newmsgs ? &tmpnew : NULL, oldmsgs ? &tmpold : NULL)) {
6559 *urgentmsgs += tmpurgent;
6569 if ((context = strchr(tmp,
'@'))) {
6572 context =
"default";
6576 *newmsgs = __has_voicemail(context, tmp,
"INBOX", 0);
6579 *oldmsgs = __has_voicemail(context, tmp,
"Old", 0);
6582 *urgentmsgs = __has_voicemail(context, tmp,
"Urgent", 0);
6591 static int inboxcount(
const char *mailbox,
int *newmsgs,
int *oldmsgs)
6594 int res =
inboxcount2(mailbox, &urgentmsgs, newmsgs, oldmsgs);
6596 *newmsgs += urgentmsgs;
6603 char arguments[255];
6604 char ext_context[256] =
"";
6605 int newvoicemails = 0, oldvoicemails = 0, urgentvoicemails = 0;
6608 if (!ast_strlen_zero(context))
6609 snprintf(ext_context,
sizeof(ext_context),
"%s@%s", extension, context);
6619 if ((mwi_msg = ast_smdi_mwi_message_wait_station(smdi_iface, SMDI_MWI_WAIT_TIMEOUT, extension))) {
6620 ast_log(AST_LOG_ERROR,
"Error executing SMDI MWI change for %s\n", extension);
6621 if (!strncmp(mwi_msg->cause,
"INV", 3))
6622 ast_log(AST_LOG_ERROR,
"Invalid MWI extension: %s\n", mwi_msg->fwd_st);
6623 else if (!strncmp(mwi_msg->cause,
"BLK", 3))
6624 ast_log(AST_LOG_WARNING,
"MWI light was already on or off for %s\n", mwi_msg->fwd_st);
6625 ast_log(AST_LOG_WARNING,
"The switch reported '%s'\n", mwi_msg->cause);
6628 ast_debug(1,
"Successfully executed SMDI MWI change for %s\n", extension);
6632 if (!ast_strlen_zero(externnotify)) {
6633 if (
inboxcount2(ext_context, &urgentvoicemails, &newvoicemails, &oldvoicemails)) {
6634 ast_log(AST_LOG_ERROR,
"Problem in calculating number of voicemail messages available for extension %s\n", extension);
6636 snprintf(arguments,
sizeof(arguments),
"%s %s %s %d %d %d &",
6637 externnotify,
S_OR(context,
"\"\""),
6638 extension, newvoicemails,
6639 oldvoicemails, urgentvoicemails);
6640 ast_debug(1,
"Executing %s\n", arguments);
6653 signed char record_gain;
6665 snprintf(dst, MSG_ID_LEN,
"%ld-%08x", (
long) time(NULL), unique_counter);
6689 char tmpdir[PATH_MAX];
6690 char tmptxtfile[PATH_MAX];
6691 char desttxtfile[PATH_MAX];
6692 char tmpaudiofile[PATH_MAX];
6694 char destination[PATH_MAX];
6699 char ext_context[256] =
"";
6715 const char *category = NULL;
6716 char msg_id[MSG_ID_LEN];
6719 if (!(
ast_fileexists(recdata->recording_file, recdata->recording_ext, NULL))) {
6720 ast_log(LOG_ERROR,
"File: %s not found.\n", recdata->recording_file);
6724 memset(&svm, 0,
sizeof(svm));
6725 if (!(recipient =
find_user(&svm, recdata->context, recdata->mailbox))) {
6726 ast_log(LOG_ERROR,
"No entry in voicemail config file for '%s@%s'\n", recdata->mailbox, recdata->context);
6731 if ((recording_fs =
ast_readfile(recdata->recording_file, recdata->recording_ext, NULL, 0, 0, VOICEMAIL_DIR_MODE))) {
6736 duration = (int) (framelength / sample_rate);
6738 ast_log(LOG_ERROR,
"Unable to determine sample rate of recording %s\n", recdata->recording_file);
6745 if (duration < recipient->minsecs) {
6746 ast_log(LOG_NOTICE,
"Copying recording to voicemail %s@%s skipped because duration was shorter than "
6747 "minmessage of recipient\n", recdata->mailbox, recdata->context);
6754 ast_log(LOG_ERROR,
"Failed to make directory.\n");
6757 snprintf(tmptxtfile,
sizeof(tmptxtfile),
"%s/XXXXXX", tmpdir);
6758 txtdes = mkstemp(tmptxtfile);
6760 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
6762 ast_log(AST_LOG_ERROR,
"Unable to create message file: %s\n", strerror(errno));
6763 free_user(recipient);
6768 txt = fdopen(txtdes,
"w+");
6774 "; Message Information file\n"
6792 S_OR(recdata->call_context,
""),
6793 S_OR(recdata->call_extension,
""),
6794 recdata->call_priority,
6795 S_OR(recdata->call_callerchan,
"Unknown"),
6796 S_OR(recdata->call_callerid,
"Unknown"),
6797 date, (
long) time(NULL),
6807 ast_log(LOG_WARNING,
"Error opening text file for output\n");
6811 free_user(recipient);
6822 snprintf(ext_context,
sizeof(ext_context),
"%s@%s", recipient->
mailbox, recipient->
context);
6826 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
6828 ast_log(LOG_NOTICE,
"Can not leave voicemail, unable to count messages\n");
6829 free_user(recipient);
6833 if (!(vms = get_vm_state_by_mailbox(recipient->
mailbox, recipient->
context, 0))) {
6838 if (!(vms = create_vm_state_from_user(recipient))) {
6839 ast_log(LOG_ERROR,
"Couldn't allocate necessary space\n");
6840 free_user(recipient);
6848 msgnum = newmsgs + oldmsgs;
6849 ast_debug(3,
"Messagecount set to %d\n", msgnum);
6850 snprintf(destination,
sizeof(destination),
"%simap/msg%s%04d", VM_SPOOL_DIR, recipient->
mailbox, msgnum);
6854 if ((res = imap_check_limits(NULL, vms, recipient, msgnum))) {
6855 ast_log(LOG_NOTICE,
"Didn't copy to voicemail. Mailbox for %s@%s is full.\n", recipient->
mailbox, recipient->
context);
6857 free_user(recipient);
6865 ast_debug(3,
"mailbox = %d : inprocess = %d\n", COUNT(recipient, dir),
6867 if (COUNT(recipient, dir) > recipient->
maxmsg - inprocess_count(recipient->
mailbox, recipient->
context, +1)) {
6868 ast_log(AST_LOG_WARNING,
"Didn't copy to voicemail. Mailbox for %s@%s is full.\n", recipient->
mailbox, recipient->
context);
6870 free_user(recipient);
6875 msgnum = LAST_MSG_INDEX(dir) + 1;
6881 ast_log(LOG_ERROR,
"Couldn't lock directory %s. Voicemail will be lost.\n", dir);
6885 free_user(recipient);
6889 make_file(destination,
sizeof(destination), dir, msgnum);
6891 make_file(tmpaudiofile,
sizeof(tmpaudiofile), tmpdir, msgnum);
6893 if (
ast_filecopy(recdata->recording_file, tmpaudiofile, recdata->recording_ext)) {
6894 ast_log(LOG_ERROR,
"Audio file failed to copy to tmp dir. Probably low disk space.\n");
6898 free_user(recipient);
6904 if (
ast_filerename(tmpaudiofile, destination, recdata->recording_ext)) {
6905 ast_log(LOG_ERROR,
"Audio file failed to move to destination directory. Permissions/Overlap?\n");
6908 free_user(recipient);
6913 snprintf(desttxtfile,
sizeof(desttxtfile),
"%s.txt", destination);
6914 rename(tmptxtfile, desttxtfile);
6916 if (chmod(desttxtfile, VOICEMAIL_FILE_MODE) < 0) {
6917 ast_log(AST_LOG_ERROR,
"Couldn't set permissions on voicemail text file %s: %s", desttxtfile, strerror(errno));
6931 char cidnum[80], cidname[80];
6937 "origmailbox", recdata->mailbox,
6938 "context",
S_OR(recdata->context,
""),
6939 "exten",
S_OR(recdata->call_extension,
""),
6940 "priority", recdata->call_priority,
6941 "callerchan",
S_OR(recdata->call_callerchan,
"Unknown"),
6942 "callerid",
S_OR(recdata->call_callerid,
"Unknown"),
6944 "origtime", time(NULL),
6945 "category",
S_OR(category,
""),
6946 "filename", tmptxtfile,
6947 "duration", duration,
6951 STORE(dir, recipient->
mailbox, recipient->
context, msgnum, NULL, recipient, fmt, 0, vms,
"", msg_id);
6959 ast_callerid_split(clid, cidname,
sizeof(cidname), cidnum,
sizeof(cidnum));
6965 notify_new_message(chan, recipient, NULL, msgnum, duration, fmt, cidnum, cidname,
"");
6969 ast_log(LOG_WARNING,
"Failed to allocate dummy channel, email will not be sent\n");
6971 notify_new_state(recipient);
6975 free_user(recipient);
6993 int newmsgs, oldmsgs;
6995 char txtfile[PATH_MAX];
6996 char tmptxtfile[PATH_MAX];
7005 int sound_duration = 0;
7007 int greeting_only = 0;
7012 char tmpdir[PATH_MAX];
7014 char prefile[PATH_MAX] =
"";
7015 char tempfile[PATH_MAX] =
"";
7016 char ext_context[256] =
"";
7019 char ecodes[17] =
"#";
7024 const char *category = NULL;
7026 const char *alldtmf =
"0123456789ABCD*#";
7028 SCOPE_ENTER(3,
"%s: %s\n", ast_channel_name(chan), ext);
7031 SCOPE_EXIT_RTN_VALUE(-1,
"Failed to allocate memory for tmp\n");
7036 if ((context = strchr(ext,
'@'))) {
7038 tmpptr = strchr(context,
'&');
7040 tmpptr = strchr(ext,
'&');
7046 ast_channel_lock(chan);
7050 ast_channel_unlock(chan);
7052 if (ast_test_flag(options, OPT_MESSAGE_Urgent)) {
7054 }
else if (ast_test_flag(options, OPT_MESSAGE_PRIORITY)) {
7061 memset(&svm, 0,
sizeof(svm));
7062 if (!(vmu =
find_user(&svm, context, ext))) {
7065 SCOPE_EXIT_LOG_RTN_VALUE(res, LOG_WARNING,
7066 "%s: Exten: %s: No entry in voicemail config file for '%s'\n", ast_channel_name(chan), ext, ext);
7072 ast_set_flag(options, OPT_SILENT);
7076 if (strcmp(vmu->
context,
"default"))
7077 snprintf(ext_context,
sizeof(ext_context),
"%s@%s", ext, vmu->
context);
7086 if (ast_test_flag(options, OPT_BUSY_GREETING)) {
7087 snprintf(prefile,
sizeof(prefile),
"%s%s/%s/busy", VM_SPOOL_DIR, vmu->
context, ext);
7088 }
else if (ast_test_flag(options, OPT_UNAVAIL_GREETING)) {
7089 snprintf(prefile,
sizeof(prefile),
"%s%s/%s/unavail", VM_SPOOL_DIR, vmu->
context, ext);
7091 ast_trace(-1,
"prefile: %s\n", prefile);
7096 snprintf(tempfile,
sizeof(tempfile),
"%s%s/%s/temp", VM_SPOOL_DIR, vmu->
context, ext);
7097 ast_trace(-1,
"tempfile: %s\n", tempfile);
7101 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING,
7102 "%s: Exten: %s: Failed to make directory (%s)\n", ast_channel_name(chan), ext, tempfile);
7104 SCOPE_CALL(-1, RETRIEVE, tempfile, -1, vmu->
mailbox, vmu->
context);
7107 ast_trace(-1,
"new prefile: %s\n", prefile);
7110 SCOPE_CALL(-1, DISPOSE, tempfile, -1);
7113 #ifndef IMAP_STORAGE
7116 snprintf(dir,
sizeof(dir),
"%simap", VM_SPOOL_DIR);
7117 if (mkdir(dir, VOICEMAIL_DIR_MODE) && errno != EEXIST) {
7118 ast_log(LOG_WARNING,
"mkdir '%s' failed: %s\n", dir, strerror(errno));
7124 if (!ast_strlen_zero(vmu->exit)) {
7126 S_COR(ast_channel_caller(chan)->
id.number.valid, ast_channel_caller(chan)->
id.number.str, NULL))) {
7127 strncat(ecodes,
"0",
sizeof(ecodes) - strlen(ecodes) - 1);
7131 S_COR(ast_channel_caller(chan)->
id.number.valid, ast_channel_caller(chan)->
id.number.str, NULL))) {
7132 strncat(ecodes,
"0",
sizeof(ecodes) - strlen(ecodes) - 1);
7137 if (!ast_strlen_zero(vmu->exit)) {
7139 S_COR(ast_channel_caller(chan)->
id.number.valid, ast_channel_caller(chan)->
id.number.str, NULL))) {
7140 strncat(ecodes,
"*",
sizeof(ecodes) - strlen(ecodes) - 1);
7143 S_COR(ast_channel_caller(chan)->
id.number.valid, ast_channel_caller(chan)->
id.number.str, NULL))) {
7144 strncat(ecodes,
"*",
sizeof(ecodes) - strlen(ecodes) - 1);
7147 if (ast_test_flag(options, OPT_DTMFEXIT)) {
7148 for (code = alldtmf; *code; code++) {
7151 if (strchr(ecodes, e[0]) == NULL
7153 (!ast_strlen_zero(options->exitcontext) ? options->exitcontext : ast_channel_context(chan)),
7154 e, 1,
S_COR(ast_channel_caller(chan)->
id.number.valid, ast_channel_caller(chan)->
id.number.str, NULL))) {
7155 strncat(ecodes, e,
sizeof(ecodes) - strlen(ecodes) - 1);
7161 if (!ast_strlen_zero(prefile)) {
7162 #if defined(ODBC_STORAGE)
7163 int success = SCOPE_CALL_WITH_INT_RESULT(-1, RETRIEVE, prefile, -1, ext, context);
7164 #elif defined(IMAP_STORAGE)
7165 SCOPE_CALL(-1, RETRIEVE, prefile, -1, ext, context);
7169 if (
ast_streamfile(chan, prefile, ast_channel_language(chan)) > -1) {
7172 if (ast_test_flag(options, OPT_SILENT_IF_GREET)) {
7173 ast_set_flag(options, OPT_SILENT);
7178 if (success == -1) {
7180 ast_trace(-1,
"Greeting '%s' not retrieved from database, but found in file storage. Inserting into database\n", prefile);
7181 SCOPE_CALL(-1, odbc_store_message, prefile, vmu->
mailbox, vmu->
context, -1);
7185 ast_trace(-1,
"%s doesn't exist, doing what we can\n", prefile);
7186 res = invent_message(chan, vmu->
context, ext, ast_test_flag(options, OPT_BUSY_GREETING), ecodes);
7188 SCOPE_CALL(-1, DISPOSE, prefile, -1);
7193 SCOPE_EXIT_RTN_VALUE(-1,
"Hang up during prefile playback\n");
7198 ast_set_flag(options, OPT_SILENT);
7201 if (!res && !ast_test_flag(options, OPT_SILENT)) {
7204 ast_set_flag(options, OPT_SILENT);
7213 ast_channel_exten_set(chan,
"a");
7214 if (!ast_strlen_zero(vmu->exit)) {
7215 ast_channel_context_set(chan, vmu->exit);
7217 ast_channel_priority_set(chan, 0);
7221 SCOPE_EXIT_RTN_VALUE(0,
"User escaped with '*'\n");
7225 if (ast_test_flag(vmu,
VM_OPERATOR) && res ==
'0') {
7228 ast_channel_exten_set(chan,
"o");
7229 if (!ast_strlen_zero(vmu->exit)) {
7230 ast_channel_context_set(chan, vmu->exit);
7233 ast_channel_priority_set(chan, 0);
7238 SCOPE_EXIT_RTN_VALUE(OPERATOR_EXIT,
"User escaped with '0'\n");
7242 if (ast_test_flag(options, OPT_DTMFEXIT) && res > 0) {
7243 if (!ast_strlen_zero(options->exitcontext)) {
7244 ast_channel_context_set(chan, options->exitcontext);
7249 SCOPE_EXIT_RTN_VALUE(res,
"User escaped back to dialplan '%c'\n", res);
7252 if (greeting_only) {
7253 ast_debug(3,
"Greetings only VM (maxmsg=0), Skipping voicemail recording\n");
7263 SCOPE_EXIT_RTN_VALUE(-1,
"Other error '%d'\n", res);
7270 if (!ast_strlen_zero(fmt)) {
7271 char msg_id[MSG_ID_LEN] =
"";
7277 res = inboxcount(ext_context, &newmsgs, &oldmsgs);
7279 ast_log(AST_LOG_NOTICE,
"Can not leave voicemail, unable to count messages\n");
7284 if (!(vms = get_vm_state_by_mailbox(ext, context, 0))) {
7289 if (!(vms = create_vm_state_from_user(vmu))) {
7290 ast_log(AST_LOG_ERROR,
"Couldn't allocate necessary space\n");
7299 msgnum = newmsgs + oldmsgs;
7300 ast_debug(3,
"Messagecount set to %d\n", msgnum);
7301 snprintf(fn,
sizeof(fn),
"%simap/msg%s%04d", VM_SPOOL_DIR, vmu->
mailbox, msgnum);
7305 if ((res = imap_check_limits(chan, vms, vmu, msgnum))) {
7310 res =
ast_streamfile(chan,
"vm-mailboxfull", ast_channel_language(chan));
7313 ast_log(AST_LOG_WARNING,
"No more messages possible\n");
7320 snprintf(tmptxtfile,
sizeof(tmptxtfile),
"%s/XXXXXX", tmpdir);
7321 ast_trace(-1,
"Tempfile: %s\n", tmptxtfile);
7322 txtdes = mkstemp(tmptxtfile);
7323 chmod(tmptxtfile, VOICEMAIL_FILE_MODE & ~my_umask);
7325 res =
ast_streamfile(chan,
"vm-mailboxfull", ast_channel_language(chan));
7328 ast_log(AST_LOG_ERROR,
"Unable to create message file: %s\n", strerror(errno));
7338 if (!ast_strlen_zero(options->beeptone)) {
7345 snprintf(priority,
sizeof(priority),
"%d", ast_channel_priority(chan));
7346 snprintf(origtime,
sizeof(origtime),
"%ld", (
long) time(NULL));
7348 ast_callerid_merge(callerid,
sizeof(callerid),
7349 S_COR(ast_channel_caller(chan)->
id.name.valid, ast_channel_caller(chan)->
id.name.str, NULL),
7350 S_COR(ast_channel_caller(chan)->
id.number.valid, ast_channel_caller(chan)->
id.number.str, NULL),
7354 "context", ast_channel_context(chan),
7355 "exten", ast_channel_exten(chan),
7356 "priority", priority,
7357 "callerchan", ast_channel_name(chan),
7358 "callerid", callerid,
7360 "origtime", origtime,
7361 "category",
S_OR(category,
""),
7362 "filename", tmptxtfile,
7367 txt = fdopen(txtdes,
"w+");
7371 ast_callerid_merge(callerid,
sizeof(callerid),
7372 S_COR(ast_channel_caller(chan)->
id.name.valid, ast_channel_caller(chan)->
id.name.str, NULL),
7373 S_COR(ast_channel_caller(chan)->
id.number.valid, ast_channel_caller(chan)->
id.number.str, NULL),
7377 "; Message Information file\n"
7392 ast_channel_context(chan),
7393 ast_channel_exten(chan),
7394 S_COR(ast_channel_redirecting(chan)->from.number.valid,
7395 ast_channel_redirecting(chan)->from.number.str,
"unknown"),
7396 ast_channel_priority(chan),
7397 ast_channel_name(chan),
7399 date, (
long) time(NULL),
7400 category ? category :
"",
7402 ast_trace(-1,
"Saving txt file mbox: %s msg_id: %s\n", ext, msg_id);
7404 ast_log(AST_LOG_WARNING,
"Error opening text file for output\n");
7409 res =
ast_streamfile(chan,
"vm-mailboxfull", ast_channel_language(chan));
7413 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);
7419 if (!strcmp(flag,
"Urgent")) {
7424 fprintf(txt,
"flag=%s\n", flag);
7425 if (sound_duration < vmu->minsecs) {
7427 ast_verb(3,
"Recording was %d seconds long but needs to be at least %d - abandoning\n", sound_duration, vmu->
minsecs);
7435 fprintf(txt,
"duration=%d\n", duration);
7438 ast_log(AST_LOG_ERROR,
"Couldn't lock directory %s. Voicemail will be lost.\n", dir);
7444 ast_debug(1,
"The recorded media file is gone, so we should remove the .txt file too!\n");
7452 #ifndef IMAP_STORAGE
7453 msgnum = LAST_MSG_INDEX(dir) + 1;
7458 #ifndef IMAP_STORAGE
7464 snprintf(txtfile,
sizeof(txtfile),
"%s.txt", fn);
7466 ast_trace(-1,
"Renaming recordings '%s' -> fn '%s'\n", tmptxtfile, fn);
7470 ast_trace(-1,
"Renaming txt file '%s' -> fn '%s'\n", tmptxtfile, txtfile);
7471 rename(tmptxtfile, txtfile);
7476 if (chmod(txtfile, VOICEMAIL_FILE_MODE) < 0)
7477 ast_log(AST_LOG_ERROR,
"Couldn't set permissions on voicemail text file %s: %s", txtfile, strerror(errno));
7481 snprintf(tmpdur,
sizeof(tmpdur),
"%d", duration);
7482 ast_update_realtime(
"voicemail_data",
"filename", tmptxtfile,
"filename", fn,
"duration", tmpdur, SENTINEL);
7488 SCOPE_CALL(-1, STORE, dir, vmu->
mailbox, vmu->
context, msgnum, chan, vmu, fmt, duration, vms, flag, msg_id);
7496 exten = strsep(&tmpptr,
"&");
7497 cntx = strchr(exten,
'@');
7502 memset(&recipu, 0,
sizeof(recipu));
7503 if ((recip =
find_user(&recipu, cntx, exten))) {
7504 copy_message(chan, vmu, 0, msgnum, duration, recip, fmt, dir, flag, NULL);
7513 S_COR(ast_channel_caller(chan)->
id.number.valid, ast_channel_caller(chan)->
id.number.str, NULL),
7514 S_COR(ast_channel_caller(chan)->
id.name.valid, ast_channel_caller(chan)->
id.name.str, NULL),
7518 S_COR(ast_channel_caller(chan)->
id.number.valid, ast_channel_caller(chan)->
id.number.str, NULL),
7519 S_COR(ast_channel_caller(chan)->
id.name.valid, ast_channel_caller(chan)->
id.name.str, NULL),
7526 SCOPE_CALL(-1, DISPOSE, dir, msgnum);
7535 }
else if (res > 0 && res !=
't')
7538 if (sound_duration < vmu->minsecs)
7544 ast_log(AST_LOG_WARNING,
"No format for saving voicemail?\n");
7550 ast_debug(3,
"*** Checking if we can expunge, expungeonhangup set to %d\n", expungeonhangup);
7551 if (expungeonhangup == 1 && vms->mailstream != NULL) {
7552 ast_mutex_lock(&vms->lock);
7553 #ifdef HAVE_IMAP_TK2006
7554 if (LEVELUIDPLUS (vms->mailstream)) {
7555 mail_expunge_full(vms->mailstream, NIL, EX_UID);
7558 mail_expunge(vms->mailstream);
7559 ast_mutex_unlock(&vms->lock);
7564 SCOPE_EXIT_RTN_VALUE(res,
"Done: '%d'\n", res);
7567 #if !defined(IMAP_STORAGE)
7568 static int resequence_mailbox(
struct ast_vm_user *vmu,
char *dir,
int stopcount)
7577 return ERROR_LOCK_PATH;
7580 for (x = 0, dest = 0; dest != stopcount && x < MAXMSGLIMIT; x++) {
7582 if (EXISTS(dir, x, sfn, NULL)) {
7598 static int say_and_wait(
struct ast_channel *chan,
int num,
const char *language)
7616 snprintf(sequence,
sizeof(sequence),
"%ld", vms->msgArray[msg]);
7618 ast_debug(3,
"Copying sequence %s to mailbox %s\n", sequence, mbox(vmu, box));
7619 ast_mutex_lock(&vms->lock);
7621 if (box == OLD_FOLDER) {
7622 mail_setflag(vms->mailstream, sequence,
"\\Seen");
7623 }
else if (box == NEW_FOLDER) {
7624 mail_clearflag(vms->mailstream, sequence,
"\\Seen");
7626 if (!strcasecmp(mbox(vmu, NEW_FOLDER), vms->curbox) && (box == NEW_FOLDER || box == OLD_FOLDER)) {
7627 ast_mutex_unlock(&vms->lock);
7632 curr_mbox = get_folder_by_name(vms->curbox);
7635 imap_mailbox_name(mailbox,
sizeof(mailbox), vms, box, 1);
7636 if (vms->mailstream && !mail_status(vms->mailstream, mailbox, SA_UIDNEXT)) {
7637 if (mail_create(vms->mailstream, mailbox) != NIL) {
7638 ast_log(AST_LOG_NOTICE,
"Folder %s created!\n", mbox(vmu, box));
7643 if (init_mailstream(vms, curr_mbox) || !vms->mailstream) {
7644 ast_log(AST_LOG_ERROR,
"IMAP mailstream is NULL or can't init_mailstream\n");
7648 res = !mail_move(vms->mailstream, sequence, (
char *) mbox(vmu, box));
7650 res = !mail_copy(vms->mailstream, sequence, (
char *) mbox(vmu, box));
7653 ast_mutex_unlock(&vms->lock);
7656 char *dir = vms->curdir;
7657 char *username = vms->username;
7661 char ddir[PATH_MAX];
7662 const char *dbox = mbox(vmu, box);
7664 SCOPE_ENTER(3,
"dir: %s msg: %d box: %d dbox: %s move? %d \n", dir, msg, box, dbox, move);
7667 ast_trace(-1,
"ddir: %s\n", ddir);
7670 SCOPE_EXIT_RTN_VALUE(ERROR_LOCK_PATH,
"Failed to lock path %s\n", ddir);
7673 x = LAST_MSG_INDEX(ddir) + 1;
7676 ast_trace(-1,
"Deleting message %d\n", msg);
7678 for (i = 1; i <= x; i++) {
7681 make_file(dfn,
sizeof(dfn), ddir, i - 1);
7682 if (EXISTS(ddir, i, sfn, NULL)) {
7683 SCOPE_CALL(-1, RENAME, ddir, i, vmu->
mailbox, vmu->
context, ddir, i - 1, sfn, dfn);
7690 SCOPE_EXIT_RTN_VALUE(ERROR_MAX_MSGS,
"Max messages reached\n");
7695 if (strcmp(sfn, dfn)) {
7696 ast_trace(-1,
"Copying message '%s' to '%s'\n", sfn, dfn);
7697 SCOPE_CALL(-1, COPY, dir, msg, ddir, x, username, context, sfn, dfn);
7704 SCOPE_EXIT_RTN_VALUE(0,
"Done\n");
7708 static int adsi_logo(
unsigned char *buf)
7711 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0,
"Comedian Mail",
"");
7712 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0,
"(C)2002-2006 Digium, Inc.",
"");
7716 static int adsi_load_vmail(
struct ast_channel *chan,
int *useadsi)
7718 unsigned char buf[256];
7725 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
7728 bytes += adsi_logo(buf);
7729 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0,
"Downloading Scripts",
"");
7731 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0,
" .",
"");
7735 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
7737 if (ast_adsi_begin_download(chan, addesc, adsifdn, adsisec, adsiver)) {
7739 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0,
"Load Cancelled.",
"");
7740 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0,
"ADSI Unavailable",
"");
7743 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
7750 bytes += ast_adsi_logo(buf);
7751 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0,
"Downloading Scripts",
"");
7752 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0,
" ..",
"");
7754 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
7763 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
7768 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0,
" ...",
"");
7772 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
7783 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
7788 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0,
" ....",
"");
7790 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
7794 for (x = 0; x < 5; x++) {
7795 snprintf(num,
sizeof(num),
"%d", x);
7796 bytes +=
ast_adsi_load_soft_key(buf + bytes, ADSI_KEY_APPS + 12 + x, mbox(NULL, x), mbox(NULL, x), num, 1);
7799 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
7804 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0,
" .....",
"");
7806 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
7809 if (ast_adsi_end_download(chan)) {
7811 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0,
"Download Unsuccessful.",
"");
7812 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0,
"ADSI Unavailable",
"");
7815 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
7821 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DOWNLOAD);
7823 ast_debug(1,
"Done downloading scripts...\n");
7828 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0,
" ......",
"");
7831 ast_debug(1,
"Restarting session...\n");
7837 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0,
"Scripts Loaded!",
"");
7839 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0,
"Load Failed!",
"");
7841 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
7845 static void adsi_begin(
struct ast_channel *chan,
int *useadsi)
7853 ast_channel_adsicpe_set(chan, AST_ADSI_UNAVAILABLE);
7857 if (adsi_load_vmail(chan, useadsi)) {
7858 ast_log(AST_LOG_WARNING,
"Unable to upload voicemail scripts\n");
7867 unsigned char buf[256];
7869 unsigned char keys[8];
7874 for (x = 0; x < 8; x++)
7877 keys[3] = ADSI_KEY_APPS + 3;
7879 bytes += adsi_logo(buf + bytes);
7880 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0,
" ",
"");
7881 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0,
" ",
"");
7888 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
7891 static void adsi_password(
struct ast_channel *chan)
7893 unsigned char buf[256];
7895 unsigned char keys[8];
7900 for (x = 0; x < 8; x++)
7903 keys[3] = ADSI_KEY_APPS + 3;
7910 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
7913 static void adsi_folders(
struct ast_channel *chan,
int start,
char *label)
7915 unsigned char buf[256];
7917 unsigned char keys[8];
7923 for (x = 0; x < 5; x++) {
7924 y = ADSI_KEY_APPS + 12 + start + x;
7925 if (y > ADSI_KEY_APPS + 12 + 4)
7927 keys[x] = ADSI_KEY_SKT | y;
7929 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 17);
7933 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_CENT, 0, label,
"");
7934 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_CENT, 0,
" ",
"");
7939 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
7945 unsigned char buf[256];
7946 char buf1[256], buf2[256];
7952 char datetime[21] =
"";
7955 unsigned char keys[8];
7963 snprintf(fn2,
sizeof(fn2),
"%s.txt", vms->fn);
7964 f = fopen(fn2,
"r");
7967 if (!fgets((
char *) buf,
sizeof(buf), f)) {
7971 char *stringp = NULL;
7972 stringp = (
char *) buf;
7973 strsep(&stringp,
"=");
7974 val = strsep(&stringp,
"=");
7975 if (!ast_strlen_zero(val)) {
7976 if (!strcmp((
char *) buf,
"callerid"))
7978 if (!strcmp((
char *) buf,
"origdate"))
7986 for (x = 0; x < 5; x++)
7987 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
7993 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
7995 if (vms->curmsg >= vms->lastmsg) {
7999 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
8008 if (!ast_strlen_zero(cid)) {
8013 name =
"Unknown Caller";
8018 ast_mutex_lock(&vms->lock);
8020 if (vms->deleted[vms->curmsg]) {
8021 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
8024 ast_mutex_unlock(&vms->lock);
8028 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
8029 snprintf(buf1,
sizeof(buf1),
"%s%s", vms->curbox,
8030 strcasecmp(vms->curbox,
"INBOX") ?
" Messages" :
"");
8031 snprintf(buf2,
sizeof(buf2),
"Message %d of %d", vms->curmsg + 1, vms->lastmsg + 1);
8033 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1,
"");
8034 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2,
"");
8035 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0, name,
"");
8036 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_LEFT, 0, datetime,
"");
8041 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
8047 unsigned char buf[256];
8048 unsigned char keys[8];
8056 for (x = 0; x < 5; x++)
8057 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 6 + x);
8064 keys[0] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
8066 if (vms->curmsg >= vms->lastmsg) {
8070 keys[3] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 1);
8079 ast_mutex_lock(&vms->lock);
8081 if (vms->deleted[vms->curmsg]) {
8082 keys[1] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 11);
8085 ast_mutex_unlock(&vms->lock);
8089 keys[5] = ADSI_KEY_SKT | (ADSI_KEY_APPS + 5);
8093 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
8098 unsigned char buf[256] =
"";
8099 char buf1[256] =
"", buf2[256] =
"";
8101 unsigned char keys[8];
8104 char *newm = (vms->newmessages == 1) ?
"message" :
"messages";
8105 char *oldm = (vms->oldmessages == 1) ?
"message" :
"messages";
8108 if (vms->newmessages) {
8109 snprintf(buf1,
sizeof(buf1),
"You have %d new", vms->newmessages);
8110 if (vms->oldmessages) {
8111 strncat(buf1,
" and",
sizeof(buf1) - strlen(buf1) - 1);
8112 snprintf(buf2,
sizeof(buf2),
"%d old %s.", vms->oldmessages, oldm);
8114 snprintf(buf2,
sizeof(buf2),
"%s.", newm);
8116 }
else if (vms->oldmessages) {
8117 snprintf(buf1,
sizeof(buf1),
"You have %d old", vms->oldmessages);
8118 snprintf(buf2,
sizeof(buf2),
"%s.", oldm);
8120 strcpy(buf1,
"You have no messages.");
8124 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1,
"");
8125 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2,
"");
8128 for (x = 0; x < 6; x++)
8129 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
8134 if (vms->lastmsg < 0)
8140 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
8145 unsigned char buf[256] =
"";
8146 char buf1[256] =
"", buf2[256] =
"";
8148 unsigned char keys[8];
8151 char *mess = (vms->lastmsg == 0) ?
"message" :
"messages";
8157 for (x = 0; x < 6; x++)
8158 keys[x] = ADSI_KEY_SKT | (ADSI_KEY_APPS + x);
8163 if ((vms->lastmsg + 1) < 1)
8166 snprintf(buf1,
sizeof(buf1),
"%s%s has", vms->curbox,
8167 strcasecmp(vms->curbox,
"INBOX") ?
" folder" :
"");
8169 if (vms->lastmsg + 1)
8170 snprintf(buf2,
sizeof(buf2),
"%d %s.", vms->lastmsg + 1, mess);
8172 strcpy(buf2,
"no messages.");
8173 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 1, ADSI_JUST_LEFT, 0, buf1,
"");
8174 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 2, ADSI_JUST_LEFT, 0, buf2,
"");
8175 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0,
"",
"");
8181 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
8199 static void adsi_goodbye(
struct ast_channel *chan)
8201 unsigned char buf[256];
8206 bytes += adsi_logo(buf + bytes);
8207 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_LEFT, 0,
" ",
"");
8208 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0,
"Goodbye",
"");
8212 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
8227 for (x = start; x < 5; x++) {
8228 if ((d =
ast_say_number(chan, x, AST_DIGIT_ANY, ast_channel_language(chan), NULL)))
8233 snprintf(fn,
sizeof(fn),
"vm-%s", mbox(NULL, x));
8240 d = vm_play_folder_name(chan, fn);
8242 ast_verb(4,
"Failed to find file %s; falling back to INBOX\n", fn);
8243 d = vm_play_folder_name(chan,
"vm-INBOX");
8247 d = vm_play_folder_name(chan, fn);
8265 static int get_folder_ja(
struct ast_channel *chan,
int start)
8270 for (x = start; x < 5; x++) {
8271 if ((d =
ast_say_number(chan, x, AST_DIGIT_ANY, ast_channel_language(chan), (
char *) NULL))) {
8274 snprintf(fn,
sizeof(fn),
"vm-%s", mbox(NULL, x));
8275 d = vm_play_folder_name(chan, fn);
8310 while (((res <
'0') || (res >
'9')) &&
8311 (res !=
'#') && (res >= 0) &&
8314 if (!strcasecmp(ast_channel_language(chan),
"ja")) {
8315 res = get_folder_ja(chan, 0);
8326 isprint(res) ? res :
'?', isprint(res) ? res :
'?');
8349 int curmsg,
char *vm_fmts,
char *context,
signed char record_gain,
long *duration,
8353 int retries = 0, prepend_duration = 0, already_recorded = 0;
8354 char msgfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
8355 char textfile[PATH_MAX];
8358 #ifndef IMAP_STORAGE
8359 signed char zero_gain = 0;
8361 const char *msg_id = NULL;
8363 const char *duration_str;
8364 SCOPE_ENTER(3,
"mbox: %s msgnum: %d curdir: %s", vmu->
mailbox, curmsg, curdir);
8367 make_file(msgfile,
sizeof(msgfile), curdir, curmsg);
8368 ast_trace(-1,
"msgfile: %s\n", msgfile);
8369 strcpy(textfile, msgfile);
8370 strcpy(backup, msgfile);
8371 strcpy(backup_textfile, msgfile);
8372 strncat(textfile,
".txt",
sizeof(textfile) - strlen(textfile) - 1);
8373 strncat(backup,
"-bak",
sizeof(backup) - strlen(backup) - 1);
8374 strncat(backup_textfile,
"-bak.txt",
sizeof(backup_textfile) - strlen(backup_textfile) - 1);
8376 if ((msg_cfg =
ast_config_load(textfile, config_flags)) &&
valid_config(msg_cfg) && (duration_str = ast_variable_retrieve(msg_cfg,
"message",
"duration"))) {
8377 *duration = atoi(duration_str);
8382 while ((cmd >= 0) && (cmd !=
't') && (cmd !=
'*')) {
8390 if (msg_cfg && msg_cfg != CONFIG_STATUS_FILEINVALID) {
8391 msg_id = ast_variable_retrieve(msg_cfg,
"message",
"msg_id");
8393 make_file(vms->introfn,
sizeof(vms->introfn), curdir, curmsg);
8394 strncat(vms->introfn,
"intro",
sizeof(vms->introfn));
8397 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);
8405 ast_trace(-1,
"Prepending to message %d\n", curmsg);
8407 make_file(msgfile,
sizeof(msgfile), curdir, curmsg);
8408 ast_trace(-1,
"msgfile: %s\n", msgfile);
8410 strcpy(textfile, msgfile);
8411 strncat(textfile,
".txt",
sizeof(textfile) - 1);
8421 #ifndef IMAP_STORAGE
8422 if (already_recorded) {
8423 ast_trace(-1,
"Restoring '%s' to '%s'\n", backup, msgfile);
8425 copy(backup_textfile, textfile);
8428 ast_trace(-1,
"Backing up '%s' to '%s'\n", backup, msgfile);
8430 copy(textfile, backup_textfile);
8433 already_recorded = 1;
8438 cmd = SCOPE_CALL_WITH_INT_RESULT(-1,
ast_play_and_prepend, chan, NULL, msgfile, 0, vm_fmts, &prepend_duration, NULL, 1, silencethreshold, maxsilence);
8450 if ((duration_str = ast_variable_retrieve(msg_cfg,
"message",
"duration")))
8451 *duration = atoi(duration_str);
8453 if (prepend_duration) {
8456 char duration_buf[12];
8458 *duration += prepend_duration;
8459 ast_trace(-1,
"Prepending duration: %d total duration: %ld\n", prepend_duration, *duration);
8461 snprintf(duration_buf,
sizeof(duration_buf),
"%ld", *duration);
8472 *vms->introfn =
'\0';
8481 already_recorded = 0;
8499 isprint(cmd) ? cmd :
'?', isprint(cmd) ? cmd :
'?');
8505 if (prepend_duration)
8506 *duration = prepend_duration;
8508 if (already_recorded && cmd == -1) {
8510 ast_trace(-1,
"Restoring '%s' to '%s'\n", backup, msgfile);
8512 rename(backup_textfile, textfile);
8515 if (cmd ==
't' || cmd ==
'S') {
8518 SCOPE_EXIT_RTN_VALUE(cmd,
"Done. CMD: %d %c\n", cmd, cmd >= 32 && cmd < 127 ? cmd :
'?');
8521 static void queue_mwi_event(
const char *channel_id,
const char *box,
int urgent,
int new,
int old)
8526 if (separate_mailbox(
ast_strdupa(box), &mailbox, &context)) {
8530 ast_debug(3,
"Queueing event for mailbox %s New: %d Old: %d\n", box,
new + urgent, old);
8533 if (!ast_strlen_zero(aliasescontext)) {
8538 while ((mapping = ao2_iterator_next(aliases))) {
8539 char alias[strlen(mapping->alias) + 1];
8540 strcpy(alias, mapping->alias);
8543 ast_debug(3,
"Found alias mapping: %s -> %s\n", mapping->alias, box);
8544 separate_mailbox(alias, &mailbox, &context);
8568 char todir[PATH_MAX], fn[PATH_MAX], ext_context[PATH_MAX], *stringp;
8569 int newmsgs = 0, oldmsgs = 0, urgentmsgs = 0;
8570 const char *category;
8571 char *myserveremail = serveremail;
8573 ast_channel_lock(chan);
8577 ast_channel_unlock(chan);
8579 #ifndef IMAP_STORAGE
8580 make_dir(todir,
sizeof(todir), vmu->
context, vmu->
mailbox, !ast_strlen_zero(flag) && !strcmp(flag,
"Urgent") ?
"Urgent" :
"INBOX");
8582 snprintf(todir,
sizeof(todir),
"%simap", VM_SPOOL_DIR);
8584 make_file(fn,
sizeof(fn), todir, msgnum);
8585 snprintf(ext_context,
sizeof(ext_context),
"%s@%s", vmu->
mailbox, vmu->
context);
8591 ast_log(AST_LOG_WARNING,
"Attachment format '%s' is not one of the recorded formats '%s'. Falling back to default format for '%s@%s'.\n", vmu->
attachfmt, fmt, vmu->
mailbox, vmu->
context);
8597 strsep(&stringp,
"|");
8602 if (!ast_strlen_zero(vmu->
email)) {
8603 int attach_user_voicemail = ast_test_flag(vmu,
VM_ATTACH);
8604 char *msg_id = NULL;
8608 char filename[PATH_MAX];
8610 snprintf(filename,
sizeof(filename),
"%s.txt", fn);
8612 if (msg_cfg && msg_cfg != CONFIG_STATUS_FILEINVALID) {
8613 msg_id =
ast_strdupa(ast_variable_retrieve(msg_cfg,
"message",
"msg_id"));
8618 if (attach_user_voicemail)
8622 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);
8624 if (attach_user_voicemail)
8625 DISPOSE(todir, msgnum);
8628 if (!ast_strlen_zero(vmu->
pager)) {
8629 sendpage(myserveremail, vmu->
pager, msgnum, vmu->
context, vmu->
mailbox, mbox(vmu, 0), cidnum, cidname, duration, vmu, category, flag);
8633 DELETE(todir, msgnum, fn, vmu);
8639 queue_mwi_event(ast_channel_uniqueid(chan), ext_context, urgentmsgs, newmsgs, oldmsgs);
8645 vm_imap_delete(NULL, vms->curmsg, vmu);
8686 char username[70]=
"";
8688 char ecodes[16] =
"#";
8689 int res = 0, cmd = 0;
8694 const char mailbox_context[256];
8695 int saved_messages = 0;
8696 int valid_extensions = 0;
8699 char urgent_str[7] =
"";
8700 int prompt_played = 0;
8701 #ifndef IMAP_STORAGE
8702 char msgfile[PATH_MAX], textfile[PATH_MAX], backup[PATH_MAX], backup_textfile[PATH_MAX];
8704 SCOPE_ENTER(3,
"%s: user: %s dir: %s msg: %d\n", ast_channel_name(chan),
8705 vms->username, vms->curdir, vms->curmsg);
8708 ast_copy_string(urgent_str, urgent ?
"Urgent" :
"",
sizeof(urgent_str));
8712 SCOPE_EXIT_RTN_VALUE(-1,
"vms is NULL\n");
8715 curmsg = vms->curmsg;
8718 while (!res && !valid_extensions) {
8719 int use_directory = 0;
8724 while ((cmd >= 0) && !done ){
8754 isprint(cmd) ? cmd :
'?', isprint(cmd) ? cmd :
'?');
8757 if (cmd < 0 || cmd ==
't')
8761 if (use_directory) {
8764 struct ast_app* directory_app;
8767 if (directory_app) {
8768 char vmcontext[256];
8769 char old_context[strlen(ast_channel_context(chan)) + 1];
8770 char old_exten[strlen(ast_channel_exten(chan)) + 1];
8773 strcpy(old_context, ast_channel_context(chan));
8774 strcpy(old_exten, ast_channel_exten(chan));
8775 old_priority = ast_channel_priority(chan);
8778 snprintf(vmcontext,
sizeof(vmcontext),
"%s,,v", context ? context :
"default");
8779 res =
pbx_exec(chan, directory_app, vmcontext);
8784 ast_channel_context_set(chan, old_context);
8785 ast_channel_exten_set(chan, old_exten);
8786 ast_channel_priority_set(chan, old_priority);
8788 ast_log(AST_LOG_WARNING,
"Could not find the Directory application, disabling directory_forward\n");
8793 res =
ast_streamfile(chan,
"vm-extension", ast_channel_language(chan));
8795 if (res || prompt_played > 4)
8797 if ((res =
ast_readstring(chan, username,
sizeof(username) - 1, 2000, 10000,
"#")) < 0)
8802 if (ast_strlen_zero(username))
8805 s = strsep(&stringp,
"*");
8807 valid_extensions = 1;
8809 snprintf((
char*)mailbox_context,
sizeof(mailbox_context),
"%s@%s", s, context ? context :
"default");
8810 if ((is_new_message == 1 || strcmp(s, sender->
mailbox)) && (receiver =
find_user(NULL, context, s))) {
8815 if (inboxcount(mailbox_context, &newmsgs, &oldmsgs)) {
8816 ast_log(LOG_ERROR,
"Problem in calculating number of voicemail messages available for extension %s\n", mailbox_context);
8819 valid_extensions = 0;
8823 if (!(dstvms = get_vm_state_by_mailbox(s, context, 0))) {
8824 if (!(dstvms = create_vm_state_from_user(receiver))) {
8825 ast_log(AST_LOG_ERROR,
"Couldn't allocate necessary space\n");
8828 valid_extensions = 0;
8832 check_quota(dstvms, imapfolder);
8833 if (dstvms->quota_limit && dstvms->quota_usage >= dstvms->quota_limit) {
8834 ast_log(LOG_NOTICE,
"Mailbox '%s' is exceeded quota %u >= %u\n", mailbox_context, dstvms->quota_usage, dstvms->quota_limit);
8836 valid_extensions = 0;
8838 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
8845 if ((newmsgs + oldmsgs) >= capacity) {
8846 ast_log(LOG_NOTICE,
"Mailbox '%s' is full with capacity of %d, prompting for another extension.\n", mailbox_context, capacity);
8848 valid_extensions = 0;
8850 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
8864 free_user(receiver);
8866 ast_log(LOG_NOTICE,
"'%s' is not a valid mailbox\n", mailbox_context);
8869 valid_extensions = 0;
8874 snprintf(fn,
sizeof(fn),
"%s%s/%s/greet", VM_SPOOL_DIR, receiver->
context, s);
8875 SCOPE_CALL(-1, RETRIEVE, fn, -1, s, receiver->
context);
8879 SCOPE_CALL(-1, DISPOSE, fn, -1);
8885 SCOPE_CALL(-1, DISPOSE, fn, -1);
8887 s = strsep(&stringp,
"*");
8890 if (valid_extensions)
8896 if (is_new_message == 1) {
8899 snprintf(mailbox,
sizeof(mailbox),
"%s@%s", username, context);
8902 memset(&leave_options, 0,
sizeof(leave_options));
8903 leave_options.record_gain = record_gain;
8904 leave_options.beeptone =
"beep";
8905 cmd = SCOPE_CALL_WITH_INT_RESULT(-1,
leave_voicemail, chan, mailbox, &leave_options);
8910 int copy_msg_result = 0;
8912 char filename[PATH_MAX];
8914 const char *msg_id = NULL;
8917 memcpy(&vmstmp, vms,
sizeof(vmstmp));
8919 SCOPE_CALL(-1, RETRIEVE, dir, curmsg, sender->
mailbox, sender->
context);
8921 make_file(filename,
sizeof(filename), dir, curmsg);
8922 strncat(filename,
".txt",
sizeof(filename) - strlen(filename) - 1);
8924 if (msg_cfg && msg_cfg == CONFIG_STATUS_FILEINVALID) {
8925 msg_id =
ast_strdupa(ast_variable_retrieve(msg_cfg,
"message",
"msg_id"));
8930 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);
8934 int attach_user_voicemail;
8935 char *myserveremail = serveremail;
8938 dstvms = get_vm_state_by_mailbox(vmtmp->mailbox, vmtmp->context, 0);
8940 dstvms = create_vm_state_from_user(vmtmp);
8943 init_mailstream(dstvms, 0);
8944 if (!dstvms->mailstream) {
8945 ast_log(AST_LOG_ERROR,
"IMAP mailstream for %s is NULL\n", vmtmp->mailbox);
8947 copy_msg_result = STORE(vmstmp.curdir, vmtmp->mailbox, vmtmp->context, curmsg, chan, vmtmp, fmt, duration, dstvms, urgent_str, msg_id);
8951 ast_log(AST_LOG_ERROR,
"Could not find state information for mailbox %s\n", vmtmp->mailbox);
8953 if (!ast_strlen_zero(vmtmp->serveremail))
8954 myserveremail = vmtmp->serveremail;
8955 attach_user_voicemail = ast_test_flag(vmtmp,
VM_ATTACH);
8957 sendmail(myserveremail, vmtmp, todircount, vmtmp->context, vmtmp->mailbox,
8959 S_COR(ast_channel_caller(chan)->
id.number.valid, ast_channel_caller(chan)->
id.number.str, NULL),
8960 S_COR(ast_channel_caller(chan)->
id.name.valid, ast_channel_caller(chan)->
id.name.str, NULL),
8961 vmstmp.fn, vmstmp.introfn, fmt, duration, attach_user_voicemail, chan,
8962 NULL, urgent_str, msg_id);
8964 copy_msg_result = SCOPE_CALL_WITH_INT_RESULT(-1,
copy_message, chan, sender, 0, curmsg, duration, vmtmp, fmt, dir, urgent_str, NULL);
8968 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
8974 if (saved_messages > 0 && !copy_msg_result) {
8985 #ifndef IMAP_STORAGE
8991 make_file(msgfile,
sizeof(msgfile), dir, curmsg);
8992 strcpy(textfile, msgfile);
8993 strcpy(backup, msgfile);
8994 strcpy(backup_textfile, msgfile);
8995 strncat(textfile,
".txt",
sizeof(textfile) - strlen(textfile) - 1);
8996 strncat(backup,
"-bak",
sizeof(backup) - strlen(backup) - 1);
8997 strncat(backup_textfile,
"-bak.txt",
sizeof(backup_textfile) - strlen(backup_textfile) - 1);
9000 rename(backup_textfile, textfile);
9004 SCOPE_CALL(-1, DISPOSE, dir, curmsg);
9005 #ifndef IMAP_STORAGE
9007 make_file(msgfile,
sizeof(msgfile), dir, curmsg);
9008 strcpy(textfile, msgfile);
9009 strcpy(backup_textfile, msgfile);
9010 strncat(textfile,
".txt",
sizeof(textfile) - strlen(textfile) - 1);
9011 strncat(backup_textfile,
"-bak.txt",
sizeof(backup_textfile) - strlen(backup_textfile) - 1);
9012 rename(backup_textfile, textfile);
9019 inprocess_count(vmtmp->mailbox, vmtmp->context, -1);
9022 SCOPE_EXIT_RTN_VALUE(res ? res : cmd,
"Done. res: %d cmd: %d\n", res, cmd);
9029 ast_log(AST_LOG_WARNING,
"Unable to play message %s\n", file);
9036 return ast_control_streamfile(chan, file, listen_control_forward_key, listen_control_reverse_key, listen_control_stop_key, listen_control_pause_key, listen_control_restart_key, skipms, NULL);
9039 static int play_message_category(
struct ast_channel *chan,
const char *category)
9043 if (!ast_strlen_zero(category))
9047 ast_log(AST_LOG_WARNING,
"No sound file for category '%s' was found.\n", category);
9054 static int play_message_datetime(
struct ast_channel *chan,
struct ast_vm_user *vmu,
const char *origtime,
const char *filename)
9057 struct vm_zone *the_zone = NULL;
9061 ast_log(AST_LOG_WARNING,
"Couldn't find origtime in %s\n", filename);
9066 if (!ast_strlen_zero(vmu->
zonetag)) {
9071 if (!strcmp(z->name, vmu->
zonetag)) {
9087 if (time_now.tm_year == time_then.tm_year)
9088 snprintf(temp,
sizeof(temp),
"%d", time_now.tm_yday);
9090 snprintf(temp,
sizeof(temp),
"%d", (time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday));
9096 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan), the_zone->msg_format, the_zone->timezone);
9097 }
else if (!strncasecmp(ast_channel_language(chan),
"de", 2)) {
9098 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan),
"'vm-received' Q 'digits/at' HM", NULL);
9099 }
else if (!strncasecmp(ast_channel_language(chan),
"gr", 2)) {
9100 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan),
"'vm-received' q H 'digits/kai' M ", NULL);
9101 }
else if (!strncasecmp(ast_channel_language(chan),
"is", 2)) {
9102 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan),
"'vm-received' Q 'digits/at' HM", NULL);
9103 }
else if (!strncasecmp(ast_channel_language(chan),
"it", 2)) {
9104 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan),
"'vm-received' q 'digits/at' 'digits/hours' k 'digits/e' M 'digits/minutes'", NULL);
9105 }
else if (!strcasecmp(ast_channel_language(chan),
"ja")) {
9106 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan),
"PHM q 'jp-ni' 'vm-received'", NULL);
9107 }
else if (!strncasecmp(ast_channel_language(chan),
"nl", 2)) {
9108 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan),
"'vm-received' q 'digits/nl-om' HM", NULL);
9109 }
else if (!strncasecmp(ast_channel_language(chan),
"no", 2)) {
9110 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan),
"'vm-received' Q 'digits/at' HM", NULL);
9111 }
else if (!strncasecmp(ast_channel_language(chan),
"pl", 2)) {
9112 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan),
"'vm-received' Q HM", NULL);
9113 }
else if (!strncasecmp(ast_channel_language(chan),
"pt_BR", 5)) {
9114 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan),
"'vm-received' Ad 'digits/pt-de' B 'digits/pt-de' Y 'digits/pt-as' HM ", NULL);
9115 }
else if (!strncasecmp(ast_channel_language(chan),
"se", 2)) {
9116 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan),
"'vm-received' dB 'digits/at' k 'and' M", NULL);
9117 }
else if (!strncasecmp(ast_channel_language(chan),
"zh", 2)) {
9118 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan),
"qR 'vm-received'", NULL);
9119 }
else if (!strncasecmp(ast_channel_language(chan),
"vi", 2)) {
9120 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan),
"'vm-received' A 'digits/day' dB 'digits/year' Y 'digits/at' k 'hours' M 'minutes'", NULL);
9122 res = ast_say_date_with_format(chan, t, AST_DIGIT_ANY, ast_channel_language(chan),
"'vm-received' q 'digits/at' IMp", NULL);
9132 static int play_message_callerid(
struct ast_channel *chan,
struct vm_state *vms,
char *cid,
const char *context,
int callback,
int saycidnumber)
9136 char *callerid, *name;
9137 char prefile[PATH_MAX] =
"";
9146 if ((cid == NULL)||(context == NULL))
9150 ast_debug(1,
"VM-CID: composite caller ID received: %s, context: %s\n", cid, context);
9152 if ((!ast_strlen_zero(callerid)) && strcmp(callerid,
"Unknown")) {
9155 for (i = 0 ; i < MAX_NUM_CID_CONTEXTS ; i++){
9156 ast_debug(1,
"VM-CID: comparing internalcontext: %s\n", cidinternalcontexts[i]);
9157 if ((strcmp(cidinternalcontexts[i], context) == 0))
9160 if (i != MAX_NUM_CID_CONTEXTS){
9162 snprintf(prefile,
sizeof(prefile),
"%s%s/%s/greet", VM_SPOOL_DIR, context, callerid);
9163 if (!ast_strlen_zero(prefile)) {
9167 ast_verb(3,
"Playing envelope info: CID number '%s' matches mailbox number, playing recorded name\n", callerid);
9169 res = wait_file2(chan, vms,
"vm-from");
9172 ast_verb(3,
"Playing envelope info: message from '%s'\n", callerid);
9175 res = wait_file2(chan, vms,
"vm-from-extension");
9181 ast_debug(1,
"VM-CID: Numeric caller id: (%s)\n", callerid);
9185 snprintf(prefile,
sizeof(prefile),
"%s/recordings/callerids/%s", ast_config_AST_SPOOL_DIR, callerid);
9187 ast_verb(3,
"Playing recorded name for CID number '%s' - '%s'\n", callerid,prefile);
9188 wait_file2(chan, vms,
"vm-from");
9190 ast_verb(3,
"Played recorded name result '%d'\n", res);
9193 wait_file2(chan, vms,
"vm-from-phonenumber");
9194 res =
ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, ast_channel_language(chan));
9197 res =
ast_say_digit_str(chan, callerid, AST_DIGIT_ANY, ast_channel_language(chan));
9202 ast_debug(1,
"VM-CID: From an unknown number\n");
9204 res = wait_file2(chan, vms,
"vm-unknown-caller");
9209 static int play_message_duration(
struct ast_channel *chan,
struct vm_state *vms,
const char *duration,
int minduration)
9215 if (duration == NULL)
9219 durations = atoi(duration);
9220 durationm = (durations / 60);
9222 ast_debug(1,
"VM-Duration: duration is: %d seconds converted to: %d minutes\n", durations, durationm);
9224 if ((!res) && (durationm >= minduration)) {
9225 res = wait_file2(chan, vms,
"vm-duration");
9228 if (!strncasecmp(ast_channel_language(chan),
"pl", 2)) {
9229 div_t num = div(durationm, 10);
9231 if (durationm == 1) {
9234 }
else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
9239 res = say_and_wait(chan, durationm - 2 , ast_channel_language(chan));
9243 res = say_and_wait(chan, durationm, ast_channel_language(chan));
9247 res = say_and_wait(chan, durationm, ast_channel_language(chan));
9252 res =
ast_say_number(chan, durationm, AST_DIGIT_ANY, ast_channel_language(chan), NULL);
9253 res = wait_file2(chan, vms,
"vm-minutes");
9262 char filename[PATH_MAX], *cid;
9263 const char *origtime, *context, *category, *duration, *flag;
9266 SCOPE_ENTER(3,
"%s: user: %s dir: %s msg: %d\n", ast_channel_name(chan),
9267 vms->username, vms->curdir, vms->curmsg);
9270 make_file(vms->fn,
sizeof(vms->fn), vms->curdir, vms->curmsg);
9271 adsi_message(chan, vms);
9273 res = wait_file2(chan, vms,
"vm-first");
9274 }
else if (vms->curmsg == vms->lastmsg) {
9275 res = wait_file2(chan, vms,
"vm-last");
9278 snprintf(filename,
sizeof(filename),
"%s.txt", vms->fn);
9279 SCOPE_CALL(-1, RETRIEVE, vms->curdir, vms->curmsg, vmu->
mailbox, vmu->
context);
9282 ast_log(LOG_WARNING,
"No message attribute file?!! (%s)\n", filename);
9285 flag = ast_variable_retrieve(msg_cfg,
"message",
"flag");
9288 if (!ast_strlen_zero(flag) && !strcmp(flag,
"Urgent")) {
9289 res = wait_file2(chan, vms,
"vm-Urgent");
9295 if (!strncasecmp(ast_channel_language(chan),
"pl", 2)) {
9296 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
9299 ten = (vms->curmsg + 1) / 10;
9300 one = (vms->curmsg + 1) % 10;
9302 if (vms->curmsg < 20) {
9303 snprintf(nextmsg,
sizeof(nextmsg),
"digits/n-%d", vms->curmsg + 1);
9304 res = wait_file2(chan, vms, nextmsg);
9306 snprintf(nextmsg,
sizeof(nextmsg),
"digits/n-%d", ten * 10);
9307 res = wait_file2(chan, vms, nextmsg);
9310 snprintf(nextmsg,
sizeof(nextmsg),
"digits/n-%d", one);
9311 res = wait_file2(chan, vms, nextmsg);
9317 res = wait_file2(chan, vms,
"vm-message");
9319 }
else if (!strncasecmp(ast_channel_language(chan),
"he", 2)) {
9321 res = wait_file2(chan, vms,
"vm-message");
9322 res = wait_file2(chan, vms,
"vm-first");
9323 }
else if (vms->curmsg == vms->lastmsg) {
9324 res = wait_file2(chan, vms,
"vm-message");
9325 res = wait_file2(chan, vms,
"vm-last");
9327 res = wait_file2(chan, vms,
"vm-message");
9328 res = wait_file2(chan, vms,
"vm-number");
9329 res =
ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, ast_channel_language(chan),
"f");
9332 }
else if (!strncasecmp(ast_channel_language(chan),
"is", 2)) {
9333 res = wait_file2(chan, vms,
"vm-message");
9334 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
9335 res =
ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, ast_channel_language(chan),
"n");
9338 }
else if (!strncasecmp(ast_channel_language(chan),
"vi", 2)) {
9340 res = wait_file2(chan, vms,
"vm-message");
9341 res = wait_file2(chan, vms,
"vm-first");
9342 }
else if (vms->curmsg == vms->lastmsg) {
9343 res = wait_file2(chan, vms,
"vm-message");
9344 res = wait_file2(chan, vms,
"vm-last");
9346 res = wait_file2(chan, vms,
"vm-message");
9347 res = wait_file2(chan, vms,
"vm-number");
9348 res =
ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, ast_channel_language(chan),
"f");
9351 if (!strncasecmp(ast_channel_language(chan),
"se", 2)) {
9352 res = wait_file2(chan, vms,
"vm-meddelandet");
9354 res = wait_file2(chan, vms,
"vm-message");
9356 if (vms->curmsg && (vms->curmsg != vms->lastmsg)) {
9359 res =
ast_say_number(chan, vms->curmsg + 1, AST_DIGIT_ANY, ast_channel_language(chan), NULL);
9366 SCOPE_EXIT_LOG_RTN_VALUE(0, AST_LOG_WARNING,
"No message attribute file?!! (%s)\n", filename);
9369 if (!(origtime = ast_variable_retrieve(msg_cfg,
"message",
"origtime"))) {
9370 SCOPE_CALL(-1, DISPOSE, vms->curdir, vms->curmsg);
9372 SCOPE_EXIT_LOG_RTN_VALUE(0, AST_LOG_WARNING,
"No origtime?!\n");
9375 cid =
ast_strdupa(ast_variable_retrieve(msg_cfg,
"message",
"callerid"));
9376 duration = ast_variable_retrieve(msg_cfg,
"message",
"duration");
9377 category = ast_variable_retrieve(msg_cfg,
"message",
"category");
9379 context = ast_variable_retrieve(msg_cfg,
"message",
"context");
9381 res = play_message_category(chan, category);
9383 if ((!res) && (ast_test_flag(vmu,
VM_ENVELOPE))) {
9384 res = play_message_datetime(chan, vmu, origtime, filename);
9386 if ((!res) && (ast_test_flag(vmu,
VM_SAYCID))) {
9387 res = play_message_callerid(chan, vms, cid, context, 0, 0);
9390 res = play_message_duration(chan, vms, duration, vmu->saydurationm);
9400 make_file(vms->fn,
sizeof(vms->fn), vms->curdir, vms->curmsg);
9402 ast_mutex_lock(&vms->lock);
9404 vms->heard[vms->curmsg] = 1;
9406 ast_mutex_unlock(&vms->lock);
9410 if (!ast_strlen_zero(vms->introfn) &&
ast_fileexists(vms->introfn, NULL, NULL) > 0) {
9411 wait_file(chan, vms, vms->introfn);
9414 if ((res = wait_file(chan, vms, vms->fn)) < 0) {
9415 ast_log(AST_LOG_WARNING,
"Playback of message %s failed\n", vms->fn);
9419 isprint(res) ? res :
'?', isprint(res) ? res :
'?');
9421 SCOPE_CALL(-1, DISPOSE, vms->curdir, vms->curmsg);
9422 SCOPE_EXIT_RTN_VALUE(res,
"Done: RC: %d\n", res);
9426 static int imap_remove_file(
char *dir,
int msgnum)
9429 char full_fn[PATH_MAX];
9430 char intro[PATH_MAX] = {0,};
9434 snprintf(intro,
sizeof(intro),
"%sintro", fn);
9438 if ((msgnum < 0 && imapgreetings) || msgnum > -1) {
9440 if (!ast_strlen_zero(intro)) {
9443 snprintf(full_fn,
sizeof(full_fn),
"%s.txt", fn);
9451 static int imap_delete_old_greeting (
char *dir,
struct vm_state *vms)
9453 char *file, *filename;
9463 ast_log(AST_LOG_ERROR,
"Failed to procure file name from directory passed. You should never see this.\n");
9467 ast_mutex_lock(&vms->lock);
9470 curr_mbox = get_folder_by_name(vms->curbox);
9472 if (init_mailstream(vms, GREETINGS_FOLDER) || !vms->mailstream) {
9473 ast_log(AST_LOG_ERROR,
"IMAP mailstream is NULL or can't init_mailstream\n");
9474 ast_mutex_unlock(&vms->lock);
9478 for (i = 0; i < vms->mailstream->nmsgs; i++) {
9479 mail_fetchstructure(vms->mailstream, i + 1, &body);
9481 if (body->nested.part->next && body->nested.part->next->body.parameter->value) {
9482 char *attachment = body->nested.part->next->body.parameter->value;
9483 char copy[strlen(attachment) + 1];
9485 strcpy(copy, attachment);
9488 filename = strsep(&attachment,
".");
9489 if (!strcmp(filename, file)) {
9490 snprintf(arg,
sizeof(arg),
"%d", i + 1);
9491 mail_setflag(vms->mailstream, arg,
"\\DELETED");
9494 ast_log(AST_LOG_ERROR,
"There is no file attached to this IMAP message.\n");
9495 ast_mutex_unlock(&vms->lock);
9499 mail_expunge(vms->mailstream);
9501 if (curr_mbox != -1) {
9503 if (init_mailstream(vms, curr_mbox) || !vms->mailstream) {
9504 ast_log(AST_LOG_ERROR,
"IMAP mailstream is NULL or can't init_mailstream\n");
9508 ast_mutex_unlock(&vms->lock);
9512 #elif !defined(IMAP_STORAGE)
9515 int count_msg, last_msg;
9516 SCOPE_ENTER(3,
"user: %s dir: %s msg: %d box %d\n",
9517 vms->username, vms->curdir, vms->curmsg, box);
9524 snprintf(vms->vmbox,
sizeof(vms->vmbox),
"vm-%s", vms->curbox);
9530 count_msg = COUNT(vmu, vms->curdir);
9531 if (count_msg < 0) {
9532 SCOPE_EXIT_RTN_VALUE(count_msg,
"msgs: %d\n", count_msg);
9534 vms->lastmsg = count_msg - 1;
9537 if (vm_allocate_dh(vms, vmu, count_msg)) {
9538 SCOPE_EXIT_RTN_VALUE(-1,
"failed to allocate dh\n");
9549 SCOPE_EXIT_LOG_RTN_VALUE(ERROR_LOCK_PATH, AST_LOG_ERROR,
"Could not open mailbox %s: mailbox is locked\n", vms->curdir);
9553 last_msg = LAST_MSG_INDEX(vms->curdir);
9556 if (last_msg < -1) {
9557 SCOPE_EXIT_RTN_VALUE(last_msg,
"last msg: %d\n", last_msg);
9558 }
else if (vms->lastmsg != last_msg) {
9559 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);
9560 resequence_mailbox(vmu, vms->curdir, count_msg);
9563 SCOPE_EXIT_RTN_VALUE(0,
"Done\n");
9570 int last_msg_idx = 0;
9572 #ifndef IMAP_STORAGE
9573 int res = 0, nummsg;
9576 SCOPE_ENTER(3,
"user: %s dir: %s msg: %d\n",
9577 vms->username, vms->curdir, vms->curmsg);
9579 if (vms->lastmsg <= -1) {
9580 ast_trace(-1,
"No messages in mailbox\n");
9585 #ifndef IMAP_STORAGE
9588 SCOPE_EXIT_RTN_VALUE(ERROR_LOCK_PATH,
"Could not open mailbox %s: mailbox is locked\n", vms->curdir);
9592 last_msg_idx = LAST_MSG_INDEX(vms->curdir);
9593 if (last_msg_idx != vms->lastmsg) {
9594 ast_log(AST_LOG_NOTICE,
"%d messages received after mailbox opened.\n", last_msg_idx - vms->lastmsg);
9598 for (x = 0; x < last_msg_idx + 1; x++) {
9599 if (!vms->deleted[x] && ((strcasecmp(vms->curbox,
"INBOX") && strcasecmp(vms->curbox,
"Urgent")) || !vms->heard[x] || (vms->heard[x] && !ast_test_flag(vmu,
VM_MOVEHEARD)))) {
9601 make_file(vms->fn,
sizeof(vms->fn), vms->curdir, x);
9602 if (!EXISTS(vms->curdir, x, vms->fn, NULL)) {
9606 make_file(fn2,
sizeof(fn2), vms->curdir, vms->curmsg);
9607 if (strcmp(vms->fn, fn2)) {
9608 SCOPE_CALL(-1, RENAME, vms->curdir, x, vmu->
mailbox, vmu->
context, vms->curdir, vms->curmsg, vms->fn, fn2);
9610 }
else if ((!strcasecmp(vms->curbox,
"INBOX") || !strcasecmp(vms->curbox,
"Urgent")) && vms->heard[x] && ast_test_flag(vmu,
VM_MOVEHEARD) && !vms->deleted[x]) {
9612 res = SCOPE_CALL_WITH_INT_RESULT(-1,
save_to_folder, vmu, vms, x, 1, NULL, 0);
9613 if (res == ERROR_LOCK_PATH || res == ERROR_MAX_MSGS) {
9615 ast_log(AST_LOG_WARNING,
"Save failed. Not moving message: %s.\n", res == ERROR_LOCK_PATH ?
"unable to lock path" :
"destination folder full");
9616 vms->deleted[x] = 0;
9622 res = SCOPE_CALL_WITH_INT_RESULT(-1,
save_to_folder, vmu, vms, x, 10, NULL, 0);
9623 if (res == ERROR_LOCK_PATH) {
9624 ast_trace(-1,
"Unable to lock path. Not moving message to deleted folder.\n");
9626 vms->deleted[x] = 0;
9633 make_file(vms->fn,
sizeof(vms->fn), vms->curdir, x);
9634 res = SCOPE_CALL_WITH_INT_RESULT(-1, EXISTS, vms->curdir, x, vms->fn, NULL);
9636 SCOPE_CALL(-1, DELETE, vms->curdir, x, vms->fn, vmu);
9643 for (x = vms->curmsg + 1; x <= nummsg; x++) {
9644 make_file(vms->fn,
sizeof(vms->fn), vms->curdir, x);
9645 res = SCOPE_CALL_WITH_INT_RESULT(-1, EXISTS, vms->curdir, x, vms->fn, NULL);
9647 SCOPE_CALL(-1, DELETE, vms->curdir, x, vms->fn, vmu);
9652 ast_mutex_lock(&vms->lock);
9656 last_msg_idx = vms->dh_arraysize;
9657 for (x = last_msg_idx - 1; x >= 0; x--) {
9658 if (vms->deleted[x]) {
9660 DELETE(vms->curdir, x, vms->fn, vmu);
9668 ast_free(vms->deleted);
9669 vms->deleted = NULL;
9672 ast_free(vms->heard);
9675 vms->dh_arraysize = 0;
9677 ast_mutex_unlock(&vms->lock);
9680 SCOPE_EXIT_RTN_VALUE(0,
"Done\n");
9689 static int vm_play_folder_name_gr(
struct ast_channel *chan,
char *box)
9698 if (!strcasecmp(box,
"vm-INBOX") || !strcasecmp(box,
"vm-Old")){
9707 static int vm_play_folder_name_ja(
struct ast_channel *chan,
char *box)
9711 if (!strcasecmp(box,
"vm-INBOX") || !strcasecmp(box,
"vm-Old")) {
9720 static int vm_play_folder_name_pl(
struct ast_channel *chan,
char *box)
9724 if (!strcasecmp(box,
"vm-INBOX") || !strcasecmp(box,
"vm-Old")) {
9725 if (!strcasecmp(box,
"vm-INBOX"))
9736 static int vm_play_folder_name_ua(
struct ast_channel *chan,
char *box)
9740 if (!strcasecmp(box,
"vm-Family") || !strcasecmp(box,
"vm-Friends") || !strcasecmp(box,
"vm-Work")){
9749 static int vm_play_folder_name(
struct ast_channel *chan,
char *box)
9753 if ( !strncasecmp(ast_channel_language(chan),
"it", 2) ||
9754 !strncasecmp(ast_channel_language(chan),
"es", 2) ||
9755 !strncasecmp(ast_channel_language(chan),
"pt", 2)) {
9758 }
else if (!strncasecmp(ast_channel_language(chan),
"gr", 2)) {
9759 return vm_play_folder_name_gr(chan, box);
9760 }
else if (!strncasecmp(ast_channel_language(chan),
"he", 2)) {
9762 }
else if (!strncasecmp(ast_channel_language(chan),
"ja", 2)) {
9763 return vm_play_folder_name_ja(chan, box);
9764 }
else if (!strncasecmp(ast_channel_language(chan),
"pl", 2)) {
9765 return vm_play_folder_name_pl(chan, box);
9766 }
else if (!strncasecmp(ast_channel_language(chan),
"ua", 2)) {
9767 return vm_play_folder_name_ua(chan, box);
9768 }
else if (!strncasecmp(ast_channel_language(chan),
"vi", 2)) {
9792 if (vms->newmessages) {
9795 res =
ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, ast_channel_language(chan), NULL);
9797 if (vms->newmessages == 1) {
9807 }
else if (vms->oldmessages){
9810 res =
ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, ast_channel_language(chan), NULL);
9811 if (vms->oldmessages == 1){
9820 }
else if (!vms->oldmessages && !vms->newmessages)
9882 static int vm_intro_multilang(
struct ast_channel *chan,
struct vm_state *vms,
const char message_gender[])
9889 if (!res && vms->newmessages) {
9890 lastnum = vms->newmessages;
9892 if (!(res =
ast_say_number(chan, lastnum, AST_DIGIT_ANY, ast_channel_language(chan), message_gender))) {
9893 res = ast_say_counted_adjective(chan, lastnum,
"vm-new", message_gender);
9896 if (!res && vms->oldmessages) {
9901 if (!res && vms->oldmessages) {
9902 lastnum = vms->oldmessages;
9904 if (!(res =
ast_say_number(chan, lastnum, AST_DIGIT_ANY, ast_channel_language(chan), message_gender))) {
9905 res = ast_say_counted_adjective(chan, lastnum,
"vm-old", message_gender);
9914 res = ast_say_counted_noun(chan, lastnum,
"vm-message");
9928 if ((vms->newmessages) || (vms->oldmessages)) {
9936 if (vms->newmessages) {
9938 if (vms->newmessages == 1) {
9941 if (vms->newmessages == 2) {
9944 res =
ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, ast_channel_language(chan),
"f");
9949 if (vms->oldmessages && !res) {
9951 if (vms->oldmessages == 1) {
9954 if (vms->oldmessages == 2) {
9957 res =
ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, ast_channel_language(chan),
"f");
9963 if (!res && vms->oldmessages && !vms->newmessages) {
9965 if (vms->oldmessages == 1) {
9968 if (vms->oldmessages == 2) {
9971 res =
ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, ast_channel_language(chan),
"f");
9978 if (!vms->oldmessages && !vms->newmessages) {
9993 if (vms->newmessages) {
10000 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10001 if (vms->oldmessages && !res)
10005 if (vms->oldmessages) {
10012 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10014 if (!vms->oldmessages && !vms->newmessages) {
10035 if (vms->urgentmessages) {
10036 res = say_and_wait(chan, vms->urgentmessages, ast_channel_language(chan));
10039 if ((vms->oldmessages || vms->newmessages) && !res) {
10042 if (vms->urgentmessages == 1)
10048 if (vms->newmessages) {
10049 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10052 if (vms->oldmessages && !res)
10055 if (vms->newmessages == 1)
10062 if (!res && vms->oldmessages) {
10063 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10067 if (vms->oldmessages == 1)
10074 if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
10092 if (vms->urgentmessages) {
10096 if (vms->urgentmessages < 5) {
10098 if (vms->urgentmessages == 1)
10099 snprintf(recname,
sizeof(recname),
"digits/1kvk");
10101 snprintf(recname,
sizeof(recname),
"digits/%dhk", vms->urgentmessages);
10105 if ((vms->oldmessages || vms->newmessages) && !res) {
10110 if (vms->newmessages) {
10111 if (vms->newmessages < 5) {
10113 if (vms->newmessages == 1)
10114 snprintf(recname,
sizeof(recname),
"digits/1kvk");
10116 snprintf(recname,
sizeof(recname),
"digits/%dhk", vms->newmessages);
10119 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10122 if (vms->oldmessages && !res)
10127 if (!res && vms->oldmessages) {
10128 if (vms->oldmessages < 5) {
10130 if (vms->oldmessages == 1)
10131 snprintf(recname,
sizeof(recname),
"digits/1kvk");
10133 snprintf(recname,
sizeof(recname),
"digits/%dhk", vms->oldmessages);
10136 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10143 if (!vms->urgentmessages && !vms->oldmessages && !vms->newmessages) {
10158 if (!vms->oldmessages && !vms->newmessages &&!vms->urgentmessages)
10163 if (!res && vms->newmessages) {
10164 res = (vms->newmessages == 1) ?
10169 say_and_wait(chan, vms->newmessages, ast_channel_language(chan)) ||
10172 if (!res && vms->oldmessages)
10175 if (!res && vms->oldmessages) {
10176 res = (vms->oldmessages == 1) ?
10181 say_and_wait(chan, vms->oldmessages, ast_channel_language(chan)) ||
10195 if (!vms->oldmessages && !vms->newmessages) {
10203 if (vms->newmessages) {
10204 num = div(vms->newmessages, 10);
10205 if (vms->newmessages == 1) {
10209 }
else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
10210 if (num.rem == 2) {
10214 res = say_and_wait(chan, vms->newmessages - 2 , ast_channel_language(chan));
10218 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10223 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10227 if (!res && vms->oldmessages)
10230 if (!res && vms->oldmessages) {
10231 num = div(vms->oldmessages, 10);
10232 if (vms->oldmessages == 1) {
10236 }
else if (num.rem > 1 && num.rem < 5 && num.quot != 1) {
10237 if (num.rem == 2) {
10241 res = say_and_wait(chan, vms->oldmessages - 2 , ast_channel_language(chan));
10245 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10250 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10269 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
10275 if (vms->newmessages) {
10276 if (vms->newmessages == 1) {
10281 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10285 if (!res && vms->oldmessages)
10288 if (!res && vms->oldmessages) {
10289 if (vms->oldmessages == 1) {
10294 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10313 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
10319 if (vms->newmessages) {
10320 if (vms->newmessages == 1) {
10325 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10329 if (!res && vms->oldmessages)
10332 if (!res && vms->oldmessages) {
10333 if (vms->oldmessages == 1) {
10338 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10357 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
10363 if (vms->newmessages) {
10364 if ((vms->newmessages == 1)) {
10369 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10373 if (!res && vms->oldmessages)
10376 if (!res && vms->oldmessages) {
10377 if (vms->oldmessages == 1) {
10382 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10399 if (vms->newmessages) {
10400 if (vms->newmessages == 1)
10403 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10406 if (vms->oldmessages && !res)
10409 if (vms->newmessages == 1)
10416 if (!res && vms->oldmessages) {
10417 if (vms->oldmessages == 1)
10420 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10424 if (vms->oldmessages == 1)
10431 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
10446 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
10454 if (vms->newmessages) {
10456 if (vms->newmessages == 1) {
10463 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10470 if (vms->oldmessages && !res)
10473 if (vms->oldmessages) {
10475 if (vms->oldmessages == 1) {
10482 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10498 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
10504 if (vms->newmessages) {
10506 res =
ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, ast_channel_language(chan),
"f");
10507 if (vms->newmessages == 1) {
10518 if (vms->oldmessages && !res)
10521 if (vms->oldmessages) {
10523 res =
ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, ast_channel_language(chan),
"f");
10524 if (vms->oldmessages == 1) {
10546 if (vms->newmessages) {
10547 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10550 if (vms->oldmessages && !res)
10553 if (vms->newmessages == 1)
10560 if (!res && vms->oldmessages) {
10561 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10565 if (vms->oldmessages == 1)
10572 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
10589 if (vms->newmessages) {
10590 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10592 if (vms->newmessages == 1)
10597 if (vms->oldmessages && !res)
10600 if (vms->newmessages == 1)
10607 if (!res && vms->oldmessages) {
10608 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10610 if (vms->oldmessages == 1)
10616 if (vms->oldmessages == 1)
10623 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
10640 if (vms->newmessages) {
10641 res =
ast_say_number(chan, vms->newmessages, AST_DIGIT_ANY, ast_channel_language(chan),
"f");
10643 if (vms->newmessages == 1) {
10653 if (vms->oldmessages && !res)
10656 if (!res && vms->oldmessages) {
10657 res =
ast_say_number(chan, vms->oldmessages, AST_DIGIT_ANY, ast_channel_language(chan),
"f");
10659 if (vms->oldmessages == 1) {
10671 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
10702 if (vms->newmessages) {
10703 if (vms->newmessages == 1) {
10706 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10709 if (vms->newmessages == 1)
10711 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
10713 if (vms->newmessages > 4)
10716 if (vms->oldmessages && !res)
10719 if (vms->newmessages == 1)
10721 if ((vms->newmessages) > 1 && (vms->newmessages < 5))
10723 if (vms->newmessages > 4)
10727 if (!res && vms->oldmessages) {
10728 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10730 if (vms->oldmessages == 1)
10732 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
10734 if (vms->oldmessages > 4)
10738 if (vms->oldmessages == 1)
10740 if ((vms->oldmessages) > 1 && (vms->oldmessages < 5))
10742 if (vms->oldmessages > 4)
10747 if (!vms->oldmessages && !vms->newmessages && !vms->urgentmessages) {
10764 if (!res && vms->newmessages) {
10767 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10772 if (vms->oldmessages && !res)
10777 if (!res && vms->oldmessages) {
10780 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10788 if (!res && !vms->oldmessages && !vms->newmessages) {
10804 if (vms->newmessages) {
10805 res = say_and_wait(chan, vms->newmessages, ast_channel_language(chan));
10808 if (vms->oldmessages && !res)
10811 if (!res && vms->oldmessages) {
10812 res = say_and_wait(chan, vms->oldmessages, ast_channel_language(chan));
10817 if (!vms->oldmessages && !vms->newmessages) {
10832 snprintf(prefile,
sizeof(prefile),
"%s%s/%s/temp", VM_SPOOL_DIR, vmu->
context, vms->username);
10838 DISPOSE(prefile, -1);
10844 }
else if (!strncasecmp(ast_channel_language(chan),
"cs", 2)) {
10845 return vm_intro_cs(chan, vms);
10846 }
else if (!strncasecmp(ast_channel_language(chan),
"cz", 2)) {
10847 static int deprecation_warning = 0;
10848 if (deprecation_warning++ % 10 == 0) {
10849 ast_log(LOG_WARNING,
"cz is not a standard language code. Please switch to using cs instead.\n");
10851 return vm_intro_cs(chan, vms);
10852 }
else if (!strncasecmp(ast_channel_language(chan),
"de", 2)) {
10853 return vm_intro_de(chan, vms);
10854 }
else if (!strncasecmp(ast_channel_language(chan),
"es", 2)) {
10855 return vm_intro_es(chan, vms);
10856 }
else if (!strncasecmp(ast_channel_language(chan),
"fr", 2)) {
10857 return vm_intro_fr(chan, vms);
10858 }
else if (!strncasecmp(ast_channel_language(chan),
"gr", 2)) {
10859 return vm_intro_gr(chan, vms);
10860 }
else if (!strncasecmp(ast_channel_language(chan),
"he", 2)) {
10861 return vm_intro_he(chan, vms);
10862 }
else if (!strncasecmp(ast_channel_language(chan),
"is", 2)) {
10863 return vm_intro_is(chan, vms);
10864 }
else if (!strncasecmp(ast_channel_language(chan),
"it", 2)) {
10865 return vm_intro_it(chan, vms);
10866 }
else if (!strncasecmp(ast_channel_language(chan),
"ja", 2)) {
10867 return vm_intro_ja(chan, vms);
10868 }
else if (!strncasecmp(ast_channel_language(chan),
"nl", 2)) {
10869 return vm_intro_nl(chan, vms);
10870 }
else if (!strncasecmp(ast_channel_language(chan),
"no", 2)) {
10871 return vm_intro_no(chan, vms);
10872 }
else if (!strncasecmp(ast_channel_language(chan),
"da", 2)) {
10873 return vm_intro_da(chan, vms);
10874 }
else if (!strncasecmp(ast_channel_language(chan),
"pl", 2)) {
10875 return vm_intro_pl(chan, vms);
10876 }
else if (!strncasecmp(ast_channel_language(chan),
"pt_BR", 5)) {
10877 return vm_intro_pt_BR(chan, vms);
10878 }
else if (!strncasecmp(ast_channel_language(chan),
"pt", 2)) {
10879 return vm_intro_pt(chan, vms);
10880 }
else if (!strncasecmp(ast_channel_language(chan),
"ru", 2)) {
10881 return vm_intro_multilang(chan, vms,
"n");
10882 }
else if (!strncasecmp(ast_channel_language(chan),
"se", 2)) {
10883 return vm_intro_se(chan, vms);
10884 }
else if (!strncasecmp(ast_channel_language(chan),
"ua", 2)) {
10885 return vm_intro_multilang(chan, vms,
"n");
10886 }
else if (!strncasecmp(ast_channel_language(chan),
"vi", 2)) {
10887 return vm_intro_vi(chan, vms);
10888 }
else if (!strncasecmp(ast_channel_language(chan),
"zh", 2)) {
10889 return vm_intro_zh(chan, vms);
10891 return vm_intro_en(chan, vms);
10895 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)
10900 if (vms->starting) {
10901 if (vms->lastmsg > -1) {
10907 res = vm_play_folder_name(chan, vms->vmbox);
10917 if (skipadvanced) {
10920 res = vm_play_folder_name(chan, vms->vmbox);
10929 if (vms->curmsg || (!in_urgent && vms->urgentmessages > 0) || (ast_test_flag(vmu,
VM_MESSAGEWRAP) && vms->lastmsg > 0)) {
10932 if (!res && !skipadvanced)
10942 if (!res && ((vms->curmsg != vms->lastmsg) || (in_urgent && vms->newmessages > 0) ||
10947 int curmsg_deleted;
10948 #ifdef IMAP_STORAGE
10949 ast_mutex_lock(&vms->lock);
10951 curmsg_deleted = vms->deleted[vms->curmsg];
10952 #ifdef IMAP_STORAGE
10953 ast_mutex_unlock(&vms->lock);
10956 if (!curmsg_deleted) {
10977 if (vms->repeats > 2) {
10985 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)
10990 if (vms->starting) {
10991 if (vms->lastmsg > -1) {
10992 res = vm_play_folder_name(chan, vms->vmbox);
11006 if (skipadvanced) {
11007 res = vm_play_folder_name(chan, vms->vmbox);
11024 if (vms->curmsg || (!in_urgent && vms->urgentmessages > 0) || (ast_test_flag(vmu,
VM_MESSAGEWRAP) && vms->lastmsg > 0)) {
11027 if (!res && !skipadvanced)
11037 if (!res && ((vms->curmsg != vms->lastmsg) || (in_urgent && vms->newmessages > 0) ||
11042 int curmsg_deleted;
11043 #ifdef IMAP_STORAGE
11044 ast_mutex_lock(&vms->lock);
11046 curmsg_deleted = vms->deleted[vms->curmsg];
11047 #ifdef IMAP_STORAGE
11048 ast_mutex_unlock(&vms->lock);
11050 if (!curmsg_deleted) {
11071 if (vms->repeats > 2) {
11081 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)
11086 if (vms->lastmsg > -1) {
11089 res = vm_play_folder_name(chan, vms->vmbox);
11099 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent, nodelete);
11105 static int vm_instructions(
struct ast_channel *chan,
struct ast_vm_user *vmu,
struct vm_state *vms,
int skipadvanced,
int in_urgent,
int nodelete)
11107 if (!strncasecmp(ast_channel_language(chan),
"ja", 2)) {
11108 return vm_instructions_ja(chan, vmu, vms, skipadvanced, in_urgent, nodelete);
11109 }
else if (vms->starting && !strncasecmp(ast_channel_language(chan),
"zh", 2)) {
11110 return vm_instructions_zh(chan, vmu, vms, skipadvanced, in_urgent, nodelete);
11112 return vm_instructions_en(chan, vmu, vms, skipadvanced, in_urgent, nodelete);
11121 char newpassword[80] =
"";
11122 char newpassword2[80] =
"";
11123 char prefile[PATH_MAX] =
"";
11124 unsigned char buf[256];
11129 bytes += adsi_logo(buf + bytes);
11130 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0,
"New User Setup",
"");
11131 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0,
"Not Done",
"");
11134 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
11139 snprintf(prefile,
sizeof(prefile),
"%s%s/%s/greet", VM_SPOOL_DIR, vmu->
context, vms->username);
11141 cmd = play_record_review(chan,
"vm-rec-name", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL, 0);
11142 if (cmd < 0 || cmd ==
't' || cmd ==
'#')
11149 snprintf(prefile,
sizeof(prefile),
"%s%s/%s/unavail", VM_SPOOL_DIR, vmu->
context, vms->username);
11151 cmd = play_record_review(chan,
"vm-rec-unv", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL, 0);
11152 if (cmd < 0 || cmd ==
't' || cmd ==
'#')
11156 snprintf(prefile,
sizeof(prefile),
"%s%s/%s/busy", VM_SPOOL_DIR, vmu->
context, vms->username);
11158 cmd = play_record_review(chan,
"vm-rec-busy", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL, 0);
11159 if (cmd < 0 || cmd ==
't' || cmd ==
'#')
11169 newpassword[1] =
'\0';
11172 newpassword[0] =
'\0';
11173 if (cmd < 0 || cmd ==
't' || cmd ==
'#')
11175 cmd =
ast_readstring(chan, newpassword + strlen(newpassword),
sizeof(newpassword) - 1, 2000, 10000,
"#");
11176 if (cmd < 0 || cmd ==
't' || cmd ==
'#')
11180 ast_log(AST_LOG_NOTICE,
"Invalid password for user %s (%s)\n", vms->username, newpassword);
11183 newpassword2[1] =
'\0';
11186 newpassword2[0] =
'\0';
11187 if (cmd < 0 || cmd ==
't' || cmd ==
'#')
11189 cmd =
ast_readstring(chan, newpassword2 + strlen(newpassword2),
sizeof(newpassword2) - 1, 2000, 10000,
"#");
11190 if (cmd < 0 || cmd ==
't' || cmd ==
'#')
11192 if (!strcmp(newpassword, newpassword2))
11194 ast_log(AST_LOG_NOTICE,
"Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
11203 if (pwdchange & PWDCHANGE_INTERNAL)
11205 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd))
11206 vm_change_password_shell(vmu, newpassword);
11208 ast_debug(1,
"User %s set password to %s of length %d\n", vms->username, newpassword, (
int) strlen(newpassword));
11219 char newpassword[80] =
"";
11220 char newpassword2[80] =
"";
11221 char prefile[PATH_MAX] =
"";
11222 unsigned char buf[256];
11224 SCOPE_ENTER(3,
"%s: %s entering mailbox options", ast_channel_name(chan), vms->username);
11228 bytes += adsi_logo(buf + bytes);
11229 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0,
"Options Menu",
"");
11230 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0,
"Not Done",
"");
11233 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
11235 while ((cmd >= 0) && (cmd !=
't')) {
11240 snprintf(prefile,
sizeof(prefile),
"%s%s/%s/unavail", VM_SPOOL_DIR, vmu->
context, vms->username);
11241 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);
11244 snprintf(prefile,
sizeof(prefile),
"%s%s/%s/busy", VM_SPOOL_DIR, vmu->
context, vms->username);
11245 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);
11248 snprintf(prefile,
sizeof(prefile),
"%s%s/%s/greet", VM_SPOOL_DIR, vmu->
context, vms->username);
11249 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);
11259 newpassword[1] =
'\0';
11262 newpassword[0] =
'\0';
11266 if ((cmd =
ast_readstring(chan, newpassword + strlen(newpassword),
sizeof(newpassword) - 1, 2000, 10000,
"#")) < 0) {
11272 ast_log(AST_LOG_NOTICE,
"Invalid password for user %s (%s)\n", vms->username, newpassword);
11279 newpassword2[1] =
'\0';
11282 newpassword2[0] =
'\0';
11287 if ((cmd =
ast_readstring(chan, newpassword2 + strlen(newpassword2),
sizeof(newpassword2) - 1, 2000, 10000,
"#")) < 0) {
11291 if (strcmp(newpassword, newpassword2)) {
11292 ast_log(AST_LOG_NOTICE,
"Password mismatch for user %s (%s != %s)\n", vms->username, newpassword, newpassword2);
11300 if (pwdchange & PWDCHANGE_INTERNAL) {
11303 if ((pwdchange & PWDCHANGE_EXTERNAL) && !ast_strlen_zero(ext_pass_cmd)) {
11304 vm_change_password_shell(vmu, newpassword);
11307 ast_debug(1,
"User %s set password to %s of length %d\n",
11308 vms->username, newpassword, (
int) strlen(newpassword));
11316 snprintf(prefile,
sizeof(prefile),
"%s%s/%s/temp", VM_SPOOL_DIR, vmu->
context, vms->username);
11317 SCOPE_CALL(-1, RETRIEVE, prefile, -1, vmu->
mailbox, vmu->
context);
11321 SCOPE_CALL(-1, DISPOSE, prefile, -1);
11335 isprint(cmd) ? cmd :
'?', isprint(cmd) ? cmd :
'?');
11340 SCOPE_EXIT_RTN_VALUE(cmd,
"Done\n");
11364 char prefile[PATH_MAX] =
"";
11365 unsigned char buf[256];
11369 bytes += adsi_logo(buf + bytes);
11370 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 3, ADSI_JUST_CENT, 0,
"Temp Greeting Menu",
"");
11371 bytes +=
ast_adsi_display(buf + bytes, ADSI_COMM_PAGE, 4, ADSI_JUST_CENT, 0,
"Not Done",
"");
11374 ast_adsi_transmit_message(chan, buf, bytes, ADSI_MSG_DISPLAY);
11378 snprintf(prefile,
sizeof(prefile),
"%s%s/%s/temp", VM_SPOOL_DIR, vmu->
context, vms->username);
11379 while ((cmd >= 0) && (cmd !=
't')) {
11384 cmd = play_record_review(chan,
"vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL, 0);
11392 cmd = play_record_review(chan,
"vm-rec-temp", prefile, maxgreet, fmtc, 0, vmu, &duration, NULL, NULL, record_gain, vms, NULL, NULL, 0);
11395 DELETE(prefile, -1, prefile, vmu);
11405 "vm-tempgreeting2" :
"vm-tempgreeting");
11416 isprint(cmd) ? cmd :
'?', isprint(cmd) ? cmd :
'?');
11419 DISPOSE(prefile, -1);
11438 if (vms->lastmsg > -1) {
11439 cmd = play_message(chan, vmu, vms);
11442 if (!strcasecmp(vms->vmbox,
"vm-INBOX") ||!strcasecmp(vms->vmbox,
"vm-Old")){
11444 snprintf(vms->fn,
sizeof(vms->fn),
"vm-%ss", vms->curbox);
11453 snprintf(vms->fn,
sizeof(vms->fn),
"vm-%s", vms->curbox);
11466 if (vms->lastmsg > -1) {
11467 cmd = play_message(chan, vmu, vms);
11469 if (!strcasecmp(vms->fn,
"INBOX")) {
11490 if (vms->lastmsg > -1) {
11491 cmd = play_message(chan, vmu, vms);
11497 snprintf(vms->fn,
sizeof(vms->fn),
"vm-%s", vms->curbox);
11518 if (vms->lastmsg > -1) {
11519 cmd = play_message(chan, vmu, vms);
11525 snprintf(vms->fn,
sizeof(vms->fn),
"vm-%s", vms->curbox);
11544 if (vms->lastmsg > -1) {
11545 cmd = play_message(chan, vmu, vms);
11547 snprintf(vms->fn,
sizeof(vms->fn),
"vm-%s", vms->curbox);
11571 if (vms->lastmsg > -1) {
11572 cmd = play_message(chan, vmu, vms);
11578 snprintf(vms->fn,
sizeof(vms->fn),
"vm-%s", vms->curbox);
11597 if (vms->lastmsg > -1) {
11598 cmd = play_message(chan, vmu, vms);
11602 snprintf(vms->fn,
sizeof(vms->fn),
"vm-%s", vms->curbox);
11623 if (vms->lastmsg > -1) {
11624 cmd = play_message(chan, vmu, vms);
11632 snprintf(vms->fn,
sizeof(vms->fn),
"vm-%s", vms->curbox);
11651 if (vms->lastmsg > -1) {
11652 cmd = play_message(chan, vmu, vms);
11656 snprintf(vms->fn,
sizeof(vms->fn),
"vm-%s", vms->curbox);
11676 if (!strncasecmp(ast_channel_language(chan),
"es", 2)) {
11678 }
else if (!strncasecmp(ast_channel_language(chan),
"gr", 2)) {
11680 }
else if (!strncasecmp(ast_channel_language(chan),
"he", 2)) {
11681 return vm_browse_messages_he(chan, vms, vmu);
11682 }
else if (!strncasecmp(ast_channel_language(chan),
"it", 2)) {
11684 }
else if (!strncasecmp(ast_channel_language(chan),
"ja", 2)) {
11686 }
else if (!strncasecmp(ast_channel_language(chan),
"pt", 2)) {
11688 }
else if (!strncasecmp(ast_channel_language(chan),
"vi", 2)) {
11690 }
else if (!strncasecmp(ast_channel_language(chan),
"zh", 2)) {
11697 static int vm_authenticate(
struct ast_channel *chan,
char *mailbox,
int mailbox_size,
11698 struct ast_vm_user *res_vmu,
const char *context,
const char *prefix,
11699 int skipuser,
int max_logins,
int silent)
11701 int useadsi = 0, valid = 0, logretries = 0;
11706 adsi_begin(chan, &useadsi);
11707 if (!skipuser && useadsi)
11709 if (!silent && !skipuser &&
ast_streamfile(chan, vm_login, ast_channel_language(chan))) {
11710 ast_log(AST_LOG_WARNING,
"Couldn't stream login file\n");
11716 while (!valid && (logretries < max_logins)) {
11718 if (!skipuser &&
ast_readstring(chan, mailbox, mailbox_size - 1, 2000, 10000,
"#") < 0) {
11719 ast_log(AST_LOG_WARNING,
"Couldn't read username\n");
11722 if (ast_strlen_zero(mailbox)) {
11723 if (ast_channel_caller(chan)->
id.number.valid && ast_channel_caller(chan)->
id.number.str) {
11724 ast_copy_string(mailbox, ast_channel_caller(chan)->
id.number.str, mailbox_size);
11726 ast_verb(3,
"Username not entered\n");
11729 }
else if (mailbox[0] ==
'*') {
11731 ast_verb(4,
"Mailbox begins with '*', attempting jump to extension 'a'\n");
11733 S_COR(ast_channel_caller(chan)->
id.number.valid, ast_channel_caller(chan)->
id.number.str, NULL))) {
11736 ast_verb(4,
"Jump to extension 'a' failed; setting mailbox to NULL\n");
11741 adsi_password(chan);
11743 if (!ast_strlen_zero(prefix)) {
11744 char fullusername[80];
11747 strncat(fullusername, mailbox,
sizeof(fullusername) - 1 - strlen(fullusername));
11751 ast_debug(1,
"Before find user for mailbox %s\n", mailbox);
11752 memset(&vmus, 0,
sizeof(vmus));
11753 vmu =
find_user(&vmus, context, mailbox);
11756 password[0] =
'\0';
11758 if (
ast_streamfile(chan, vm_password, ast_channel_language(chan))) {
11760 ast_log(AST_LOG_WARNING,
"Unable to stream password file\n");
11765 if (
ast_readstring(chan, password,
sizeof(password) - 1, 2000, 10000,
"#") < 0) {
11766 ast_log(AST_LOG_NOTICE,
"Unable to read password\n");
11769 }
else if (password[0] ==
'*') {
11771 ast_verb(4,
"Password begins with '*', attempting jump to extension 'a'\n");
11773 S_COR(ast_channel_caller(chan)->
id.number.valid, ast_channel_caller(chan)->
id.number.str, NULL))) {
11778 ast_verb(4,
"Jump to extension 'a' failed; setting mailbox and user to NULL\n");
11788 if (passptr[0] ==
'-') passptr++;
11790 if (vmu && !strcmp(passptr, password))
11793 ast_verb(3,
"Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context :
"default");
11794 if (!ast_strlen_zero(prefix))
11799 if (skipuser || logretries >= max_logins) {
11800 if (
ast_streamfile(chan,
"vm-incorrect", ast_channel_language(chan))) {
11801 ast_log(AST_LOG_WARNING,
"Unable to stream incorrect message\n");
11812 if (
ast_streamfile(chan,
"vm-incorrect-mailbox", ast_channel_language(chan))) {
11813 ast_log(AST_LOG_WARNING,
"Unable to stream incorrect mailbox message\n");
11820 if (!valid && (logretries >= max_logins)) {
11826 if (vmu && !skipuser) {
11832 static int play_message_by_id_helper(
struct ast_channel *chan,
11835 const char *msg_id)
11842 make_file(vms->fn,
sizeof(vms->fn), vms->curdir, vms->curmsg);
11844 #ifdef IMAP_STORAGE
11848 if (!ast_strlen_zero(vms->introfn) &&
ast_fileexists(vms->introfn, NULL, NULL) > 0) {
11849 wait_file(chan, vms, vms->introfn);
11854 if ((wait_file(chan, vms, vms->fn)) < 0) {
11855 ast_log(AST_LOG_WARNING,
"Playback of message %s failed\n", vms->fn);
11857 #ifdef IMAP_STORAGE
11858 ast_mutex_lock(&vms->lock);
11860 vms->heard[vms->curmsg] = 1;
11861 #ifdef IMAP_STORAGE
11862 ast_mutex_unlock(&vms->lock);
11865 DISPOSE(vms->curdir, vms->curmsg);
11884 memset(&vmus, 0,
sizeof(vmus));
11885 memset(&vms, 0,
sizeof(vms));
11887 if (!(vmu =
find_user(&vmus, context, mailbox))) {
11888 goto play_msg_cleanup;
11892 for (i = 0; i < ARRAY_LEN(mailbox_folders) && !played; i++) {
11897 if ((res = open_mailbox(&vms, vmu, i)) < 0) {
11898 ast_log(LOG_WARNING,
"Could not open mailbox %s\n", mailbox);
11900 goto play_msg_cleanup;
11905 if ((vms.lastmsg != -1) && !(play_message_by_id_helper(chan, vmu, &vms, msg_id))) {
11910 if ((res = close_mailbox(&vms, vmu) == ERROR_LOCK_PATH)) {
11912 goto play_msg_cleanup;
11923 close_mailbox(&vms, vmu);
11926 #ifdef IMAP_STORAGE
11928 vmstate_delete(&vms);
11937 static int vm_playmsgexec(
struct ast_channel *chan,
const char *data)
11940 char *mailbox = NULL;
11941 char *context = NULL;
11954 if (ast_strlen_zero(data)) {
11961 if (ast_strlen_zero(args.mailbox) || ast_strlen_zero(args.msg_id)) {
11965 if ((context = strchr(args.mailbox,
'@'))) {
11968 mailbox = args.mailbox;
11976 static int show_mailbox_details(
struct ast_cli_args *a)
11978 #define VMBOX_STRING_HEADER_FORMAT "%-32.32s %-32.32s %-16.16s %-16.16s %-16.16s %-16.16s\n"
11979 #define VMBOX_STRING_DATA_FORMAT "%-32.32s %-32.32s %-16.16s %-16.16s %-16.16s %-16.16s\n"
11981 const char *mailbox = a->argv[3];
11982 const char *context = a->argv[4];
11985 memset(&vmus, 0,
sizeof(vmus));
11986 memset(&vms, 0,
sizeof(vms));
11988 if (!(vmu =
find_user(&vmus, context, mailbox))) {
11989 ast_cli(a->fd,
"Can't find voicemail user %s@%s\n", mailbox, context);
11993 ast_cli(a->fd, VMBOX_STRING_HEADER_FORMAT,
"Full Name",
"Email",
"Pager",
"Language",
"Locale",
"Time Zone");
11999 static int show_mailbox_snapshot(
struct ast_cli_args *a)
12001 #define VM_STRING_HEADER_FORMAT "%-8.8s %-32.32s %-32.32s %-9.9s %-6.6s %-30.30s\n"
12002 const char *mailbox = a->argv[3];
12003 const char *context = a->argv[4];
12010 if (!mailbox_snapshot) {
12011 ast_cli(a->fd,
"Can't create snapshot for voicemail user %s@%s\n", mailbox, context);
12015 ast_cli(a->fd, VM_STRING_HEADER_FORMAT,
"Folder",
"Caller ID",
"Date",
"Duration",
"Flag",
"ID");
12017 for (i = 0; i < mailbox_snapshot->folders; i++) {
12019 ast_cli(a->fd, VM_STRING_HEADER_FORMAT, msg->folder_name, msg->callerid, msg->origdate, msg->duration,
12020 msg->flag, msg->msg_id);
12024 ast_cli(a->fd,
"%d Message%s Total\n", mailbox_snapshot->total_msg_num,
ESS(mailbox_snapshot->total_msg_num));
12031 static int show_messages_for_mailbox(
struct ast_cli_args *a)
12033 if (show_mailbox_details(a)){
12036 ast_cli(a->fd,
"\n");
12037 return show_mailbox_snapshot(a);
12040 static int forward_message_from_mailbox(
struct ast_cli_args *a)
12042 const char *from_mailbox = a->argv[2];
12043 const char *from_context = a->argv[3];
12044 const char *from_folder = a->argv[4];
12045 const char *
id[] = { a->argv[5] };
12046 const char *to_mailbox = a->argv[6];
12047 const char *to_context = a->argv[7];
12048 const char *to_folder = a->argv[8];
12049 int ret = vm_msg_forward(from_mailbox, from_context, from_folder, to_mailbox, to_context, to_folder, 1,
id, 0);
12051 ast_cli(a->fd,
"Error forwarding message %s from mailbox %s@%s %s to mailbox %s@%s %s\n",
12052 id[0], from_mailbox, from_context, from_folder, to_mailbox, to_context, to_folder);
12054 ast_cli(a->fd,
"Forwarded message %s from mailbox %s@%s %s to mailbox %s@%s %s\n",
12055 id[0], from_mailbox, from_context, from_folder, to_mailbox, to_context, to_folder);
12060 static int move_message_from_mailbox(
struct ast_cli_args *a)
12062 const char *mailbox = a->argv[2];
12063 const char *context = a->argv[3];
12064 const char *from_folder = a->argv[4];
12065 const char *
id[] = { a->argv[5] };
12066 const char *to_folder = a->argv[6];
12067 int ret = vm_msg_move(mailbox, context, 1, from_folder,
id, to_folder);
12069 ast_cli(a->fd,
"Error moving message %s from mailbox %s@%s %s to %s\n",
12070 id[0], mailbox, context, from_folder, to_folder);
12072 ast_cli(a->fd,
"Moved message %s from mailbox %s@%s %s to %s\n",
12073 id[0], mailbox, context, from_folder, to_folder);
12078 static int remove_message_from_mailbox(
struct ast_cli_args *a)
12080 const char *mailbox = a->argv[2];
12081 const char *context = a->argv[3];
12082 const char *folder = a->argv[4];
12083 const char *
id[] = { a->argv[5] };
12084 int ret = vm_msg_remove(mailbox, context, 1, folder,
id);
12086 ast_cli(a->fd,
"Error removing message %s from mailbox %s@%s %s\n",
12087 id[0], mailbox, context, folder);
12089 ast_cli(a->fd,
"Removed message %s from mailbox %s@%s %s\n",
12090 id[0], mailbox, context, folder);
12095 static char *complete_voicemail_show_mailbox(
struct ast_cli_args *a)
12097 const char *word = a->word;
12103 const char *context =
"", *mailbox =
"";
12108 wordlen = strlen(word);
12111 if (!strncasecmp(word, vmu->
mailbox , wordlen)) {
12112 if (mailbox && strcmp(mailbox, vmu->
mailbox) && ++which > state) {
12121 }
else if (pos == 4) {
12123 const char *box = a->argv[3];
12124 wordlen = strlen(word);
12127 if (!strncasecmp(word, vmu->
context, wordlen) && !strcasecmp(box, vmu->
mailbox)) {
12128 if (context && strcmp(context, vmu->
context) && ++which > state) {
12146 e->
command =
"voicemail show mailbox";
12148 "Usage: voicemail show mailbox <mailbox> <context>\n"
12149 " Show contents of mailbox <mailbox>@<context>\n";
12152 return complete_voicemail_show_mailbox(a);
12157 if (a->argc != 5) {
12158 return CLI_SHOWUSAGE;
12161 if (show_messages_for_mailbox(a)) {
12162 return CLI_FAILURE;
12165 return CLI_SUCCESS;
12185 static char *complete_voicemail_move_message(
struct ast_cli_args *a,
int maxpos)
12187 const char *word = a->word;
12193 const char *context =
"", *mailbox =
"", *folder =
"", *
id =
"";
12196 if (pos > maxpos) {
12202 if (pos == 2 || (pos == 6 && maxpos == 8)) {
12204 wordlen = strlen(word);
12207 if (!strncasecmp(word, vmu->
mailbox , wordlen)) {
12208 if (mailbox && strcmp(mailbox, vmu->
mailbox) && ++which > state) {
12217 }
else if (pos == 3 || pos == 7) {
12219 mailbox = (pos == 3) ? a->argv[2] : a->argv[6];
12220 wordlen = strlen(word);
12223 if (!strncasecmp(word, vmu->
context, wordlen) && !strcasecmp(mailbox, vmu->
mailbox)) {
12224 if (context && strcmp(context, vmu->
context) && ++which > state) {
12233 }
else if (pos == 4 || pos == 8 || (pos == 6 && maxpos == 6) ) {
12236 wordlen = strlen(word);
12237 for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
12238 if (folder && !strncasecmp(word, mailbox_folders[i], wordlen) && ++which > state) {
12241 folder = mailbox_folders[i];
12243 }
else if (pos == 5) {
12247 mailbox = a->argv[2];
12248 context = a->argv[3];
12249 folder = a->argv[4];
12250 wordlen = strlen(word);
12256 for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
12257 if (!strcasecmp(mailbox_folders[i], folder)) {
12262 if (
id && !strncasecmp(word, msg->msg_id, wordlen) && ++which > state) {
12280 e->
command =
"voicemail forward";
12282 "Usage: voicemail forward <from_mailbox> <from_context> <from_folder> <messageid> <to_mailbox> <to_context> <to_folder>\n"
12283 " Forward message <messageid> in mailbox <mailbox>@<context> <from_folder>\n"
12284 " to mailbox <mailbox>@<context> <to_folder>\n";
12287 return complete_voicemail_move_message(a, 8);
12292 if (a->argc != 9) {
12293 return CLI_SHOWUSAGE;
12296 if (forward_message_from_mailbox(a)) {
12297 return CLI_FAILURE;
12300 return CLI_SUCCESS;
12307 e->
command =
"voicemail move";
12309 "Usage: voicemail move <mailbox> <context> <from_folder> <messageid> <to_folder>\n"
12310 " Move message <messageid> in mailbox <mailbox>&<context> from <from_folder> to <to_folder>\n";
12313 return complete_voicemail_move_message(a, 6);
12318 if (a->argc != 7) {
12319 return CLI_SHOWUSAGE;
12322 if (move_message_from_mailbox(a)) {
12323 return CLI_FAILURE;
12326 return CLI_SUCCESS;
12333 e->
command =
"voicemail remove";
12335 "Usage: voicemail remove <mailbox> <context> <from_folder> <messageid>\n"
12336 " Remove message <messageid> from <from_folder> in mailbox <mailbox>@<context>\n";
12339 return complete_voicemail_move_message(a, 5);
12344 if (a->argc != 6) {
12345 return CLI_SHOWUSAGE;
12348 if (remove_message_from_mailbox(a)) {
12349 return CLI_FAILURE;
12352 return CLI_SUCCESS;
12355 static int vm_execmain(
struct ast_channel *chan,
const char *data)
12363 char prefixstr[80] =
"";
12364 char ext_context[256]=
"";
12370 char *context = NULL;
12371 int silentexit = 0;
12373 signed char record_gain = 0;
12375 int play_folder = 0;
12378 #ifdef IMAP_STORAGE
12381 SCOPE_ENTER(3,
"%s:\n", ast_channel_name(chan));
12392 if (!ast_strlen_zero(data)) {
12393 char *opts[OPT_ARG_ARRAY_SIZE];
12404 if (args.argc == 2) {
12406 SCOPE_EXIT_LOG_RTN_VALUE(-1, AST_LOG_WARNING,
"Invalid option string '%s'\n", args.argv1);
12408 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
12410 if (!ast_strlen_zero(opts[OPT_ARG_RECORDGAIN])) {
12411 if (sscanf(opts[OPT_ARG_RECORDGAIN],
"%30d", &gain) != 1) {
12412 SCOPE_EXIT_LOG_RTN_VALUE(-1, AST_LOG_WARNING,
"Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
12414 record_gain = (
signed char) gain;
12417 ast_log(AST_LOG_WARNING,
"Invalid Gain level set with option g\n");
12420 if (ast_test_flag(&flags, OPT_AUTOPLAY) ) {
12422 if (!ast_strlen_zero(opts[OPT_ARG_PLAYFOLDER])) {
12424 if (isdigit(opts[OPT_ARG_PLAYFOLDER][0])) {
12425 if (sscanf(opts[OPT_ARG_PLAYFOLDER],
"%30d", &play_folder) != 1) {
12429 play_folder = get_folder_by_name(opts[OPT_ARG_PLAYFOLDER]);
12432 ast_log(AST_LOG_WARNING,
"Invalid folder set with option a\n");
12434 if (play_folder > 9 || play_folder < 0) {
12435 ast_log(AST_LOG_WARNING,
12436 "Invalid value '%s' provided for folder autoplay option. Defaulting to 'INBOX'\n",
12437 opts[OPT_ARG_PLAYFOLDER]);
12441 if (ast_test_flag(&flags, OPT_READONLY)) {
12446 while (*(args.argv0)) {
12447 if (*(args.argv0) ==
's')
12448 ast_set_flag(&flags, OPT_SILENT);
12449 else if (*(args.argv0) ==
'p')
12450 ast_set_flag(&flags, OPT_PREPEND_MAILBOX);
12458 valid = ast_test_flag(&flags, OPT_SILENT);
12460 if ((context = strchr(args.argv0,
'@')))
12463 if (ast_test_flag(&flags, OPT_PREPEND_MAILBOX))
12468 if (!ast_strlen_zero(vms.username)) {
12469 if ((vmu =
find_user(&vmus, context ,vms.username))) {
12472 ast_log(LOG_WARNING,
"Mailbox '%s%s%s' doesn't exist\n", vms.username, context ?
"@":
"", context ? context :
"");
12481 res = vm_authenticate(chan, vms.username,
sizeof(vms.username), &vmus, context, prefixstr, skipuser, maxlogins, 0);
12483 ast_trace(-1,
"vm_authenticate user: %s\n", vms.username);
12485 if (vms.username[0] ==
'*') {
12486 ast_trace(-1,
"user pressed * in context '%s'\n", ast_channel_context(chan));
12505 adsi_begin(chan, &useadsi);
12508 ast_trace(-1,
"Invalid user\n");
12513 #ifdef IMAP_STORAGE
12514 pthread_once(&ts_vmstate.once, ts_vmstate.key_init);
12515 pthread_setspecific(ts_vmstate.key, &vms);
12517 vms.interactive = 1;
12521 vmstate_insert(&vms);
12522 init_vm_state(&vms);
12526 if (!ast_strlen_zero(vmu->
language)) {
12527 ast_channel_lock(chan);
12528 ast_channel_language_set(chan, vmu->
language);
12529 ast_channel_unlock(chan);
12533 ast_trace(-1,
"Before open_mailbox\n");
12534 res = SCOPE_CALL_WITH_INT_RESULT(-1, open_mailbox, &vms, vmu, OLD_FOLDER);
12536 ast_trace(-1,
"open mailbox: %d\n", res);
12539 vms.oldmessages = vms.lastmsg + 1;
12540 ast_trace(-1,
"Number of old messages: %d\n", vms.oldmessages);
12542 res = SCOPE_CALL_WITH_INT_RESULT(-1, open_mailbox, &vms, vmu, NEW_FOLDER);
12544 ast_trace(-1,
"open mailbox: %d\n", res);
12547 vms.newmessages = vms.lastmsg + 1;
12548 ast_trace(-1,
"Number of new messages: %d\n", vms.newmessages);
12551 res = SCOPE_CALL_WITH_INT_RESULT(-1, open_mailbox, &vms, vmu, 11);
12553 ast_trace(-1,
"open mailbox: %d\n", res);
12556 vms.urgentmessages = vms.lastmsg + 1;
12557 ast_trace(-1,
"Number of urgent messages: %d\n", vms.urgentmessages);
12562 if (vms.urgentmessages) {
12564 res = SCOPE_CALL_WITH_INT_RESULT(-1, open_mailbox, &vms, vmu, 11);
12567 res = SCOPE_CALL_WITH_INT_RESULT(-1, open_mailbox, &vms, vmu, play_folder);
12570 ast_trace(-1,
"open mailbox: %d\n", res);
12575 if (vms.lastmsg == -1) {
12582 if (!vms.newmessages && !vms.urgentmessages && vms.oldmessages) {
12584 res = SCOPE_CALL_WITH_INT_RESULT(-1, open_mailbox, &vms, vmu, OLD_FOLDER);
12589 }
else if (!vms.urgentmessages && vms.newmessages) {
12592 res = SCOPE_CALL_WITH_INT_RESULT(-1, open_mailbox, &vms, vmu, NEW_FOLDER);
12599 adsi_status(chan, &vms);
12606 ast_log(AST_LOG_WARNING,
"Couldn't stream new user file\n");
12607 cmd = vm_newuser_setup(chan, vmu, &vms, vmfmts, record_gain);
12608 if ((cmd ==
't') || (cmd ==
'#')) {
12612 ast_trace(-1,
"Timeout\n");
12614 }
else if (cmd < 0) {
12618 ast_trace(-1,
"Hangup\n");
12622 #ifdef IMAP_STORAGE
12623 ast_debug(3,
"Checking quotas: comparing %u to %u\n", vms.quota_usage, vms.quota_limit);
12624 if (vms.quota_limit && vms.quota_usage >= vms.quota_limit) {
12625 ast_debug(1,
"*** QUOTA EXCEEDED!!\n");
12628 ast_debug(3,
"Checking quotas: User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->
maxmsg);
12629 if ((vms.newmessages + vms.oldmessages) >= vmu->
maxmsg) {
12630 ast_log(AST_LOG_WARNING,
"No more messages possible. User has %d messages and limit is %d.\n", (vms.newmessages + vms.oldmessages), vmu->
maxmsg);
12639 cmd = vm_intro(chan, vmu, &vms);
12642 isprint(cmd) ? cmd :
'?', isprint(cmd) ? cmd :
'?');
12646 while ((cmd > -1) && (cmd !=
't') && (cmd !=
'#')) {
12648 ast_trace(-1,
"Main menu: %d %c\n", cmd, (cmd >= 32 && cmd <= 126 ? cmd :
' '));
12660 adsi_folders(chan, 0,
"Change to folder...");
12664 isprint(cmd) ? cmd :
'?', isprint(cmd) ? cmd :
'?');
12667 }
else if (cmd > 0) {
12669 res = SCOPE_CALL_WITH_INT_RESULT(-1, close_mailbox, &vms, vmu);
12670 if (res == ERROR_LOCK_PATH) {
12671 ast_trace(-1,
"close mailbox: %d\n", res);
12675 if (cmd != 11) in_urgent = 0;
12676 res = SCOPE_CALL_WITH_INT_RESULT(-1, open_mailbox, &vms, vmu, cmd);
12678 ast_trace(-1,
"open mailbox: %d\n", res);
12685 adsi_status2(chan, &vms);
12688 cmd = vm_play_folder_name(chan, vms.vmbox);
12698 while ((cmd > -1) && (cmd !=
't') && (cmd !=
'#')) {
12701 if (vms.lastmsg > -1 && !vms.starting) {
12703 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
12705 ast_trace(-1,
"advanced options: %d\n", cmd);
12715 ast_verb(3,
"Callback Requested\n");
12716 if (!ast_strlen_zero(vmu->callback) && vms.lastmsg > -1 && !vms.starting) {
12718 ast_trace(-1,
"advanced options: %d\n", cmd);
12722 }
else if (cmd == ERROR_LOCK_PATH) {
12732 if (vms.lastmsg > -1 && !vms.starting) {
12734 if (cmd == ERROR_LOCK_PATH) {
12736 ast_trace(-1,
"advanced options: %d\n", cmd);
12745 if (!ast_strlen_zero(vmu->dialout)) {
12746 cmd = dialout(chan, vmu, NULL, vmu->dialout);
12749 ast_trace(-1,
"dialout: %d\n", cmd);
12760 cmd = SCOPE_CALL_WITH_INT_RESULT(-1,
forward_message, chan, context, &vms, vmu, vmfmts, 1, record_gain, 0);
12761 if (cmd == ERROR_LOCK_PATH || cmd == OPERATOR_EXIT) {
12763 ast_trace(-1,
"forward message: %d\n", cmd);
12778 if (!vms.starting) {
12781 if (!ast_strlen_zero(vmu->callback) && !vms.starting && !cmd) {
12784 if (!cmd && !vms.starting) {
12787 if (!ast_strlen_zero(vmu->dialout) && !cmd) {
12790 if (ast_test_flag(vmu,
VM_SVMAIL) && !cmd) {
12802 if (vms.repeats > 3) {
12806 isprint(cmd) ? cmd :
'?', isprint(cmd) ? cmd :
'?');
12816 if (vms.curmsg > 0) {
12818 cmd = SCOPE_CALL_WITH_INT_RESULT(-1, play_message, chan, vmu, &vms);
12824 if (in_urgent == 0 && vms.urgentmessages > 0) {
12827 res = SCOPE_CALL_WITH_INT_RESULT(-1, close_mailbox, &vms, vmu);
12828 if (res == ERROR_LOCK_PATH) {
12829 ast_trace(-1,
"close mailbox: %d\n", res);
12832 res = SCOPE_CALL_WITH_INT_RESULT(-1, open_mailbox, &vms, vmu, 11);
12834 ast_trace(-1,
"open mailbox: %d\n", res);
12837 ast_debug(1,
"No more new messages, opened INBOX and got %d Urgent messages\n", vms.lastmsg + 1);
12838 vms.curmsg = vms.lastmsg;
12839 if (vms.lastmsg < 0) {
12842 }
else if (ast_test_flag(vmu,
VM_MESSAGEWRAP) && vms.lastmsg > 0) {
12843 vms.curmsg = vms.lastmsg;
12844 cmd = SCOPE_CALL_WITH_INT_RESULT(-1, play_message, chan, vmu, &vms);
12852 if (vms.curmsg < vms.lastmsg) {
12854 cmd = SCOPE_CALL_WITH_INT_RESULT(-1, play_message, chan, vmu, &vms);
12856 if (in_urgent && vms.newmessages > 0) {
12862 res = SCOPE_CALL_WITH_INT_RESULT(-1, close_mailbox, &vms, vmu);
12863 if (res == ERROR_LOCK_PATH) {
12864 ast_trace(-1,
"close mailbox: %d\n", res);
12867 res = SCOPE_CALL_WITH_INT_RESULT(-1, open_mailbox, &vms, vmu, NEW_FOLDER);
12869 ast_trace(-1,
"open mailbox: %d\n", res);
12872 ast_debug(1,
"No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
12874 if (vms.lastmsg < 0) {
12877 }
else if (ast_test_flag(vmu,
VM_MESSAGEWRAP) && vms.lastmsg > 0) {
12879 cmd = SCOPE_CALL_WITH_INT_RESULT(-1, play_message, chan, vmu, &vms);
12886 if (!nodelete && vms.curmsg >= 0 && vms.curmsg <= vms.lastmsg) {
12887 vms.deleted[vms.curmsg] = !vms.deleted[vms.curmsg];
12889 adsi_delete(chan, &vms);
12890 if (vms.deleted[vms.curmsg]) {
12891 if (play_folder == 0) {
12893 vms.urgentmessages--;
12898 else if (play_folder == 1)
12902 if (play_folder == 0) {
12904 vms.urgentmessages++;
12909 else if (play_folder == 1)
12914 if (vms.curmsg < vms.lastmsg) {
12916 cmd = SCOPE_CALL_WITH_INT_RESULT(-1, play_message, chan, vmu, &vms);
12917 }
else if (ast_test_flag(vmu,
VM_MESSAGEWRAP) && vms.lastmsg > 0) {
12919 cmd = SCOPE_CALL_WITH_INT_RESULT(-1, play_message, chan, vmu, &vms);
12925 if (in_urgent == 1) {
12928 res = SCOPE_CALL_WITH_INT_RESULT(-1, close_mailbox, &vms, vmu);
12929 if (res == ERROR_LOCK_PATH) {
12930 ast_trace(-1,
"close mailbox: %d\n", res);
12933 res = SCOPE_CALL_WITH_INT_RESULT(-1, open_mailbox, &vms, vmu, NEW_FOLDER);
12935 ast_trace(-1,
"open mailbox: %d\n", res);
12938 ast_debug(1,
"No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
12940 if (vms.lastmsg < 0) {
12950 #ifdef IMAP_STORAGE
12956 if (vms.lastmsg > -1) {
12957 cmd = SCOPE_CALL_WITH_INT_RESULT(-1,
forward_message, chan, context, &vms, vmu, vmfmts, 0, record_gain, in_urgent);
12958 if (cmd == ERROR_LOCK_PATH) {
12960 ast_trace(-1,
"forward message: %d\n", res);
12968 if (in_urgent == 1 && vms.newmessages > 0) {
12971 res = SCOPE_CALL_WITH_INT_RESULT(-1, close_mailbox, &vms, vmu);
12972 if (res == ERROR_LOCK_PATH) {
12973 ast_trace(-1,
"close mailbox: %d\n", res);
12976 res = SCOPE_CALL_WITH_INT_RESULT(-1, open_mailbox, &vms, vmu, NEW_FOLDER);
12978 ast_trace(-1,
"open mailbox: %d\n", res);
12981 ast_debug(1,
"No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
12983 if (vms.lastmsg < 0) {
12993 if (vms.curmsg < 0 || vms.curmsg > vms.lastmsg) {
12999 adsi_folders(chan, 1,
"Save to folder...");
13002 isprint(cmd) ? cmd :
'?', isprint(cmd) ? cmd :
'?');
13007 }
else if (cmd > 0) {
13008 box = cmd = cmd -
'0';
13009 cmd = SCOPE_CALL_WITH_INT_RESULT(-1,
save_to_folder, vmu, &vms, vms.curmsg, cmd, NULL, 0);
13010 if (cmd == ERROR_LOCK_PATH) {
13012 ast_trace(-1,
"save to folder: %d\n", res);
13014 #ifndef IMAP_STORAGE
13016 vms.deleted[vms.curmsg] = 1;
13019 vms.deleted[vms.curmsg] = 0;
13020 vms.heard[vms.curmsg] = 0;
13023 make_file(vms.fn,
sizeof(vms.fn), vms.curdir, vms.curmsg);
13025 adsi_message(chan, &vms);
13026 snprintf(vms.fn,
sizeof(vms.fn),
"vm-%s", mbox(vmu, box));
13030 cmd = say_and_wait(chan, vms.curmsg + 1, ast_channel_language(chan));
13034 cmd = vm_play_folder_name(chan, vms.fn);
13039 if (vms.curmsg < vms.lastmsg) {
13041 cmd = SCOPE_CALL_WITH_INT_RESULT(-1, play_message, chan, vmu, &vms);
13042 }
else if (ast_test_flag(vmu,
VM_MESSAGEWRAP) && vms.lastmsg > 0) {
13044 cmd = SCOPE_CALL_WITH_INT_RESULT(-1, play_message, chan, vmu, &vms);
13050 if (in_urgent == 1 && vms.newmessages > 0) {
13053 res = SCOPE_CALL_WITH_INT_RESULT(-1, close_mailbox, &vms, vmu);
13054 if (res == ERROR_LOCK_PATH) {
13055 ast_trace(-1,
"close mailbox: %d\n", res);
13058 res = SCOPE_CALL_WITH_INT_RESULT(-1, open_mailbox, &vms, vmu, NEW_FOLDER);
13060 ast_trace(-1,
"open mailbox: %d\n", res);
13063 ast_debug(1,
"No more urgent messages, opened INBOX and got %d new messages\n", vms.lastmsg + 1);
13065 if (vms.lastmsg < 0) {
13075 if (!vms.starting) {
13076 if (!strncasecmp(ast_channel_language(chan),
"ja", 2)) {
13077 cmd = vm_play_folder_name(chan, vms.vmbox);
13089 cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent, nodelete);
13093 if (!strncasecmp(ast_channel_language(chan),
"he", 2)) {
13097 cmd = vm_play_folder_name(chan, vms.vmbox);
13101 cmd = vm_instructions(chan, vmu, &vms, 1, in_urgent, nodelete);
13106 cmd = SCOPE_CALL_WITH_INT_RESULT(-1, vm_options,chan, vmu, &vms, vmfmts, record_gain);
13108 adsi_status(chan, &vms);
13110 res = SCOPE_CALL_WITH_INT_RESULT(-1, open_mailbox, &vms, vmu, play_folder);
13112 ast_trace(-1,
"open mailbox: %d\n", res);
13119 cmd = vm_instructions(chan, vmu, &vms, 0, in_urgent, nodelete);
13123 if ((cmd ==
't') || (cmd ==
'#')) {
13134 adsi_goodbye(chan);
13135 if (valid && res != OPERATOR_EXIT) {
13141 if ((valid && res > 0) || res == OPERATOR_EXIT) {
13145 ast_adsi_unload_session(chan);
13148 SCOPE_CALL(-1, close_mailbox, &vms, vmu);
13151 int new = 0, old = 0, urgent = 0;
13152 snprintf(ext_context,
sizeof(ext_context),
"%s@%s", vms.username, vmu->
context);
13156 queue_mwi_event(ast_channel_uniqueid(chan), ext_context, urgent,
new, old);
13158 #ifdef IMAP_STORAGE
13160 ast_debug(3,
"*** Checking if we can expunge, deleted set to %d, expungeonhangup set to %d\n", deleted, expungeonhangup);
13161 if (vmu && deleted == 1 && expungeonhangup == 1 && vms.mailstream != NULL) {
13162 ast_mutex_lock(&vms.lock);
13163 #ifdef HAVE_IMAP_TK2006
13164 if (LEVELUIDPLUS (vms.mailstream)) {
13165 mail_expunge_full(vms.mailstream, NIL, EX_UID);
13168 mail_expunge(vms.mailstream);
13169 ast_mutex_unlock(&vms.lock);
13174 vmstate_delete(&vms);
13180 #ifdef IMAP_STORAGE
13181 pthread_setspecific(ts_vmstate.key, NULL);
13183 SCOPE_EXIT_RTN_VALUE(res,
"Done. RC: %d\n", res);
13186 static int vm_exec(
struct ast_channel *chan,
const char *data)
13192 char *opts[OPT_ARG_ARRAY_SIZE];
13197 SCOPE_ENTER(3,
"%s\n", ast_channel_name(chan));
13199 memset(&leave_options, 0,
sizeof(leave_options));
13201 if (!ast_strlen_zero(data)) {
13204 if (args.argc == 2) {
13206 SCOPE_EXIT_RTN_VALUE(-1,
"parse options failed for '%s'\n", args.argv1);
13208 ast_copy_flags(&leave_options, &flags, OPT_SILENT | OPT_SILENT_IF_GREET | OPT_BUSY_GREETING | OPT_UNAVAIL_GREETING | OPT_MESSAGE_Urgent | OPT_MESSAGE_PRIORITY | OPT_DTMFEXIT);
13209 if (ast_test_flag(&flags, OPT_RECORDGAIN)) {
13212 if (sscanf(opts[OPT_ARG_RECORDGAIN],
"%30d", &gain) != 1) {
13213 SCOPE_EXIT_LOG_RTN_VALUE(-1, AST_LOG_WARNING,
"Invalid value '%s' provided for record gain option\n", opts[OPT_ARG_RECORDGAIN]);
13215 leave_options.record_gain = (
signed char) gain;
13218 if (ast_test_flag(&flags, OPT_DTMFEXIT)) {
13219 if (!ast_strlen_zero(opts[OPT_ARG_DTMFEXIT]))
13220 leave_options.exitcontext = opts[OPT_ARG_DTMFEXIT];
13223 if (ast_test_flag(&flags, OPT_BEEP)) {
13224 leave_options.beeptone = opts[OPT_ARG_BEEP_TONE];
13226 leave_options.beeptone =
"beep";
13230 res =
ast_app_getdata(chan,
"vm-whichbox", temp,
sizeof(temp) - 1, 0);
13232 SCOPE_EXIT_RTN_VALUE(res,
"getdata failed. RC: %d", res);
13234 if (ast_strlen_zero(temp)) {
13235 SCOPE_EXIT_RTN_VALUE(0);
13241 if (ast_test_flag(&flags, OPT_EARLYM_GREETING)) {
13248 res = SCOPE_CALL_WITH_INT_RESULT(-1,
leave_voicemail, chan, args.argv0, &leave_options);
13254 if (res == OPERATOR_EXIT) {
13258 if (res == ERROR_LOCK_PATH) {
13259 ast_log(AST_LOG_ERROR,
"Could not leave voicemail. The path is already locked.\n");
13264 SCOPE_EXIT_RTN_VALUE(res,
"Done. RC: %d", res);
13267 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)
13273 var = ast_variable_new(
"msg_id",
id,
"");
13280 ast_log(LOG_ERROR,
"Voicemail data file %s/%d.txt has no [message] category?\n", dir, msg);
13285 ast_variable_append(cat, var);
13288 ast_log(LOG_WARNING,
"Unable to update %s to have a message ID\n", filename);
13292 UPDATE_MSG_ID(dir, msg,
id, vmu, msg_cfg, folder);
13296 static struct ast_vm_user *find_or_create(
const char *context,
const char *box)
13300 if (!ast_strlen_zero(box) && box[0] ==
'*') {
13301 ast_log(LOG_WARNING,
"Mailbox %s in context %s begins with '*' character. The '*' character,"
13302 "\n\twhen it is the first character in a mailbox or password, is used to jump to a"
13303 "\n\tpredefined extension 'a'. A mailbox or password beginning with '*' is not valid"
13304 "\n\tand will be ignored.\n", box, context);
13309 if (ast_test_flag((&globalflags),
VM_SEARCH) && !strcasecmp(box, vmu->
mailbox)) {
13310 if (strcasecmp(vmu->
context, context)) {
13311 ast_log(LOG_WARNING,
"\nIt has been detected that you have defined mailbox '%s' in separate\
13312 \n\tcontexts and that you have the 'searchcontexts' option on. This type of\
13313 \n\tconfiguration creates an ambiguity that you likely do not want. Please\
13314 \n\tamend your voicemail.conf file to avoid this situation.\n", box);
13316 ast_log(LOG_WARNING,
"Ignoring duplicated mailbox %s\n", box);
13319 if (!strcasecmp(context, vmu->
context) && !strcasecmp(box, vmu->
mailbox)) {
13320 ast_log(LOG_WARNING,
"Ignoring duplicated mailbox %s in context %s\n", box, context);
13336 static int append_mailbox(
const char *context,
const char *box,
const char *data)
13343 char mailbox_full[MAX_VM_MAILBOX_LEN];
13344 int new = 0, old = 0, urgent = 0;
13345 char secretfn[PATH_MAX] =
"";
13349 if (!(vmu = find_or_create(context, box)))
13355 if ((s = strsep(&stringp,
","))) {
13356 if (!ast_strlen_zero(s) && s[0] ==
'*') {
13357 ast_log(LOG_WARNING,
"Invalid password detected for mailbox %s. The password"
13358 "\n\tmust be reset in voicemail.conf.\n", box);
13363 if (stringp && (s = strsep(&stringp,
","))) {
13366 if (stringp && (s = strsep(&stringp,
","))) {
13369 if (stringp && (s = strsep(&stringp,
","))) {
13377 case OPT_PWLOC_SPOOLDIR:
13378 snprintf(secretfn,
sizeof(secretfn),
"%s%s/%s/secret.conf", VM_SPOOL_DIR, vmu->
context, vmu->
mailbox);
13382 snprintf(mailbox_full, MAX_VM_MAILBOX_LEN,
"%s%s%s",
13384 ast_strlen_zero(context) ?
"" :
"@",
13388 #ifdef IMAP_STORAGE
13389 imap_logout(mailbox_full);
13391 queue_mwi_event(NULL, mailbox_full, urgent,
new, old);
13396 #ifdef TEST_FRAMEWORK
13402 static const char options_string[] =
"attach=yes|attachfmt=wav49|"
13403 "serveremail=someguy@digium.com|fromstring=Voicemail System|tz=central|delete=yes|saycid=yes|"
13404 "sendvoicemail=yes|review=yes|tempgreetwarn=yes|messagewrap=yes|operator=yes|leaveurgent=yes|"
13405 "envelope=yes|moveheard=yes|sayduration=yes|saydurationm=5|forcename=yes|"
13406 "forcegreetings=yes|callback=somecontext|dialout=somecontext2|"
13407 "exitcontext=somecontext3|minsecs=10|maxsecs=100|nextaftercmd=yes|"
13408 "backupdeleted=50|volgain=1.3|passwordlocation=spooldir|emailbody="
13409 "Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message|emailsubject="
13410 "[PBX]: New message \\\\${VM_MSGNUM}\\\\ in mailbox ${VM_MAILBOX}";
13411 #ifdef IMAP_STORAGE
13412 static const char option_string2[] =
"imapuser=imapuser|imappassword=imappasswd|"
13413 "imapfolder=INBOX|imapvmshareid=6000|imapserver=imapserver|imapport=1234|imapflags=flagged";
13418 info->name =
"vmuser";
13419 info->category =
"/apps/app_voicemail/";
13420 info->summary =
"Vmuser unit test";
13421 info->description =
13422 "This tests passing all supported parameters to apply_options, the voicemail user config parser";
13423 return AST_TEST_NOT_RUN;
13429 return AST_TEST_NOT_RUN;
13437 ast_test_status_update(
test,
"Parse failure for attach option\n");
13440 if (strcasecmp(vmu->
attachfmt,
"wav49")) {
13441 ast_test_status_update(
test,
"Parse failure for attachfmt option\n");
13444 if (strcasecmp(vmu->
fromstring,
"Voicemail System")) {
13445 ast_test_status_update(
test,
"Parse failure for fromstring option\n");
13448 if (strcasecmp(vmu->
serveremail,
"someguy@digium.com")) {
13449 ast_test_status_update(
test,
"Parse failure for serveremail option\n");
13452 if (!vmu->
emailsubject || strcasecmp(vmu->
emailsubject,
"[PBX]: New message \\${VM_MSGNUM}\\ in mailbox ${VM_MAILBOX}")) {
13453 ast_test_status_update(
test,
"Parse failure for emailsubject option\n");
13456 if (!vmu->
emailbody || strcasecmp(vmu->
emailbody,
"Dear ${VM_NAME}:\n\n\tYou were just left a ${VM_DUR} long message")) {
13457 ast_test_status_update(
test,
"Parse failure for emailbody option\n");
13460 if (strcasecmp(vmu->
zonetag,
"central")) {
13461 ast_test_status_update(
test,
"Parse failure for tz option\n");
13465 ast_test_status_update(
test,
"Parse failure for delete option\n");
13469 ast_test_status_update(
test,
"Parse failure for saycid option\n");
13473 ast_test_status_update(
test,
"Parse failure for sendvoicemail option\n");
13477 ast_test_status_update(
test,
"Parse failure for review option\n");
13481 ast_test_status_update(
test,
"Parse failure for leaveurgent option\n");
13485 ast_test_status_update(
test,
"Parse failure for tempgreetwarm option\n");
13489 ast_test_status_update(
test,
"Parse failure for messagewrap option\n");
13493 ast_test_status_update(
test,
"Parse failure for operator option\n");
13497 ast_test_status_update(
test,
"Parse failure for envelope option\n");
13501 ast_test_status_update(
test,
"Parse failure for moveheard option\n");
13505 ast_test_status_update(
test,
"Parse failure for sayduration option\n");
13508 if (vmu->saydurationm != 5) {
13509 ast_test_status_update(
test,
"Parse failure for saydurationm option\n");
13513 ast_test_status_update(
test,
"Parse failure for forcename option\n");
13517 ast_test_status_update(
test,
"Parse failure for forcegreetings option\n");
13520 if (strcasecmp(vmu->callback,
"somecontext")) {
13521 ast_test_status_update(
test,
"Parse failure for callbacks option\n");
13524 if (strcasecmp(vmu->dialout,
"somecontext2")) {
13525 ast_test_status_update(
test,
"Parse failure for dialout option\n");
13528 if (strcasecmp(vmu->exit,
"somecontext3")) {
13529 ast_test_status_update(
test,
"Parse failure for exitcontext option\n");
13533 ast_test_status_update(
test,
"Parse failure for minsecs option\n");
13537 ast_test_status_update(
test,
"Parse failure for maxsecs option\n");
13541 ast_test_status_update(
test,
"Parse failure for nextaftercmd option\n");
13545 ast_test_status_update(
test,
"Parse failure for backupdeleted option\n");
13549 ast_test_status_update(
test,
"Parse failure for volgain option\n");
13553 ast_test_status_update(
test,
"Parse failure for passwordlocation option\n");
13556 #ifdef IMAP_STORAGE
13559 if (strcasecmp(vmu->imapuser,
"imapuser")) {
13560 ast_test_status_update(
test,
"Parse failure for imapuser option\n");
13563 if (strcasecmp(vmu->imappassword,
"imappasswd")) {
13564 ast_test_status_update(
test,
"Parse failure for imappasswd option\n");
13567 if (strcasecmp(vmu->imapfolder,
"INBOX")) {
13568 ast_test_status_update(
test,
"Parse failure for imapfolder option\n");
13571 if (strcasecmp(vmu->imapvmshareid,
"6000")) {
13572 ast_test_status_update(
test,
"Parse failure for imapvmshareid option\n");
13575 if (strcasecmp(vmu->imapserver,
"imapserver")) {
13576 ast_test_status_update(
test,
"Parse failure for imapserver option\n");
13579 if (strcasecmp(vmu->imapport,
"1234")) {
13580 ast_test_status_update(
test,
"Parse failure for imapport option\n");
13583 if (strcasecmp(vmu->imapflags,
"flagged")) {
13584 ast_test_status_update(
test,
"Parse failure for imapflags option\n");
13591 return res ? AST_TEST_FAIL : AST_TEST_PASS;
13595 static int acf_vm_info(
struct ast_channel *chan,
const char *cmd,
char *args,
char *buf,
size_t len)
13612 if (ast_strlen_zero(args)) {
13613 ast_log(LOG_ERROR,
"VM_INFO requires an argument (<mailbox>[@<context>],attribute[,folder])\n");
13620 if (ast_strlen_zero(arg.mailbox_context)
13621 || ast_strlen_zero(arg.attribute)
13622 || separate_mailbox(
ast_strdupa(arg.mailbox_context), &mailbox, &context)) {
13623 ast_log(LOG_ERROR,
"VM_INFO requires an argument (<mailbox>[@<context>],attribute[,folder])\n");
13627 memset(&svm, 0,
sizeof(svm));
13628 vmu =
find_user(&svm, context, mailbox);
13630 if (!strncasecmp(arg.attribute,
"exists", 5)) {
13637 if (!strncasecmp(arg.attribute,
"password", 8)) {
13639 }
else if (!strncasecmp(arg.attribute,
"fullname", 8)) {
13641 }
else if (!strncasecmp(arg.attribute,
"email", 5)) {
13643 }
else if (!strncasecmp(arg.attribute,
"pager", 5)) {
13645 }
else if (!strncasecmp(arg.attribute,
"language", 8)) {
13647 }
else if (!strncasecmp(arg.attribute,
"locale", 6)) {
13649 }
else if (!strncasecmp(arg.attribute,
"tz", 2)) {
13651 }
else if (!strncasecmp(arg.attribute,
"count", 5)) {
13654 mailbox_id =
ast_alloca(strlen(mailbox) + strlen(context) + 2);
13655 sprintf(mailbox_id,
"%s@%s", mailbox, context);
13658 res = messagecount(mailbox_id, arg.folder);
13660 ast_log(LOG_ERROR,
"Unable to retrieve message count for mailbox %s\n", arg.mailbox_context);
13664 snprintf(buf, len,
"%d", res);
13666 ast_log(LOG_ERROR,
"Unknown attribute '%s' for VM_INFO\n", arg.attribute);
13678 .read = acf_vm_info,
13681 static int vmauthenticate(
struct ast_channel *chan,
const char *data)
13685 char *options = NULL;
13686 int silent = 0, skipuser = 0;
13691 user = strsep(&s,
",");
13692 options = strsep(&s,
",");
13695 user = strsep(&s,
"@");
13696 context = strsep(&s,
"");
13697 if (!ast_strlen_zero(user))
13704 silent = (strchr(options,
's')) != NULL;
13707 if (!vm_authenticate(chan, mailbox,
sizeof(mailbox), &vmus, context, NULL, skipuser, 3, silent)) {
13712 }
else if (mailbox[0] ==
'*') {
13722 static char *show_users_realtime(
int fd,
const char *context)
13725 const char *cat = NULL;
13728 "context", context, SENTINEL))) {
13729 return CLI_FAILURE;
13734 "=============================================================\n"
13735 "=== Configured Voicemail Users ==============================\n"
13736 "=============================================================\n"
13742 "=== Mailbox ...\n"
13744 for (var = ast_variable_browse(cfg, cat); var; var = var->
next)
13745 ast_cli(fd,
"=== ==> %s: %s\n", var->
name, var->
value);
13748 "=== ---------------------------------------------------------\n"
13753 "=============================================================\n"
13758 return CLI_SUCCESS;
13761 static char *complete_voicemail_show_users(
const char *line,
const char *word,
int pos,
int state)
13766 const char *context =
"";
13772 wordlen = strlen(word);
13775 if (!strncasecmp(word, vmu->
context, wordlen)) {
13776 if (context && strcmp(context, vmu->
context) && ++which > state) {
13793 #define HVSU_OUTPUT_FORMAT "%-10s %-5s %-25s %-10s %6s\n"
13794 const char *context = NULL;
13795 int users_counter = 0;
13799 e->
command =
"voicemail show users [for]";
13801 "Usage: voicemail show users [for <context>]\n"
13802 " Lists all mailboxes currently set up\n";
13805 return complete_voicemail_show_users(a->line, a->word, a->pos, a->n);
13808 if ((a->argc < 3) || (a->argc > 5) || (a->argc == 4))
13809 return CLI_SHOWUSAGE;
13810 if (a->argc == 5) {
13811 if (strcmp(a->argv[3],
"for"))
13812 return CLI_SHOWUSAGE;
13813 context = a->argv[4];
13818 ast_cli(a->fd,
"You must specify a specific context to show users from realtime!\n");
13819 return CLI_SHOWUSAGE;
13821 return show_users_realtime(a->fd, context);
13826 ast_cli(a->fd,
"There are no voicemail users currently defined\n");
13828 return CLI_FAILURE;
13831 ast_cli(a->fd, HVSU_OUTPUT_FORMAT,
"Context",
"Mbox",
"User",
"Zone",
"NewMsg");
13835 if (!strcmp(context, vmu->
context)) {
13841 ast_cli(a->fd, HVSU_OUTPUT_FORMAT,
"Context",
"Mbox",
"User",
"Zone",
"NewMsg");
13843 ast_cli(a->fd,
"No such voicemail context \"%s\"\n", context);
13845 return CLI_FAILURE;
13849 int newmsgs = 0, oldmsgs = 0;
13850 char count[12], tmp[256] =
"";
13852 if (!context || !strcmp(context, vmu->
context)) {
13853 snprintf(tmp,
sizeof(tmp),
"%s@%s", vmu->
mailbox, ast_strlen_zero(vmu->
context) ?
"default" : vmu->
context);
13854 inboxcount(tmp, &newmsgs, &oldmsgs);
13855 snprintf(count,
sizeof(count),
"%d", newmsgs);
13861 ast_cli(a->fd,
"%d voicemail users configured.\n", users_counter);
13862 return CLI_SUCCESS;
13869 #define HVSZ_OUTPUT_FORMAT "%-15s %-20s %-45s\n"
13870 char *res = CLI_SUCCESS;
13874 e->
command =
"voicemail show zones";
13876 "Usage: voicemail show zones\n"
13877 " Lists zone message formats\n";
13884 return CLI_SHOWUSAGE;
13888 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT,
"Zone",
"Timezone",
"Message Format");
13890 ast_cli(a->fd, HVSZ_OUTPUT_FORMAT, zone->name, zone->timezone, zone->msg_format);
13893 ast_cli(a->fd,
"There are no voicemail zones currently defined\n");
13906 #define ALIASES_OUTPUT_FORMAT "%-32s %-32s\n"
13907 char *res = CLI_SUCCESS;
13911 e->
command =
"voicemail show aliases";
13913 "Usage: voicemail show aliases\n"
13914 " Lists mailbox aliases\n";
13921 return CLI_SHOWUSAGE;
13923 if (ast_strlen_zero(aliasescontext)) {
13924 ast_cli(a->fd,
"Aliases are not enabled\n");
13928 ast_cli(a->fd,
"Aliases context: %s\n", aliasescontext);
13929 ast_cli(a->fd, ALIASES_OUTPUT_FORMAT,
"Alias",
"Mailbox");
13932 while ((mapping = ao2_iterator_next(&aliases))) {
13933 ast_cli(a->fd, ALIASES_OUTPUT_FORMAT, mapping->alias, mapping->mailbox);
13946 e->
command =
"voicemail reload";
13948 "Usage: voicemail reload\n"
13949 " Reload voicemail configuration\n";
13956 return CLI_SHOWUSAGE;
13958 ast_cli(a->fd,
"Reloading voicemail configuration...\n");
13961 return CLI_SUCCESS;
13969 AST_CLI_DEFINE(handle_voicemail_show_mailbox,
"Display a mailbox's content details"),
13970 AST_CLI_DEFINE(handle_voicemail_forward_message,
"Forward message to another folder"),
13971 AST_CLI_DEFINE(handle_voicemail_move_message,
"Move message to another folder"),
13972 AST_CLI_DEFINE(handle_voicemail_remove_message,
"Remove message"),
13975 static int poll_subscribed_mailbox(
struct ast_mwi_state *mwi_state,
void *data)
13977 int new = 0, old = 0, urgent = 0;
13986 #ifdef IMAP_STORAGE
13987 if (imap_poll_logout) {
13993 queue_mwi_event(NULL, mwi_state->
uniqueid, urgent,
new, old);
14000 static void *mb_poll_thread(
void *data)
14002 while (poll_thread_run) {
14003 struct timespec ts = { 0, };
14004 struct timeval wait;
14008 if (!poll_thread_run) {
14013 ts.tv_sec = wait.tv_sec;
14014 ts.tv_nsec = wait.tv_usec * 1000;
14016 ast_mutex_lock(&poll_lock);
14017 ast_cond_timedwait(&poll_cond, &poll_lock, &ts);
14018 ast_mutex_unlock(&poll_lock);
14024 #ifdef IMAP_STORAGE
14025 static void imap_logout(
const char *mailbox_id)
14033 if (ast_strlen_zero(mailbox_id)
14034 || separate_mailbox(
ast_strdupa(mailbox_id), &mailbox, &context)) {
14038 memset(&vmus, 0,
sizeof(vmus));
14040 if (!(vmu =
find_user(&vmus, context, mailbox)) || vmu->imapuser[0] ==
'\0') {
14044 vms = get_vm_state_by_imapuser(vmu->imapuser, 0);
14046 vms = get_vm_state_by_mailbox(mailbox, context, 0);
14052 ast_mutex_lock(&vms->lock);
14053 vms->mailstream = mail_close(vms->mailstream);
14054 ast_mutex_unlock(&vms->lock);
14056 vmstate_delete(vms);
14059 static int imap_close_subscribed_mailbox(
struct ast_mwi_state *mwi_state,
void *data)
14061 if (mwi_state && !ast_strlen_zero(mwi_state->
uniqueid)) {
14070 static int mwi_handle_unsubscribe2(
void *data)
14081 #ifdef IMAP_STORAGE
14082 imap_close_subscribed_mailbox(mwi_state, NULL);
14100 static int mwi_handle_subscribe2(
void *data)
14102 poll_subscribed_mailbox(data, NULL);
14120 .on_unsubscribe = mwi_handle_unsubscribe,
14123 static void start_poll_thread(
void)
14128 poll_thread_run = 1;
14130 if ((errcode = ast_pthread_create(&poll_thread, NULL, mb_poll_thread, NULL))) {
14131 ast_log(LOG_ERROR,
"Could not create thread: %s\n", strerror(errcode));
14135 static void stop_poll_thread(
void)
14137 poll_thread_run = 0;
14139 ast_mutex_lock(&poll_lock);
14140 ast_cond_signal(&poll_cond);
14141 ast_mutex_unlock(&poll_lock);
14143 pthread_join(poll_thread, NULL);
14144 poll_thread = AST_PTHREADT_NULL;
14156 const char* event_name,
14157 const char* actionid
14165 if((s == NULL) || (vmu == NULL) || (event_name == NULL) || (actionid == NULL)) {
14166 ast_log(LOG_ERROR,
"Wrong input parameter.");
14171 if (!ast_strlen_zero(vmu->
context)) {
14177 ast_log(LOG_ERROR,
"Could not create mailbox string. err[%s]\n", strerror(errno));
14182 ret = inboxcount(mailbox, &
new, &old);
14185 ast_log(LOG_ERROR,
"Could not get mailbox count. user[%s], context[%s]\n",
14193 "VMContext: %s\r\n"
14194 "VoiceMailbox: %s\r\n"
14198 "ServerEmail: %s\r\n"
14199 "FromString: %s\r\n"
14200 "MailCommand: %s\r\n"
14206 "ExitContext: %s\r\n"
14207 "SayDurationMinimum: %d\r\n"
14208 "SayEnvelope: %s\r\n"
14210 "AttachMessage: %s\r\n"
14211 "AttachmentFormat: %s\r\n"
14212 "DeleteMessage: %s\r\n"
14213 "VolumeGain: %.2f\r\n"
14214 "CanReview: %s\r\n"
14215 "CanMarkUrgent: %s\r\n"
14216 "CallOperator: %s\r\n"
14217 "MaxMessageCount: %d\r\n"
14218 "MaxMessageLength: %d\r\n"
14219 "NewMessageCount: %d\r\n"
14220 "OldMessageCount: %d\r\n"
14221 #ifdef IMAP_STORAGE
14223 "IMAPServer: %s\r\n"
14225 "IMAPFlags: %s\r\n"
14247 ast_test_flag(vmu,
VM_SAYCID) ?
"Yes" :
"No",
14248 ast_test_flag(vmu,
VM_ATTACH) ?
"Yes" :
"No",
14250 ast_test_flag(vmu,
VM_DELETE) ?
"Yes" :
"No",
14252 ast_test_flag(vmu,
VM_REVIEW) ?
"Yes" :
"No",
14259 #ifdef IMAP_STORAGE
14281 const char* event_name,
14282 const char* actionid)
14286 int nummessages = 0;
14291 if (!mailbox_snapshot) {
14292 ast_log(LOG_ERROR,
"Could not append voicemail box info for box %s@%s.",
14299 for (i = 0; i < mailbox_snapshot->folders; i++) {
14332 static int manager_match_mailbox(
struct ast_mwi_state *mwi_state,
void *data)
14338 if (!ast_strlen_zero(mwi_state->
uniqueid)) {
14341 (ast_strlen_zero(context) && ast_strlen_zero(mailbox)) ||
14343 (ast_strlen_zero(context) && !ast_strlen_zero(mailbox) &&
14344 (at = strchr(mwi_state->
uniqueid,
'@')) &&
14347 (!ast_strlen_zero(context) && ast_strlen_zero(mailbox) &&
14348 (at = strchr(mwi_state->
uniqueid,
'@')) &&
14349 strcmp(context, at + 1) == 0) ||
14351 (!ast_strlen_zero(context) && !ast_strlen_zero(mailbox) &&
14352 (at = strchr(mwi_state->
uniqueid,
'@')) &&
14354 strcmp(context, at + 1) == 0)
14356 poll_subscribed_mailbox(mwi_state, NULL);
14363 static int manager_voicemail_refresh(
struct mansession *s,
const struct message *m)
14367 return RESULT_SUCCESS;
14370 static int manager_status_voicemail_user(
struct mansession *s,
const struct message *m)
14374 char actionid[128];
14381 if ((ast_strlen_zero(context) || ast_strlen_zero(mailbox))) {
14383 return RESULT_SUCCESS;
14386 actionid[0] =
'\0';
14387 if (!ast_strlen_zero(
id)) {
14388 snprintf(actionid,
sizeof(actionid),
"ActionID: %s\r\n",
id);
14392 memset(&svm, 0,
sizeof(svm));
14393 vmu =
find_user(&svm, context, mailbox);
14396 astman_send_ack(s, m,
"There is no voicemail user of the given info.");
14397 return RESULT_SUCCESS;
14406 ast_log(LOG_ERROR,
"Could not append voicemail user info.");
14412 return RESULT_SUCCESS;
14420 char actionid[128];
14424 actionid[0] =
'\0';
14425 if (!ast_strlen_zero(
id)) {
14426 snprintf(actionid,
sizeof(actionid),
"ActionID: %s\r\n",
id);
14432 astman_send_ack(s, m,
"There are no voicemail users currently defined.");
14434 return RESULT_SUCCESS;
14443 ast_log(LOG_ERROR,
"Could not append voicemail user info.");
14454 return RESULT_SUCCESS;
14457 static int manager_get_mailbox_summary(
struct mansession *s,
const struct message *m)
14461 char actionid[128];
14467 if ((ast_strlen_zero(context) || ast_strlen_zero(mailbox))) {
14472 actionid[0] =
'\0';
14473 if (!ast_strlen_zero(
id)) {
14474 snprintf(actionid,
sizeof(actionid),
"ActionID: %s\r\n",
id);
14478 memset(&svm, 0,
sizeof(svm));
14479 vmu =
find_user(&svm, context, mailbox);
14482 astman_send_ack(s, m,
"There is no voicemail user matching the given user.");
14495 static int manager_voicemail_move(
struct mansession *s,
const struct message *m)
14503 if (ast_strlen_zero(mailbox)) {
14507 if (ast_strlen_zero(context)) {
14511 if (ast_strlen_zero(from_folder)) {
14515 if (ast_strlen_zero(
id[0])) {
14519 if (ast_strlen_zero(to_folder)) {
14524 if (vm_msg_move(mailbox, context, 1, from_folder,
id, to_folder)) {
14533 static int manager_voicemail_remove(
struct mansession *s,
const struct message *m)
14540 if (ast_strlen_zero(mailbox)) {
14544 if (ast_strlen_zero(context)) {
14548 if (ast_strlen_zero(folder)) {
14552 if (ast_strlen_zero(
id[0])) {
14557 if (vm_msg_remove(mailbox, context, 1, folder,
id)) {
14566 static int manager_voicemail_forward(
struct mansession *s,
const struct message *m)
14576 if (ast_strlen_zero(from_mailbox)) {
14580 if (ast_strlen_zero(from_context)) {
14584 if (ast_strlen_zero(from_folder)) {
14588 if (ast_strlen_zero(
id[0])) {
14592 if (ast_strlen_zero(to_mailbox)) {
14596 if (ast_strlen_zero(to_context)) {
14600 if (ast_strlen_zero(to_folder)) {
14605 if (vm_msg_forward(from_mailbox, from_context, from_folder, to_mailbox, to_context, to_folder, 1,
id, 0)) {
14621 free_user_final(current);
14636 static const char *substitute_escapes(
const char *value)
14646 for (current = (
char *) value; *current; current++) {
14647 if (*current ==
'\\') {
14650 ast_log(AST_LOG_NOTICE,
"Incomplete escape at end of value.\n");
14653 switch (*current) {
14661 #ifdef IMAP_STORAGE
14662 if (!str->used || str->str[str->used - 1] !=
'\r') {
14672 ast_log(AST_LOG_NOTICE,
"Substitution routine does not support this character: \\%c\n", *current);
14692 if ((cfg =
ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
14693 if ((ucfg =
ast_config_load(
"users.conf", config_flags)) == CONFIG_STATUS_FILEUNCHANGED) {
14695 }
else if (ucfg == CONFIG_STATUS_FILEINVALID) {
14696 ast_log(LOG_ERROR,
"Config file users.conf is in an invalid format. Avoiding.\n");
14700 if ((cfg =
ast_config_load(VOICEMAIL_CONFIG, config_flags)) == CONFIG_STATUS_FILEINVALID) {
14702 ast_log(LOG_ERROR,
"Config file " VOICEMAIL_CONFIG
" is in an invalid format. Aborting.\n");
14705 }
else if (cfg == CONFIG_STATUS_FILEINVALID) {
14706 ast_log(LOG_ERROR,
"Config file " VOICEMAIL_CONFIG
" is in an invalid format. Aborting.\n");
14710 if ((ucfg =
ast_config_load(
"users.conf", config_flags)) == CONFIG_STATUS_FILEINVALID) {
14711 ast_log(LOG_ERROR,
"Config file users.conf is in an invalid format. Avoiding.\n");
14716 res = actual_load_config(reload, cfg, ucfg);
14724 static int load_config(
int reload)
14729 #ifdef TEST_FRAMEWORK
14730 static int load_config_from_memory(
int reload,
struct ast_config *cfg,
struct ast_config *ucfg)
14734 return actual_load_config(reload, cfg, ucfg);
14738 static struct alias_mailbox_mapping *alias_mailbox_mapping_create(
const char *alias,
const char *mailbox)
14741 size_t from_len = strlen(alias) + 1;
14742 size_t to_len = strlen(mailbox) + 1;
14744 mapping = ao2_alloc(
sizeof(*mapping) + from_len + to_len, NULL);
14748 mapping->alias = mapping->buf;
14749 mapping->mailbox = mapping->buf + from_len;
14756 static void load_aliases(
struct ast_config *cfg)
14760 if (ast_strlen_zero(aliasescontext)) {
14763 var = ast_variable_browse(cfg, aliasescontext);
14767 ao2_link(alias_mailbox_mappings, mapping);
14768 ao2_link(mailbox_alias_mappings, mapping);
14775 static void load_zonemessages(
struct ast_config *cfg)
14779 var = ast_variable_browse(cfg,
"zonemessages");
14783 char *msg_format, *tzone;
14784 char storage[strlen(var->
value) + 1];
14791 strcpy(storage, var->
value);
14792 msg_format = storage;
14793 tzone = strsep(&msg_format,
"|,");
14802 ast_log(AST_LOG_WARNING,
"Invalid timezone definition at line %d\n", var->lineno);
14816 if (strcasecmp(cat,
"general") == 0
14817 || strcasecmp(cat, aliasescontext) == 0
14818 || strcasecmp(cat,
"zonemessages") == 0) {
14822 var = ast_variable_browse(cfg, cat);
14824 append_mailbox(cat, var->
name, var->
value);
14835 char *q, *stringp, *tmp;
14837 unsigned int tmpadsi[4];
14838 char secretfn[PATH_MAX] =
"";
14839 long tps_queue_low;
14840 long tps_queue_high;
14842 #ifdef IMAP_STORAGE
14846 strcpy(listen_control_forward_key, DEFAULT_LISTEN_CONTROL_FORWARD_KEY);
14847 strcpy(listen_control_reverse_key, DEFAULT_LISTEN_CONTROL_REVERSE_KEY);
14848 strcpy(listen_control_pause_key, DEFAULT_LISTEN_CONTROL_PAUSE_KEY);
14849 strcpy(listen_control_restart_key, DEFAULT_LISTEN_CONTROL_RESTART_KEY);
14850 strcpy(listen_control_stop_key, DEFAULT_LISTEN_CONTROL_STOP_KEY);
14852 #ifdef IMAP_STORAGE
14868 memset(ext_pass_cmd, 0,
sizeof(ext_pass_cmd));
14869 memset(ext_pass_check_cmd, 0,
sizeof(ext_pass_check_cmd));
14874 if (!(val = ast_variable_retrieve(cfg,
"general",
"userscontext")))
14878 aliasescontext[0] =
'\0';
14879 val = ast_variable_retrieve(cfg,
"general",
"aliasescontext");
14883 if (!(val = ast_variable_retrieve(cfg,
"general",
"attach")))
14887 if (!(val = ast_variable_retrieve(cfg,
"general",
"searchcontexts")))
14892 if ((val = ast_variable_retrieve(cfg,
"general",
"volgain")))
14893 sscanf(val,
"%30lf", &volgain);
14895 #ifdef ODBC_STORAGE
14896 strcpy(odbc_database,
"asterisk");
14897 if ((val = ast_variable_retrieve(cfg,
"general",
"odbcstorage"))) {
14901 strcpy(odbc_table,
"voicemessages");
14902 if ((val = ast_variable_retrieve(cfg,
"general",
"odbctable"))) {
14905 odbc_table_len = strlen(odbc_table);
14908 if (!(val = ast_variable_retrieve(cfg,
"general",
"odbc_audio_on_disk")))
14915 if ((val = ast_variable_retrieve(cfg,
"general",
"mailcmd")))
14919 if ((val = ast_variable_retrieve(cfg,
"general",
"maxsilence"))) {
14920 maxsilence = atoi(val);
14921 if (maxsilence > 0)
14922 maxsilence *= 1000;
14925 if (!(val = ast_variable_retrieve(cfg,
"general",
"maxmsg"))) {
14928 maxmsg = atoi(val);
14930 ast_log(AST_LOG_WARNING,
"Invalid number of messages per folder '%s'. Using default value %i\n", val, MAXMSG);
14932 }
else if (maxmsg > MAXMSGLIMIT) {
14933 ast_log(AST_LOG_WARNING,
"Maximum number of messages per folder is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
14934 maxmsg = MAXMSGLIMIT;
14938 if (!(val = ast_variable_retrieve(cfg,
"general",
"backupdeleted"))) {
14941 if (sscanf(val,
"%30d", &x) == 1)
14944 maxdeletedmsg = MAXMSG;
14948 if (maxdeletedmsg < 0) {
14949 ast_log(AST_LOG_WARNING,
"Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG);
14950 maxdeletedmsg = MAXMSG;
14951 }
else if (maxdeletedmsg > MAXMSGLIMIT) {
14952 ast_log(AST_LOG_WARNING,
"Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val);
14953 maxdeletedmsg = MAXMSGLIMIT;
14958 if ((val = ast_variable_retrieve(cfg,
"general",
"emaildateformat"))) {
14963 if ((val = ast_variable_retrieve(cfg,
"general",
"pagerdateformat"))) {
14968 if ((val = ast_variable_retrieve(cfg,
"general",
"externpass"))) {
14970 pwdchange = PWDCHANGE_EXTERNAL;
14971 }
else if ((val = ast_variable_retrieve(cfg,
"general",
"externpassnotify"))) {
14973 pwdchange = PWDCHANGE_EXTERNAL | PWDCHANGE_INTERNAL;
14977 if ((val = ast_variable_retrieve(cfg,
"general",
"externpasscheck"))) {
14978 ast_copy_string(ext_pass_check_cmd, val,
sizeof(ext_pass_check_cmd));
14979 ast_debug(1,
"found externpasscheck: %s\n", ext_pass_check_cmd);
14982 #ifdef IMAP_STORAGE
14984 if ((val = ast_variable_retrieve(cfg,
"general",
"imapserver"))) {
14990 if ((val = ast_variable_retrieve(cfg,
"general",
"imapport"))) {
14996 if ((val = ast_variable_retrieve(cfg,
"general",
"imapflags"))) {
15000 if ((val = ast_variable_retrieve(cfg,
"general",
"authuser"))) {
15004 if ((val = ast_variable_retrieve(cfg,
"general",
"authpassword"))) {
15008 if ((val = ast_variable_retrieve(cfg,
"general",
"expungeonhangup"))) {
15010 expungeonhangup = 0;
15012 expungeonhangup = 1;
15014 expungeonhangup = 1;
15017 if ((val = ast_variable_retrieve(cfg,
"general",
"imapfolder"))) {
15022 if ((val = ast_variable_retrieve(cfg,
"general",
"imapparentfolder"))) {
15025 if ((val = ast_variable_retrieve(cfg,
"general",
"imapgreetings"))) {
15030 if ((val = ast_variable_retrieve(cfg,
"general",
"greetingfolder"))) {
15032 }
else if ((val = ast_variable_retrieve(cfg,
"general",
"greetingsfolder"))) {
15038 if ((val = ast_variable_retrieve(cfg,
"general",
"imap_poll_logout"))) {
15041 imap_poll_logout = 0;
15048 if ((val = ast_variable_retrieve(cfg,
"general",
"imapreadtimeout"))) {
15049 mail_parameters(NIL, SET_READTIMEOUT, (
void *) (atol(val)));
15051 mail_parameters(NIL, SET_READTIMEOUT, (
void *) 60L);
15054 if ((val = ast_variable_retrieve(cfg,
"general",
"imapwritetimeout"))) {
15055 mail_parameters(NIL, SET_WRITETIMEOUT, (
void *) (atol(val)));
15057 mail_parameters(NIL, SET_WRITETIMEOUT, (
void *) 60L);
15060 if ((val = ast_variable_retrieve(cfg,
"general",
"imapopentimeout"))) {
15061 mail_parameters(NIL, SET_OPENTIMEOUT, (
void *) (atol(val)));
15063 mail_parameters(NIL, SET_OPENTIMEOUT, (
void *) 60L);
15066 if ((val = ast_variable_retrieve(cfg,
"general",
"imapclosetimeout"))) {
15067 mail_parameters(NIL, SET_CLOSETIMEOUT, (
void *) (atol(val)));
15069 mail_parameters(NIL, SET_CLOSETIMEOUT, (
void *) 60L);
15076 if ((val = ast_variable_retrieve(cfg,
"general",
"externnotify"))) {
15078 ast_debug(1,
"found externnotify: %s\n", externnotify);
15080 externnotify[0] =
'\0';
15084 if ((val = ast_variable_retrieve(cfg,
"general",
"smdienable")) &&
ast_true(val)) {
15085 ast_debug(1,
"Enabled SMDI voicemail notification\n");
15086 if ((val = ast_variable_retrieve(cfg,
"general",
"smdiport"))) {
15089 ast_debug(1,
"No SMDI interface set, trying default (/dev/ttyS0)\n");
15093 ast_log(AST_LOG_ERROR,
"No valid SMDI interface specfied, disabling SMDI voicemail notification\n");
15099 if ((val = ast_variable_retrieve(cfg,
"general",
"silencethreshold")))
15100 silencethreshold = atoi(val);
15102 if (!(val = ast_variable_retrieve(cfg,
"general",
"serveremail")))
15107 if ((val = ast_variable_retrieve(cfg,
"general",
"maxsecs"))) {
15108 if (sscanf(val,
"%30d", &x) == 1) {
15111 ast_log(AST_LOG_WARNING,
"Invalid max message time length\n");
15113 }
else if ((val = ast_variable_retrieve(cfg,
"general",
"maxmessage"))) {
15114 static int maxmessage_deprecate = 0;
15115 if (maxmessage_deprecate == 0) {
15116 maxmessage_deprecate = 1;
15117 ast_log(AST_LOG_WARNING,
"Setting 'maxmessage' has been deprecated in favor of 'maxsecs'.\n");
15119 if (sscanf(val,
"%30d", &x) == 1) {
15122 ast_log(AST_LOG_WARNING,
"Invalid max message time length\n");
15127 if ((val = ast_variable_retrieve(cfg,
"general",
"minsecs"))) {
15128 if (sscanf(val,
"%30d", &x) == 1) {
15130 if (maxsilence / 1000 >= vmminsecs) {
15131 ast_log(AST_LOG_WARNING,
"maxsilence should be less than minsecs or you may get empty messages\n");
15134 ast_log(AST_LOG_WARNING,
"Invalid min message time length\n");
15136 }
else if ((val = ast_variable_retrieve(cfg,
"general",
"minmessage"))) {
15137 static int maxmessage_deprecate = 0;
15138 if (maxmessage_deprecate == 0) {
15139 maxmessage_deprecate = 1;
15140 ast_log(AST_LOG_WARNING,
"Setting 'minmessage' has been deprecated in favor of 'minsecs'.\n");
15142 if (sscanf(val,
"%30d", &x) == 1) {
15144 if (maxsilence / 1000 >= vmminsecs) {
15145 ast_log(AST_LOG_WARNING,
"maxsilence should be less than minmessage or you may get empty messages\n");
15148 ast_log(AST_LOG_WARNING,
"Invalid min message time length\n");
15152 val = ast_variable_retrieve(cfg,
"general",
"format");
15159 ast_log(LOG_ERROR,
"Error processing format string, defaulting to format 'wav'\n");
15166 if ((val = ast_variable_retrieve(cfg,
"general",
"maxgreet"))) {
15167 if (sscanf(val,
"%30d", &x) == 1) {
15170 ast_log(AST_LOG_WARNING,
"Invalid max message greeting length\n");
15174 if ((val = ast_variable_retrieve(cfg,
"general",
"skipms"))) {
15175 if (sscanf(val,
"%30d", &x) == 1) {
15178 ast_log(AST_LOG_WARNING,
"Invalid skipms value\n");
15183 if ((val = ast_variable_retrieve(cfg,
"general",
"maxlogins"))) {
15184 if (sscanf(val,
"%30d", &x) == 1) {
15187 ast_log(AST_LOG_WARNING,
"Invalid max failed login attempts\n");
15192 if ((val = ast_variable_retrieve(cfg,
"general",
"minpassword"))) {
15193 if (sscanf(val,
"%30d", &x) == 1) {
15196 ast_log(AST_LOG_WARNING,
"Invalid minimum password length. Default to %d\n", minpassword);
15201 if (!(val = ast_variable_retrieve(cfg,
"general",
"forcename")))
15206 if (!(val = ast_variable_retrieve(cfg,
"general",
"forcegreetings")))
15210 if ((val = ast_variable_retrieve(cfg,
"general",
"cidinternalcontexts"))) {
15211 ast_debug(1,
"VM_CID Internal context string: %s\n", val);
15213 for (x = 0 ; x < MAX_NUM_CID_CONTEXTS ; x++){
15214 if (!ast_strlen_zero(stringp)) {
15215 q = strsep(&stringp,
",");
15216 while ((*q ==
' ')||(*q ==
'\t'))
15218 ast_copy_string(cidinternalcontexts[x], q,
sizeof(cidinternalcontexts[x]));
15219 ast_debug(1,
"VM_CID Internal context %d: %s\n", x, cidinternalcontexts[x]);
15221 cidinternalcontexts[x][0] =
'\0';
15225 if (!(val = ast_variable_retrieve(cfg,
"general",
"review"))){
15226 ast_debug(1,
"VM Review Option disabled globally\n");
15231 if (!(val = ast_variable_retrieve(cfg,
"general",
"leaveurgent"))){
15234 ast_debug(1,
"VM leave urgent messages disabled globally\n");
15240 if (!(val = ast_variable_retrieve(cfg,
"general",
"tempgreetwarn"))) {
15241 ast_debug(1,
"VM Temporary Greeting Reminder Option disabled globally\n");
15244 ast_debug(1,
"VM Temporary Greeting Reminder Option enabled globally\n");
15247 if (!(val = ast_variable_retrieve(cfg,
"general",
"messagewrap"))){
15248 ast_debug(1,
"VM next message wrap disabled globally\n");
15253 if (!(val = ast_variable_retrieve(cfg,
"general",
"operator"))){
15254 ast_debug(1,
"VM Operator break disabled globally\n");
15259 if (!(val = ast_variable_retrieve(cfg,
"general",
"saycid"))) {
15260 ast_debug(1,
"VM CID Info before msg disabled globally\n");
15265 if (!(val = ast_variable_retrieve(cfg,
"general",
"sendvoicemail"))){
15266 ast_debug(1,
"Send Voicemail msg disabled globally\n");
15271 if (!(val = ast_variable_retrieve(cfg,
"general",
"envelope"))) {
15272 ast_debug(1,
"ENVELOPE before msg enabled globally\n");
15277 if (!(val = ast_variable_retrieve(cfg,
"general",
"moveheard"))) {
15278 ast_debug(1,
"Move Heard enabled globally\n");
15283 if (!(val = ast_variable_retrieve(cfg,
"general",
"forward_urgent_auto"))) {
15284 ast_debug(1,
"Autoset of Urgent flag on forwarded Urgent messages disabled globally\n");
15289 if (!(val = ast_variable_retrieve(cfg,
"general",
"sayduration"))) {
15290 ast_debug(1,
"Duration info before msg enabled globally\n");
15295 saydurationminfo = 2;
15296 if ((val = ast_variable_retrieve(cfg,
"general",
"saydurationm"))) {
15297 if (sscanf(val,
"%30d", &x) == 1) {
15298 saydurationminfo = x;
15300 ast_log(AST_LOG_WARNING,
"Invalid min duration for say duration\n");
15304 if (!(val = ast_variable_retrieve(cfg,
"general",
"nextaftercmd"))) {
15305 ast_debug(1,
"We are not going to skip to the next msg after save/delete\n");
15310 if ((val = ast_variable_retrieve(cfg,
"general",
"dialout"))) {
15312 ast_debug(1,
"found dialout context: %s\n", dialcontext);
15314 dialcontext[0] =
'\0';
15317 if ((val = ast_variable_retrieve(cfg,
"general",
"callback"))) {
15319 ast_debug(1,
"found callback context: %s\n", callcontext);
15321 callcontext[0] =
'\0';
15324 if ((val = ast_variable_retrieve(cfg,
"general",
"exitcontext"))) {
15326 ast_debug(1,
"found operator context: %s\n", exitcontext);
15328 exitcontext[0] =
'\0';
15332 if ((val = ast_variable_retrieve(cfg,
"general",
"vm-login")))
15334 if ((val = ast_variable_retrieve(cfg,
"general",
"vm-newuser")))
15336 if ((val = ast_variable_retrieve(cfg,
"general",
"vm-password")))
15338 if ((val = ast_variable_retrieve(cfg,
"general",
"vm-newpassword")))
15340 if ((val = ast_variable_retrieve(cfg,
"general",
"vm-invalid-password")))
15341 ast_copy_string(vm_invalid_password, val,
sizeof(vm_invalid_password));
15342 if ((val = ast_variable_retrieve(cfg,
"general",
"vm-passchanged")))
15344 if ((val = ast_variable_retrieve(cfg,
"general",
"vm-reenterpassword")))
15345 ast_copy_string(vm_reenterpassword, val,
sizeof(vm_reenterpassword));
15346 if ((val = ast_variable_retrieve(cfg,
"general",
"vm-mismatch")))
15348 if ((val = ast_variable_retrieve(cfg,
"general",
"vm-pls-try-again"))) {
15351 if ((val = ast_variable_retrieve(cfg,
"general",
"vm-prepend-timeout"))) {
15352 ast_copy_string(vm_prepend_timeout, val,
sizeof(vm_prepend_timeout));
15355 if ((val = ast_variable_retrieve(cfg,
"general",
"listen-control-forward-key")) &&
is_valid_dtmf(val))
15356 ast_copy_string(listen_control_forward_key, val,
sizeof(listen_control_forward_key));
15357 if ((val = ast_variable_retrieve(cfg,
"general",
"listen-control-reverse-key")) &&
is_valid_dtmf(val))
15358 ast_copy_string(listen_control_reverse_key, val,
sizeof(listen_control_reverse_key));
15359 if ((val = ast_variable_retrieve(cfg,
"general",
"listen-control-pause-key")) &&
is_valid_dtmf(val))
15360 ast_copy_string(listen_control_pause_key, val,
sizeof(listen_control_pause_key));
15361 if ((val = ast_variable_retrieve(cfg,
"general",
"listen-control-restart-key")) &&
is_valid_dtmf(val))
15362 ast_copy_string(listen_control_restart_key, val,
sizeof(listen_control_restart_key));
15363 if ((val = ast_variable_retrieve(cfg,
"general",
"listen-control-stop-key")) &&
is_valid_dtmf(val))
15364 ast_copy_string(listen_control_stop_key, val,
sizeof(listen_control_stop_key));
15366 if (!(val = ast_variable_retrieve(cfg,
"general",
"usedirectory")))
15370 if (!(val = ast_variable_retrieve(cfg,
"general",
"passwordlocation"))) {
15371 val =
"voicemail.conf";
15373 if (!(strcmp(val,
"spooldir"))) {
15374 passwordlocation = OPT_PWLOC_SPOOLDIR;
15376 passwordlocation = OPT_PWLOC_VOICEMAILCONF;
15380 if ((val = ast_variable_retrieve(cfg,
"general",
"pollfreq"))) {
15381 if (sscanf(val,
"%30u", &poll_freq) != 1) {
15383 ast_log(AST_LOG_ERROR,
"'%s' is not a valid value for the pollfreq option!\n", val);
15387 poll_mailboxes = 0;
15388 if ((val = ast_variable_retrieve(cfg,
"general",
"pollmailboxes")))
15391 memset(fromstring, 0,
sizeof(fromstring));
15392 memset(pagerfromstring, 0,
sizeof(pagerfromstring));
15393 strcpy(charset,
"ISO-8859-1");
15395 ast_free(emailbody);
15398 if (emailsubject) {
15399 ast_free(emailsubject);
15400 emailsubject = NULL;
15403 ast_free(pagerbody);
15406 if (pagersubject) {
15407 ast_free(pagersubject);
15408 pagersubject = NULL;
15410 if ((val = ast_variable_retrieve(cfg,
"general",
"pbxskip")))
15412 if ((val = ast_variable_retrieve(cfg,
"general",
"fromstring")))
15414 if ((val = ast_variable_retrieve(cfg,
"general",
"pagerfromstring")))
15416 if ((val = ast_variable_retrieve(cfg,
"general",
"charset")))
15418 if ((val = ast_variable_retrieve(cfg,
"general",
"adsifdn"))) {
15419 sscanf(val,
"%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
15420 for (x = 0; x < 4; x++) {
15421 memcpy(&adsifdn[x], &tmpadsi[x], 1);
15424 if ((val = ast_variable_retrieve(cfg,
"general",
"adsisec"))) {
15425 sscanf(val,
"%2x%2x%2x%2x", &tmpadsi[0], &tmpadsi[1], &tmpadsi[2], &tmpadsi[3]);
15426 for (x = 0; x < 4; x++) {
15427 memcpy(&adsisec[x], &tmpadsi[x], 1);
15430 if ((val = ast_variable_retrieve(cfg,
"general",
"adsiver"))) {
15432 adsiver = atoi(val);
15435 if ((val = ast_variable_retrieve(cfg,
"general",
"tz"))) {
15438 if ((val = ast_variable_retrieve(cfg,
"general",
"locale"))) {
15441 if ((val = ast_variable_retrieve(cfg,
"general",
"emailsubject"))) {
15442 emailsubject =
ast_strdup(substitute_escapes(val));
15444 if ((val = ast_variable_retrieve(cfg,
"general",
"emailbody"))) {
15445 emailbody =
ast_strdup(substitute_escapes(val));
15447 if ((val = ast_variable_retrieve(cfg,
"general",
"pagersubject"))) {
15448 pagersubject =
ast_strdup(substitute_escapes(val));
15450 if ((val = ast_variable_retrieve(cfg,
"general",
"pagerbody"))) {
15451 pagerbody =
ast_strdup(substitute_escapes(val));
15455 if ((val = ast_variable_retrieve(cfg,
"general",
"tps_queue_high"))) {
15456 if (sscanf(val,
"%30ld", &tps_queue_high) != 1 || tps_queue_high <= 0) {
15457 ast_log(AST_LOG_WARNING,
"Invalid the taskprocessor high water alert trigger level '%s'\n", val);
15461 tps_queue_low = -1;
15462 if ((val = ast_variable_retrieve(cfg,
"general",
"tps_queue_low"))) {
15463 if (sscanf(val,
"%30ld", &tps_queue_low) != 1 ||
15464 tps_queue_low < -1 || tps_queue_high < tps_queue_low) {
15465 ast_log(AST_LOG_WARNING,
"Invalid the taskprocessor low water clear alert level '%s'\n", val);
15466 tps_queue_low = -1;
15470 ast_log(AST_LOG_WARNING,
"Failed to set alert levels for voicemail taskprocessor.\n");
15476 if (!strcasecmp(cat,
"general")) {
15481 if ((current = find_or_create(userscontext, cat))) {
15490 case OPT_PWLOC_SPOOLDIR:
15491 snprintf(secretfn,
sizeof(secretfn),
"%s%s/%s/secret.conf", VM_SPOOL_DIR, current->
context, current->
mailbox);
15492 read_password_from_file(secretfn, current->
password,
sizeof(current->
password));
15506 load_zonemessages(cfg);
15512 if (poll_mailboxes && poll_thread == AST_PTHREADT_NULL)
15513 start_poll_thread();
15514 if (!poll_mailboxes && poll_thread != AST_PTHREADT_NULL)
15515 stop_poll_thread();;
15520 ast_log(AST_LOG_WARNING,
"Failed to load configuration file.\n");
15525 static int sayname(
struct ast_channel *chan,
const char *mailbox,
const char *context)
15528 char dir[PATH_MAX];
15529 snprintf(dir,
sizeof(dir),
"%s%s/%s/greet", VM_SPOOL_DIR, context, mailbox);
15530 ast_debug(2,
"About to try retrieving name file %s\n", dir);
15531 RETRIEVE(dir, -1, mailbox, context);
15550 static int vm_sayname(
struct ast_channel *chan,
const char *mailbox_id)
15555 if (ast_strlen_zero(mailbox_id)
15556 || separate_mailbox(
ast_strdupa(mailbox_id), &mailbox, &context)) {
15559 return sayname(chan, mailbox, context);
15562 static void read_password_from_file(
const char *secretfn,
char *password,
int passwordlen) {
15568 const char *val = ast_variable_retrieve(pwconf,
"general",
"password");
15576 ast_log(LOG_NOTICE,
"Failed reading voicemail password from %s, using secret from config file\n", secretfn);
15579 static int write_password_to_file(
const char *secretfn,
const char *password) {
15586 ast_log(LOG_ERROR,
"Error creating new config structure\n");
15590 ast_log(LOG_ERROR,
"Error creating new category structure\n");
15594 if (!(var = ast_variable_new(
"password", password,
""))) {
15595 ast_log(LOG_ERROR,
"Error creating new variable structure\n");
15597 ast_category_destroy(cat);
15601 ast_variable_append(cat, var);
15605 ast_log(LOG_ERROR,
"Error writing voicemail password to %s\n", secretfn);
15612 static int vmsayname_exec(
struct ast_channel *chan,
const char *data)
15618 if (ast_strlen_zero(data)
15619 || separate_mailbox(
ast_strdupa(data), &mailbox, &context)) {
15620 ast_log(LOG_WARNING,
"VMSayName requires argument mailbox@context\n");
15624 if ((res = sayname(chan, mailbox, context)) < 0) {
15625 ast_debug(3,
"Greeting not found for '%s@%s', falling back to mailbox number.\n", mailbox, context);
15635 #ifdef TEST_FRAMEWORK
15648 char dir[PATH_MAX];
15649 char dir2[PATH_MAX];
15650 static const char TEST_CONTEXT[] =
"very_long_unique_context_so_that_nobody_will_ever_have_the_same_one_configured_3141592653";
15651 static const char TEST_EXTENSION[] =
"1234";
15658 .
write = fake_write,
15664 info->name =
"vmsayname_exec";
15665 info->category =
"/apps/app_voicemail/";
15666 info->summary =
"Vmsayname unit test";
15667 info->description =
15668 "This tests passing various parameters to vmsayname";
15669 return AST_TEST_NOT_RUN;
15675 NULL, NULL, 0, 0,
"TestChannel1"))) {
15676 goto exit_vmsayname_test;
15681 if (!capabilities) {
15682 goto exit_vmsayname_test;
15685 ast_channel_nativeformats_set(test_channel1, capabilities);
15691 ast_channel_tech_set(test_channel1, &fake_tech);
15693 ast_channel_unlock(test_channel1);
15695 ast_test_status_update(
test,
"Test playing of extension when greeting is not available...\n");
15696 snprintf(dir,
sizeof(dir),
"%s@%s", TEST_EXTENSION, TEST_CONTEXT);
15697 if (!(res = vmsayname_exec(test_channel1, dir))) {
15698 snprintf(dir,
sizeof(dir),
"%s%s/%s/greet", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
15700 ast_test_status_update(
test,
"This should not happen, most likely means clean up from previous test failed\n");
15702 goto exit_vmsayname_test;
15705 if ((res =
create_dirpath(dir,
sizeof(dir), TEST_CONTEXT, TEST_EXTENSION,
""))) {
15706 ast_log(AST_LOG_WARNING,
"Failed to make test directory\n");
15707 goto exit_vmsayname_test;
15709 snprintf(dir,
sizeof(dir),
"%s/sounds/beep.gsm", ast_config_AST_DATA_DIR);
15710 snprintf(dir2,
sizeof(dir2),
"%s%s/%s/greet.gsm", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
15712 if ((res = symlink(dir, dir2))) {
15713 ast_log(LOG_WARNING,
"Symlink reported %s\n", strerror(errno));
15714 goto exit_vmsayname_test;
15716 ast_test_status_update(
test,
"Test playing created mailbox greeting...\n");
15717 snprintf(dir,
sizeof(dir),
"%s@%s", TEST_EXTENSION, TEST_CONTEXT);
15718 res = vmsayname_exec(test_channel1, dir);
15722 snprintf(dir2,
sizeof(dir2),
"%s%s/%s", VM_SPOOL_DIR, TEST_CONTEXT, TEST_EXTENSION);
15724 snprintf(dir2,
sizeof(dir2),
"%s%s", VM_SPOOL_DIR, TEST_CONTEXT);
15729 exit_vmsayname_test:
15733 return res ? AST_TEST_FAIL : AST_TEST_PASS;
15736 struct test_files {
15744 int i, j, res = AST_TEST_PASS, syserr;
15748 #ifdef IMAP_STORAGE
15752 struct test_files *tmp =
ast_alloca(
sizeof(
struct test_files) * 3);
15754 const char origweasels[] =
"tt-weasels";
15755 const char testcontext[] =
"test";
15756 const char testmailbox[] =
"00000000";
15757 const char testspec[] =
"00000000@test";
15759 int new, old, urgent;
15760 const char *folders[3] = {
"Old",
"Urgent",
"INBOX" };
15761 const int folder2mbox[3] = { 1, 11, 0 };
15762 const int expected_results[3][12] = {
15764 { 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0 },
15765 { 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1 },
15766 { 1, 1, 1, 1, 0, 2, 1, 1, 1, 1, 1, 2 },
15771 info->name =
"test_voicemail_msgcount";
15772 info->category =
"/apps/app_voicemail/";
15773 info->summary =
"Test Voicemail status checks";
15774 info->description =
15775 "Verify that message counts are correct when retrieved through the public API";
15776 return AST_TEST_NOT_RUN;
15782 snprintf(syscmd,
sizeof(syscmd),
"rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
15784 ast_test_status_update(
test,
"Unable to clear test directory: %s\n",
15785 syserr > 0 ? strerror(syserr) :
"unable to fork()");
15786 return AST_TEST_FAIL;
15789 #ifdef IMAP_STORAGE
15791 ast_test_status_update(
test,
"Unable to create dummy channel\n");
15792 return AST_TEST_FAIL;
15796 memset(&svm, 0,
sizeof(svm));
15797 if (!(vmu =
find_user(&svm, testcontext, testmailbox)) &&
15798 !(vmu = find_or_create(testcontext, testmailbox))) {
15799 ast_test_status_update(
test,
"Cannot create vmu structure\n");
15801 #ifdef IMAP_STORAGE
15804 return AST_TEST_FAIL;
15808 memset(&vms, 0,
sizeof(vms));
15811 for (i = 0; i < 3; i++) {
15812 create_dirpath(tmp[i].dir,
sizeof(tmp[i].dir), testcontext, testmailbox, folders[i]);
15813 make_file(tmp[i].file,
sizeof(tmp[i].file), tmp[i].dir, 0);
15814 snprintf(tmp[i].txtfile,
sizeof(tmp[i].txtfile),
"%s.txt", tmp[i].file);
15817 snprintf(syscmd,
sizeof(syscmd),
"cp \"%s/sounds/en/%s.gsm\" \"%s/%s/%s/%s/msg0000.gsm\"", ast_config_AST_DATA_DIR, origweasels,
15818 VM_SPOOL_DIR, testcontext, testmailbox, folders[i]);
15820 ast_test_status_update(
test,
"Unable to create test voicemail: %s\n",
15821 syserr > 0 ? strerror(syserr) :
"unable to fork()");
15823 #ifdef IMAP_STORAGE
15827 return AST_TEST_FAIL;
15831 if ((txt = fopen(tmp[i].txtfile,
"w+"))) {
15832 fprintf(txt,
"; just a stub\n[message]\nflag=%s\n", strcmp(folders[i],
"Urgent") ?
"" :
"Urgent");
15835 ast_test_status_update(
test,
"Unable to write message file '%s'\n", tmp[i].txtfile);
15836 res = AST_TEST_FAIL;
15839 open_mailbox(&vms, vmu, folder2mbox[i]);
15840 STORE(tmp[i].dir, testmailbox, testcontext, 0, chan, vmu,
"gsm", 600, &vms, strcmp(folders[i],
"Urgent") ?
"" :
"Urgent", NULL);
15843 for (j = 0; j < 3; j++) {
15846 ast_test_status_update(
test,
"has_voicemail(%s, %s) returned %d and we expected %d\n",
15848 res = AST_TEST_FAIL;
15852 new = old = urgent = 0;
15854 ast_test_status_update(
test,
"inboxcount returned failure\n");
15855 res = AST_TEST_FAIL;
15856 }
else if (old != expected_results[i][3 + 0] ||
new != expected_results[i][3 + 2]) {
15857 ast_test_status_update(
test,
"inboxcount(%s) returned old=%d (expected %d) and new=%d (expected %d)\n",
15858 testspec, old, expected_results[i][3 + 0],
new, expected_results[i][3 + 2]);
15859 res = AST_TEST_FAIL;
15862 new = old = urgent = 0;
15864 ast_test_status_update(
test,
"inboxcount2 returned failure\n");
15865 res = AST_TEST_FAIL;
15866 }
else if (old != expected_results[i][6 + 0] ||
15867 urgent != expected_results[i][6 + 1] ||
15868 new != expected_results[i][6 + 2] ) {
15869 ast_test_status_update(
test,
"inboxcount2(%s) returned old=%d (expected %d), urgent=%d (expected %d), and new=%d (expected %d)\n",
15870 testspec, old, expected_results[i][6 + 0], urgent, expected_results[i][6 + 1],
new, expected_results[i][6 + 2]);
15871 res = AST_TEST_FAIL;
15874 new = old = urgent = 0;
15875 for (j = 0; j < 3; j++) {
15877 ast_test_status_update(
test,
"messagecount(%s, %s) returned %d and we expected %d\n",
15878 testspec, folders[j],
ast_app_messagecount(testspec, folders[j]), expected_results[i][9 + j]);
15879 res = AST_TEST_FAIL;
15884 for (i = 0; i < 3; i++) {
15888 DELETE(tmp[i].dir, 0, tmp[i].file, vmu);
15889 DISPOSE(tmp[i].dir, 0);
15893 ast_free(vms.deleted);
15896 ast_free(vms.heard);
15899 #ifdef IMAP_STORAGE
15904 snprintf(syscmd,
sizeof(syscmd),
"rm -rf \"%s%s/%s\"", VM_SPOOL_DIR, testcontext, testmailbox);
15906 ast_test_status_update(
test,
"Unable to clear test directory: %s\n",
15907 syserr > 0 ? strerror(syserr) :
"unable to fork()");
15917 int res = AST_TEST_PASS;
15918 char testcontext[] =
"test";
15919 char testmailbox[] =
"00000000";
15920 char from[] =
"test@example.net", cidnum[] =
"1234", cidname[] =
"Mark Spencer", format[] =
"gsm";
15921 char attach[256], attach2[256];
15922 char buf[256] =
"";
15930 enum { INT, FLAGVAL, STATIC, STRPTR } type;
15937 {
"plain jane config", STATIC, vmus.
password, .u.strval =
"1234" },
15938 {
"emailsubject", STRPTR, vmus.
emailsubject, .u.strval =
"Oogly boogly\xf8koogly with what appears to be UTF-8" },
15939 {
"emailbody", STRPTR, vmus.
emailbody, .u.strval =
"This is a test\n\twith multiple\nlines\nwithin\n" },
15940 {
"serveremail", STATIC, vmus.
serveremail, .u.strval =
"\"\xf8Something\xe8that\xd8seems to have UTF-8 chars\" <test@example.net>" },
15941 {
"attachment flag", FLAGVAL, &vmus.
flags, .u.intval =
VM_ATTACH },
15942 {
"attach2", STRPTR, attach2, .u.strval =
"" },
15943 {
"attach", STRPTR, attach, .u.strval =
"" },
15949 info->name =
"test_voicemail_notify_endl";
15950 info->category =
"/apps/app_voicemail/";
15951 info->summary =
"Test Voicemail notification end-of-line";
15952 info->description =
15953 "Verify that notification emails use a consistent end-of-line character";
15954 return AST_TEST_NOT_RUN;
15959 snprintf(attach,
sizeof(attach),
"%s/sounds/en/tt-weasels", ast_config_AST_DATA_DIR);
15960 snprintf(attach2,
sizeof(attach2),
"%s/sounds/en/tt-somethingwrong", ast_config_AST_DATA_DIR);
15962 if (!(vmu =
find_user(&vmus, testcontext, testmailbox)) &&
15963 !(vmu = find_or_create(testcontext, testmailbox))) {
15964 ast_test_status_update(
test,
"Cannot create vmu structure\n");
15965 return AST_TEST_NOT_RUN;
15968 if (vmu != &vmus && !(vmu =
find_user(&vmus, testcontext, testmailbox))) {
15969 ast_test_status_update(
test,
"Cannot find vmu structure?!!\n");
15970 return AST_TEST_NOT_RUN;
15975 #ifdef IMAP_STORAGE
15980 for (which = 0; which < ARRAY_LEN(test_items); which++) {
15983 if (ftruncate(fileno(file), 0)) {
15984 ast_test_status_update(
test,
"Cannot truncate test output file: %s\n", strerror(errno));
15985 res = AST_TEST_FAIL;
15990 if (test_items[which].type == INT) {
15991 *((
int *) test_items[which].location) = test_items[which].u.intval;
15992 }
else if (test_items[which].type == FLAGVAL) {
15993 if (ast_test_flag(vmu, test_items[which].u.intval)) {
15994 ast_clear_flag(vmu, test_items[which].u.intval);
15996 ast_set_flag(vmu, test_items[which].u.intval);
15998 }
else if (test_items[which].type == STATIC) {
15999 strcpy(test_items[which].location, test_items[which].u.strval);
16000 }
else if (test_items[which].type == STRPTR) {
16001 test_items[which].location = test_items[which].u.strval;
16004 make_email_file(file, from, vmu, 0, testcontext, testmailbox,
"INBOX", cidnum, cidname, attach, attach2, format, 999, 1, chan, NULL, 0, NULL, NULL);
16006 while (fgets(buf,
sizeof(buf), file)) {
16008 (strlen(buf) > 1 &&
16009 #ifdef IMAP_STORAGE
16010 buf[strlen(buf) - 2] !=
'\r'
16012 buf[strlen(buf) - 2] ==
'\r'
16015 || buf[strlen(buf) - 1] !=
'\n') {
16016 res = AST_TEST_FAIL;
16028 int res = AST_TEST_PASS;
16031 char config_filename[32] =
"/tmp/voicemail.conf.XXXXXX";
16038 info->name =
"test_voicemail_load_config";
16039 info->category =
"/apps/app_voicemail/";
16040 info->summary =
"Test loading Voicemail config";
16041 info->description =
16042 "Verify that configuration is loaded consistently. "
16043 "This is to test regressions of ASTERISK-18838 where it was noticed that "
16044 "some options were loaded after the mailboxes were instantiated, causing "
16045 "those options not to be set correctly.";
16046 return AST_TEST_NOT_RUN;
16052 if ((fd = mkstemp(config_filename)) < 0) {
16053 return AST_TEST_FAIL;
16055 if (!(file = fdopen(fd,
"w"))) {
16057 unlink(config_filename);
16058 return AST_TEST_FAIL;
16060 fputs(
"[general]\ncallback=somecontext\nlocale=de_DE.UTF-8\ntz=european\n[test]", file);
16061 fputs(
"00000001 => 9999,Mr. Test,,,callback=othercontext|locale=nl_NL.UTF-8|tz=central\n", file);
16062 fputs(
"00000002 => 9999,Mrs. Test\n", file);
16066 res = AST_TEST_FAIL;
16070 load_config_from_memory(1, cfg, NULL);
16073 #define CHECK(u, attr, value) else if (strcmp(u->attr, value)) { \
16074 ast_test_status_update(test, "mailbox %s should have %s '%s', but has '%s'\n", \
16075 u->mailbox, #attr, value, u->attr); res = AST_TEST_FAIL; break; }
16079 if (!strcmp(vmu->
mailbox,
"00000001")) {
16081 CHECK(vmu, callback,
"othercontext")
16082 CHECK(vmu, locale, "nl_NL.UTF-8")
16083 CHECK(vmu, zonetag, "central")
16084 } else if (!strcmp(vmu->mailbox, "00000002")) {
16086 CHECK(vmu, callback,
"somecontext")
16087 CHECK(vmu, locale, "de_DE.UTF-8")
16088 CHECK(vmu, zonetag, "european")
16099 unlink(config_filename);
16107 const char testcontext[] =
"test";
16108 const char testmailbox[] =
"00000000";
16109 const char vminfo_cmd[] =
"VM_INFO";
16110 char vminfo_buf[256], vminfo_args[256];
16111 int res = AST_TEST_PASS;
16113 int test_counter = 0;
16116 char *vminfo_test_args;
16117 char *vminfo_expected;
16121 {
"00000000@test,badparam",
"", -1 },
16122 {
"00000000@test",
"", -1 },
16123 {
"00000000@test,exists",
"1", 0 },
16124 {
"11111111@test,exists",
"0", 0 },
16125 {
"00000000@test,email",
"vm-info-test@example.net", 0 },
16126 {
"11111111@test,email",
"", 0 },
16127 {
"00000000@test,fullname",
"Test Framework Mailbox", 0 },
16128 {
"00000000@test,pager",
"vm-info-pager-test@example.net", 0 },
16129 {
"00000000@test,locale",
"en_US", 0 },
16130 {
"00000000@test,tz",
"central", 0 },
16131 {
"00000000@test,language",
"en", 0 },
16132 {
"00000000@test,password",
"9876", 0 },
16137 info->name =
"test_voicemail_vm_info";
16138 info->category =
"/apps/app_voicemail/";
16139 info->summary =
"VM_INFO unit test";
16140 info->description =
16141 "This tests passing various parameters to VM_INFO";
16142 return AST_TEST_NOT_RUN;
16148 ast_test_status_update(
test,
"Unable to create dummy channel\n");
16149 return AST_TEST_FAIL;
16152 if (!(vmu =
find_user(NULL, testcontext, testmailbox)) &&
16153 !(vmu = find_or_create(testcontext, testmailbox))) {
16154 ast_test_status_update(
test,
"Cannot create vmu structure\n");
16156 return AST_TEST_FAIL;
16163 ast_test_status_update(
test,
"Cannot create vmu email\n");
16165 return AST_TEST_FAIL;
16174 for (test_counter = 0; test_counter < ARRAY_LEN(test_items); test_counter++) {
16175 ast_copy_string(vminfo_args, test_items[test_counter].vminfo_test_args,
sizeof(vminfo_args));
16176 test_ret = acf_vm_info(chan, vminfo_cmd, vminfo_args, vminfo_buf,
sizeof(vminfo_buf));
16177 if (strcmp(vminfo_buf, test_items[test_counter].vminfo_expected)) {
16178 ast_test_status_update(
test,
"VM_INFO respose was: '%s', but expected: '%s'\n", vminfo_buf, test_items[test_counter].vminfo_expected);
16179 res = AST_TEST_FAIL;
16181 if (!(test_ret == test_items[test_counter].vminfo_ret)) {
16182 ast_test_status_update(
test,
"VM_INFO return code was: '%i', but expected '%i'\n", test_ret, test_items[test_counter].vminfo_ret);
16183 res = AST_TEST_FAIL;
16195 .module_name = AST_MODULE,
16198 .inboxcount = inboxcount,
16200 .messagecount = messagecount,
16201 .copy_recording_to_vm = msg_create_from_file,
16202 .index_to_foldername = vm_index_to_foldername,
16203 .mailbox_snapshot_create = vm_mailbox_snapshot_create,
16204 .mailbox_snapshot_destroy = vm_mailbox_snapshot_destroy,
16205 .msg_move = vm_msg_move,
16206 .msg_remove = vm_msg_remove,
16207 .msg_forward = vm_msg_forward,
16208 .msg_play = vm_msg_play,
16213 .module_name = AST_MODULE,
16215 .sayname = vm_sayname,
16218 static int reload(
void)
16220 return load_config(1);
16223 static int unload_module(
void)
16240 #ifdef TEST_FRAMEWORK
16241 res |= AST_TEST_UNREGISTER(test_voicemail_vmsayname);
16242 res |= AST_TEST_UNREGISTER(test_voicemail_msgcount);
16243 res |= AST_TEST_UNREGISTER(test_voicemail_vmuser);
16244 res |= AST_TEST_UNREGISTER(test_voicemail_notify_endl);
16245 res |= AST_TEST_UNREGISTER(test_voicemail_load_config);
16246 res |= AST_TEST_UNREGISTER(test_voicemail_vm_info);
16251 #ifdef TEST_FRAMEWORK
16252 ast_uninstall_vm_test_functions();
16254 ao2_ref(inprocess_container, -1);
16257 ao2_cleanup(alias_mailbox_mappings);
16259 ao2_cleanup(mailbox_alias_mappings);
16261 if (poll_thread != AST_PTHREADT_NULL)
16262 stop_poll_thread();
16268 #ifdef IMAP_STORAGE
16276 static void print_mappings(
void *v_obj,
void *where,
ao2_prnt_fn *prnt)
16283 prnt(where,
"Alias: %s Mailbox: %s", mapping->alias, mapping->mailbox);
16303 my_umask = umask(0);
16307 inprocess_hash_fn, NULL, inprocess_cmp_fn);
16308 if (!inprocess_container) {
16313 alias_mailbox_mapping_hash_fn, NULL, alias_mailbox_mapping_cmp_fn);
16314 if (!alias_mailbox_mappings) {
16315 ast_log(LOG_ERROR,
"Unable to create alias_mailbox_mappings container\n");
16316 ao2_cleanup(inprocess_container);
16319 res =
ao2_container_register(
"voicemail_alias_mailbox_mappings", alias_mailbox_mappings, print_mappings);
16321 ast_log(LOG_ERROR,
"Unable to register alias_mailbox_mappings container\n");
16322 ao2_cleanup(inprocess_container);
16323 ao2_cleanup(alias_mailbox_mappings);
16328 mailbox_alias_mapping_hash_fn, NULL, mailbox_alias_mapping_cmp_fn);
16329 if (!mailbox_alias_mappings) {
16330 ast_log(LOG_ERROR,
"Unable to create mailbox_alias_mappings container\n");
16331 ao2_cleanup(inprocess_container);
16333 ao2_cleanup(alias_mailbox_mappings);
16336 res =
ao2_container_register(
"voicemail_mailbox_alias_mappings", mailbox_alias_mappings, print_mappings);
16338 ast_log(LOG_ERROR,
"Unable to register mailbox_alias_mappings container\n");
16339 ao2_cleanup(inprocess_container);
16341 ao2_cleanup(alias_mailbox_mappings);
16342 ao2_cleanup(mailbox_alias_mappings);
16347 snprintf(VM_SPOOL_DIR,
sizeof(VM_SPOOL_DIR),
"%s/voicemail/", ast_config_AST_SPOOL_DIR);
16350 ast_log(AST_LOG_WARNING,
"failed to reference mwi subscription taskprocessor. MWI will not work\n");
16353 if ((res = load_config(0))) {
16365 res |=
ast_manager_register_xml(
"VoicemailUserStatus", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_status_voicemail_user);
16367 res |=
ast_manager_register_xml(
"VoicemailBoxSummary", EVENT_FLAG_CALL | EVENT_FLAG_REPORTING, manager_get_mailbox_summary);
16371 #ifdef TEST_FRAMEWORK
16372 res |= AST_TEST_REGISTER(test_voicemail_vmsayname);
16373 res |= AST_TEST_REGISTER(test_voicemail_msgcount);
16374 res |= AST_TEST_REGISTER(test_voicemail_vmuser);
16375 res |= AST_TEST_REGISTER(test_voicemail_notify_endl);
16376 res |= AST_TEST_REGISTER(test_voicemail_load_config);
16377 res |= AST_TEST_REGISTER(test_voicemail_vm_info);
16381 ast_log(LOG_ERROR,
"Failure registering applications, functions or tests\n");
16389 ast_log(LOG_ERROR,
"Failure registering as a voicemail provider\n");
16397 ast_log(LOG_ERROR,
"Failure registering as a greeter provider\n");
16404 #ifdef TEST_FRAMEWORK
16405 ast_install_vm_test_functions(vm_test_create_user, vm_test_destroy_user);
16414 static int dialout(
struct ast_channel *chan,
struct ast_vm_user *vmu,
char *num,
char *outgoing_context)
16417 char destination[80] =
"";
16421 ast_verb(3,
"Destination number will be entered manually\n");
16422 while (retries < 3 && cmd !=
't') {
16423 destination[1] =
'\0';
16432 destination[0] = cmd;
16441 ast_verb(3,
"User hit '*' to cancel outgoing call\n");
16444 if ((cmd =
ast_readstring(chan, destination + strlen(destination),
sizeof(destination) - 1, 6000, 10000,
"#")) < 0)
16450 isprint(cmd) ? cmd :
'?', isprint(cmd) ? cmd :
'?');
16452 if (retries >= 3) {
16457 ast_verb(3,
"Destination number is CID number '%s'\n", num);
16461 if (!ast_strlen_zero(destination)) {
16462 if (destination[strlen(destination) -1 ] ==
'*')
16464 ast_verb(3,
"Placing outgoing call to extension '%s' in context '%s' from context '%s'\n", destination, outgoing_context, ast_channel_context(chan));
16465 ast_channel_exten_set(chan, destination);
16466 ast_channel_context_set(chan, outgoing_context);
16467 ast_channel_priority_set(chan, 0);
16489 char filename[PATH_MAX];
16491 const char *origtime, *context;
16499 make_file(vms->fn,
sizeof(vms->fn), vms->curdir, msg);
16502 snprintf(filename,
sizeof(filename),
"%s.txt", vms->fn);
16505 DISPOSE(vms->curdir, vms->curmsg);
16507 ast_log(AST_LOG_WARNING,
"No message attribute file?!! (%s)\n", filename);
16511 if (!(origtime = ast_variable_retrieve(msg_cfg,
"message",
"origtime"))) {
16516 cid =
ast_strdupa(ast_variable_retrieve(msg_cfg,
"message",
"callerid"));
16518 context = ast_variable_retrieve(msg_cfg,
"message",
"context");
16522 res = play_message_datetime(chan, vmu, origtime, filename);
16525 res = play_message_callerid(chan, vms, cid, context, 0, 1);
16533 if (ast_strlen_zero(cid))
16537 while ((res > -1) && (res !=
't')) {
16542 res = dialout(chan, vmu, num, vmu->callback);
16554 if (!ast_strlen_zero(vmu->dialout)) {
16555 res = dialout(chan, vmu, NULL, vmu->dialout);
16561 ast_verb(3,
"Caller can not specify callback number - no dialout context available\n");
16583 ast_verb(3,
"Confirm CID number '%s' is number to use for callback\n", num);
16586 res = play_message_callerid(chan, vms, num, vmu->
context, 1, 1);
16590 if (!ast_strlen_zero(vmu->dialout)) {
16596 if (!ast_strlen_zero(vmu->dialout)) {
16614 isprint(res) ? res :
'?', isprint(res) ? res :
'?');
16620 else if (res ==
'*')
16627 if (ast_strlen_zero(cid))
16632 ast_verb(3,
"No CID number available, no reply sent\n");
16639 memset(&vmu2, 0,
sizeof(vmu2));
16644 snprintf(mailbox,
sizeof(mailbox),
"%s@%s", num, vmu->
context);
16646 ast_verb(3,
"Leaving voicemail for '%s' in context '%s'\n", num, vmu->
context);
16648 memset(&leave_options, 0,
sizeof(leave_options));
16649 leave_options.record_gain = record_gain;
16650 leave_options.beeptone =
"beep";
16659 ast_verb(3,
"No mailbox number '%s' in context '%s', no reply sent\n", num, vmu->
context);
16673 #ifndef IMAP_STORAGE
16675 make_file(vms->fn,
sizeof(vms->fn), vms->curdir, msg);
16676 vms->heard[msg] = 1;
16677 res = wait_file(chan, vms, vms->fn);
16683 static int play_record_review(
struct ast_channel *chan,
char *playfile,
char *recordfile,
int maxtime,
char *fmt,
16684 int outsidecaller,
struct ast_vm_user *vmu,
int *duration,
int *sound_duration,
const char *unlockdir,
16685 signed char record_gain,
struct vm_state *vms,
char *flag,
const char *msg_id,
int forwardintro)
16690 int max_attempts = 3;
16693 int msg_exists = 0;
16694 signed char zero_gain = 0;
16695 char tempfile[PATH_MAX];
16696 char *acceptdtmf =
"#";
16697 char *canceldtmf =
"";
16698 int canceleddtmf = 0;
16699 SCOPE_ENTER(3,
"%s: rf: %s fmt: %s type: %s vmu: %s\n",
16700 ast_channel_name(chan), recordfile, fmt, outsidecaller ?
"msg" :
"greeting",
16705 if (duration == NULL) {
16706 SCOPE_EXIT_LOG_RTN_VALUE(-1, LOG_WARNING,
"%s\n",
"Error play_record_review called without duration pointer\n");
16709 if (!outsidecaller)
16710 snprintf(tempfile,
sizeof(tempfile),
"%s.tmp", recordfile);
16716 while ((cmd >= 0) && (cmd !=
't')) {
16725 ast_verb(3,
"Saving message as is\n");
16726 if (!outsidecaller) {
16727 ast_trace(-1,
"Renaming greeting '%s' to '%s'\n", tempfile, recordfile);
16730 if (!forwardintro) {
16733 if (!outsidecaller) {
16735 ast_trace(-1,
"Saving greeting '%s'\n", recordfile);
16736 SCOPE_CALL(-1, STORE, recordfile, vmu->
mailbox, vmu->
context, -1, chan, vmu, fmt, *duration, vms, flag, msg_id);
16737 SCOPE_CALL(-1, DISPOSE, recordfile, -1);
16740 SCOPE_EXIT_RTN_VALUE(res,
"Message saved to %s\n", recordfile);
16744 ast_verb(3,
"Reviewing the message\n");
16745 ast_trace(-1,
"Reviewing '%s'\n", tempfile);
16752 ast_verb(3,
"Re-recording the message\n");
16754 ast_verb(3,
"Recording the message\n");
16756 if (recorded && outsidecaller) {
16757 if (forwardintro) {
16767 SCOPE_EXIT_RTN_VALUE(cmd,
"User hung up before message could be rerecorded. Deleted '%s'\n", tempfile);
16775 ast_trace(-1,
"Recording '%s'\n", tempfile);
16776 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);
16777 if (strchr(canceldtmf, cmd)) {
16785 if (!outsidecaller) {
16789 SCOPE_EXIT_RTN_VALUE(cmd,
"User hung up after recording. %s %s\n",
16790 outsidecaller ?
"Saved message " :
"Deleted greeting \n", tempfile);
16794 }
else if (cmd ==
'*') {
16797 }
else if (vmu->review && sound_duration && (*sound_duration < 5)) {
16799 ast_verb(3,
"Message too short\n");
16803 }
else if (vmu->review && (cmd == 2 && sound_duration && *sound_duration < (maxsilence + 3))) {
16805 ast_verb(3,
"Nothing recorded\n");
16821 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag,
"Urgent"))) {
16822 ast_verb(3,
"marking message as Urgent\n");
16824 strcpy(flag,
"Urgent");
16826 ast_verb(3,
"UNmarking message as Urgent\n");
16853 if (outsidecaller) {
16854 res = vm_exec(chan, NULL);
16861 if (!ast_test_flag(vmu,
VM_OPERATOR) || (!canceleddtmf && !outsidecaller)) {
16865 if (msg_exists || recorded) {
16866 ast_trace(-1,
"Reviewing '%s'\n", tempfile);
16871 ast_trace(-1,
"Saving '%s' to '%s'\n", tempfile, recordfile);
16875 }
else if (cmd ==
'4') {
16878 strcpy(flag,
"Urgent");
16883 ast_trace(-1,
"Deleting '%s'\n", tempfile);
16885 SCOPE_CALL(-1, DELETE, tempfile, -1, tempfile, vmu);
16886 SCOPE_CALL(-1, DISPOSE, tempfile, -1);
16895 if (outsidecaller && !ast_test_flag(vmu,
VM_REVIEW) && !forwardintro) {
16896 SCOPE_EXIT_RTN_VALUE(cmd,
"Done. Outside caller, review not set, no forwardintro\n");
16900 if (!cmd && outsidecaller && ast_test_flag(vmu,
VM_MARK_URGENT)) {
16901 if ((flag && ast_strlen_zero(flag)) || (!ast_strlen_zero(flag) && strcmp(flag,
"Urgent"))) {
16913 if (!cmd && outsidecaller && ast_test_flag(vmu,
VM_OPERATOR)) {
16927 if (attempts > max_attempts) {
16932 if (!outsidecaller && (cmd == -1 || cmd ==
't')) {
16934 ast_trace(-1,
"Deleting '%s' on hangup or timeout\n", tempfile);
16938 if (cmd !=
't' && outsidecaller)
16941 SCOPE_EXIT_RTN_VALUE(cmd,
"Done\n");
16948 if (!(msg_snapshot =
ast_calloc(1,
sizeof(*msg_snapshot)))) {
16953 ast_free(msg_snapshot);
16957 return msg_snapshot;
16963 ast_free(msg_snapshot);
16968 #ifdef TEST_FRAMEWORK
16970 static int vm_test_destroy_user(
const char *context,
const char *mailbox)
16976 if (!strcmp(context, vmu->
context)
16977 && !strcmp(mailbox, vmu->
mailbox)) {
16988 static int vm_test_create_user(
const char *context,
const char *mailbox)
16992 if (!(vmu = find_or_create(context, mailbox))) {
17015 int snapshot_index,
17018 enum ast_vm_snapshot_sort_val sort_val)
17024 char filename[PATH_MAX];
17027 for (vms->curmsg = 0; vms->curmsg <= vms->lastmsg; vms->curmsg++) {
17030 make_file(vms->fn,
sizeof(vms->fn), vms->curdir, vms->curmsg);
17031 snprintf(filename,
sizeof(filename),
"%s.txt", vms->fn);
17034 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
17035 DISPOSE(vms->curdir, vms->curmsg);
17040 if (!(msg_snapshot = vm_msg_snapshot_alloc())) {
17046 if ((value = ast_variable_retrieve(msg_cfg,
"message",
"msg_id"))) {
17053 char id[MSG_ID_LEN];
17054 if (!(add_message_id(msg_cfg, vms->curdir, vms->curmsg,
17055 filename,
id,
sizeof(
id), vmu, mailbox_index))) {
17058 ast_log(LOG_WARNING,
"Unable to create a message ID for message %s/%d\n", vms->curdir, vms->curmsg);
17061 if ((value = ast_variable_retrieve(msg_cfg,
"message",
"callerid"))) {
17064 if ((value = ast_variable_retrieve(msg_cfg,
"message",
"callerchan"))) {
17067 if ((value = ast_variable_retrieve(msg_cfg,
"message",
"exten"))) {
17070 if ((value = ast_variable_retrieve(msg_cfg,
"message",
"origdate"))) {
17073 if ((value = ast_variable_retrieve(msg_cfg,
"message",
"origtime"))) {
17076 if ((value = ast_variable_retrieve(msg_cfg,
"message",
"duration"))) {
17079 if ((value = ast_variable_retrieve(msg_cfg,
"message",
"flag"))) {
17082 msg_snapshot->msg_number = vms->curmsg;
17086 switch (sort_val) {
17088 case AST_VM_SNAPSHOT_SORT_BY_ID:
17096 case AST_VM_SNAPSHOT_SORT_BY_TIME:
17098 int val = strcmp(msg_snapshot->origtime, msg_snapshot_tmp->origtime);
17099 if (descending && val >= 0) {
17103 }
else if (!descending && val <= 0) {
17117 mailbox_snapshot->total_msg_num++;
17121 DISPOSE(vms->curdir, vms->curmsg);
17128 const char *context,
17129 const char *folder,
17131 enum ast_vm_snapshot_sort_val sort_val,
17132 int combine_INBOX_and_OLD)
17139 int this_index_only = -1;
17141 int inbox_index = get_folder_by_name(
"INBOX");
17142 int old_index = get_folder_by_name(
"Old");
17143 int urgent_index = get_folder_by_name(
"Urgent");
17145 if (ast_strlen_zero(mailbox)) {
17146 ast_log(LOG_WARNING,
"Cannot create a mailbox snapshot since no mailbox was specified\n");
17150 memset(&vmus, 0,
sizeof(vmus));
17152 if (!(ast_strlen_zero(folder))) {
17154 for (i = 0; i < ARRAY_LEN(mailbox_folders); i++) {
17155 if (!strcasecmp(mailbox_folders[i], folder)) {
17156 this_index_only = i;
17160 if (this_index_only == -1) {
17166 if (!(vmu =
find_user(&vmus, context, mailbox))) {
17167 ast_log(AST_LOG_WARNING,
"Failed to create mailbox snapshot for unknown voicemail user %s@%s\n", mailbox, context);
17171 if (!(mailbox_snapshot =
ast_calloc(1,
sizeof(*mailbox_snapshot)))) {
17172 ast_log(AST_LOG_ERROR,
"Failed to allocate memory for mailbox snapshot\n");
17177 if (!(mailbox_snapshot->snapshots =
ast_calloc(ARRAY_LEN(mailbox_folders),
sizeof(*mailbox_snapshot->snapshots)))) {
17178 ast_free(mailbox_snapshot);
17183 mailbox_snapshot->folders = ARRAY_LEN(mailbox_folders);
17185 for (i = 0; i < mailbox_snapshot->folders; i++) {
17186 int msg_folder_index = i;
17193 if (!(this_index_only == -1 || this_index_only == i || (this_index_only == inbox_index && combine_INBOX_and_OLD && (i == old_index || i == urgent_index)))) {
17198 if (combine_INBOX_and_OLD && (i == old_index || i == urgent_index)) {
17199 msg_folder_index = inbox_index;
17202 memset(&vms, 0,
sizeof(vms));
17208 if ((res = open_mailbox(&vms, vmu, i)) < 0) {
17209 ast_log(LOG_WARNING,
"Could not open mailbox %s\n", mailbox);
17210 goto snapshot_cleanup;
17215 if (vms.lastmsg != -1) {
17217 ast_log(LOG_WARNING,
"Failed to create msg snapshots for %s@%s\n", mailbox, context);
17218 goto snapshot_cleanup;
17223 if ((res = close_mailbox(&vms, vmu) == ERROR_LOCK_PATH)) {
17224 goto snapshot_cleanup;
17231 close_mailbox(&vms, vmu);
17234 #ifdef IMAP_STORAGE
17236 vmstate_delete(&vms);
17241 return mailbox_snapshot;
17249 for (i = 0; i < mailbox_snapshot->folders; i++) {
17251 msg_snapshot = vm_msg_snapshot_destroy(msg_snapshot);
17254 ast_free(mailbox_snapshot->snapshots);
17255 ast_free(mailbox_snapshot);
17282 for (i = 0; i < num_msgs; ++i) {
17283 const char *msg_id = msg_ids[i];
17285 for (vms->curmsg = 0; vms->curmsg <= vms->lastmsg; vms->curmsg++) {
17286 const char *other_msg_id;
17287 char filename[PATH_MAX];
17291 make_file(vms->fn,
sizeof(vms->fn), vms->curdir, vms->curmsg);
17292 snprintf(filename,
sizeof(filename),
"%s.txt", vms->fn);
17295 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
17296 DISPOSE(vms->curdir, vms->curmsg);
17301 other_msg_id = ast_variable_retrieve(msg_cfg,
"message",
"msg_id");
17303 if (!ast_strlen_zero(other_msg_id) && !strcmp(other_msg_id, msg_id)) {
17308 msg_nums[i] = vms->curmsg;
17310 DISPOSE(vms->curdir, vms->curmsg);
17314 DISPOSE(vms->curdir, vms->curmsg);
17327 static void notify_new_state(
struct ast_vm_user *vmu)
17329 int new = 0, old = 0, urgent = 0;
17330 char ext_context[1024];
17332 snprintf(ext_context,
sizeof(ext_context),
"%s@%s", vmu->
mailbox, vmu->
context);
17335 queue_mwi_event(NULL, ext_context, urgent,
new, old);
17338 static int vm_msg_forward(
const char *from_mailbox,
17339 const char *from_context,
17340 const char *from_folder,
17341 const char *to_mailbox,
17342 const char *to_context,
17343 const char *to_folder,
17345 const char *msg_ids [],
17353 char filename[PATH_MAX];
17354 int from_folder_index;
17360 if (ast_strlen_zero(from_mailbox) || ast_strlen_zero(to_mailbox)) {
17361 ast_log(LOG_WARNING,
"Cannot forward message because either the from or to mailbox was not specified\n");
17366 ast_log(LOG_WARNING,
"Invalid number of messages specified to forward: %zu\n", num_msgs);
17370 if (ast_strlen_zero(from_folder) || ast_strlen_zero(to_folder)) {
17371 ast_log(LOG_WARNING,
"Cannot forward message because the from_folder or to_folder was not specified\n");
17375 memset(&vmus, 0,
sizeof(vmus));
17376 memset(&to_vmus, 0,
sizeof(to_vmus));
17377 memset(&from_vms, 0,
sizeof(from_vms));
17379 from_folder_index = get_folder_by_name(from_folder);
17380 if (from_folder_index == -1) {
17384 if (get_folder_by_name(to_folder) == -1) {
17388 if (!(vmu =
find_user(&vmus, from_context, from_mailbox))) {
17389 ast_log(LOG_WARNING,
"Can't find voicemail user to forward from (%s@%s)\n", from_mailbox, from_context);
17393 if (!(to_vmu =
find_user(&to_vmus, to_context, to_mailbox))) {
17394 ast_log(LOG_WARNING,
"Can't find voicemail user to forward to (%s@%s)\n", to_mailbox, to_context);
17399 ast_copy_string(from_vms.username, from_mailbox,
sizeof(from_vms.username));
17400 from_vms.lastmsg = -1;
17404 if ((res = open_mailbox(&from_vms, vmu, from_folder_index)) < 0) {
17405 ast_log(LOG_WARNING,
"Could not open mailbox %s\n", from_mailbox);
17407 goto vm_forward_cleanup;
17412 if ((from_vms.lastmsg + 1) < num_msgs) {
17413 ast_log(LOG_WARNING,
"Folder %s has less than %zu messages\n", from_folder, num_msgs);
17415 goto vm_forward_cleanup;
17418 msg_nums =
ast_alloca(
sizeof(
int) * num_msgs);
17421 goto vm_forward_cleanup;
17425 for (i = 0; i < num_msgs; i++) {
17426 int cur_msg = msg_nums[i];
17430 make_file(from_vms.fn,
sizeof(from_vms.fn), from_vms.curdir, cur_msg);
17431 snprintf(filename,
sizeof(filename),
"%s.txt", from_vms.fn);
17438 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
17439 DISPOSE(from_vms.curdir, cur_msg);
17442 if ((value = ast_variable_retrieve(msg_cfg,
"message",
"duration"))) {
17443 duration = atoi(value);
17446 copy_message(NULL, vmu, from_folder_index, cur_msg, duration, to_vmu, vmfmts, from_vms.curdir,
"", to_folder);
17449 from_vms.deleted[cur_msg] = 1;
17452 DISPOSE(from_vms.curdir, cur_msg);
17456 if ((res = close_mailbox(&from_vms, vmu) == ERROR_LOCK_PATH)) {
17458 goto vm_forward_cleanup;
17462 vm_forward_cleanup:
17464 close_mailbox(&from_vms, vmu);
17466 #ifdef IMAP_STORAGE
17468 vmstate_delete(&from_vms);
17473 notify_new_state(to_vmu);
17481 static int vm_msg_move(
const char *mailbox,
17482 const char *context,
17484 const char *oldfolder,
17485 const char *old_msg_ids [],
17486 const char *newfolder)
17490 int old_folder_index;
17491 int new_folder_index;
17497 if (ast_strlen_zero(mailbox)) {
17498 ast_log(LOG_WARNING,
"Cannot move message because no mailbox was specified\n");
17503 ast_log(LOG_WARNING,
"Invalid number of messages specified to move: %zu\n", num_msgs);
17507 if (ast_strlen_zero(oldfolder) || ast_strlen_zero(newfolder)) {
17508 ast_log(LOG_WARNING,
"Cannot move message because either oldfolder or newfolder was not specified\n");
17512 old_folder_index = get_folder_by_name(oldfolder);
17513 new_folder_index = get_folder_by_name(newfolder);
17515 memset(&vmus, 0,
sizeof(vmus));
17516 memset(&vms, 0,
sizeof(vms));
17518 if (old_folder_index == -1 || new_folder_index == -1) {
17522 if (!(vmu =
find_user(&vmus, context, mailbox))) {
17531 if ((res = open_mailbox(&vms, vmu, old_folder_index)) < 0) {
17532 ast_log(LOG_WARNING,
"Could not open mailbox %s\n", mailbox);
17534 goto vm_move_cleanup;
17539 if ((vms.lastmsg + 1) < num_msgs) {
17540 ast_log(LOG_WARNING,
"Folder %s has less than %zu messages\n", oldfolder, num_msgs);
17542 goto vm_move_cleanup;
17545 old_msg_nums =
ast_alloca(
sizeof(
int) * num_msgs);
17548 goto vm_move_cleanup;
17552 for (i = 0; i < num_msgs; ++i) {
17553 if (
save_to_folder(vmu, &vms, old_msg_nums[i], new_folder_index, NULL, 0)) {
17555 goto vm_move_cleanup;
17557 vms.deleted[old_msg_nums[i]] = 1;
17561 if ((res = close_mailbox(&vms, vmu) == ERROR_LOCK_PATH)) {
17563 goto vm_move_cleanup;
17569 close_mailbox(&vms, vmu);
17571 #ifdef IMAP_STORAGE
17573 vmstate_delete(&vms);
17578 notify_new_state(vmu);
17585 static int vm_msg_remove(
const char *mailbox,
17586 const char *context,
17588 const char *folder,
17589 const char *msgs[])
17599 if (ast_strlen_zero(mailbox)) {
17600 ast_log(LOG_WARNING,
"Cannot remove message because no mailbox was specified\n");
17605 ast_log(LOG_WARNING,
"Invalid number of messages specified to remove: %zu\n", num_msgs);
17609 if (ast_strlen_zero(folder)) {
17610 ast_log(LOG_WARNING,
"Cannot remove message because no folder was specified\n");
17614 memset(&vmus, 0,
sizeof(vmus));
17615 memset(&vms, 0,
sizeof(vms));
17617 folder_index = get_folder_by_name(folder);
17618 if (folder_index == -1) {
17619 ast_log(LOG_WARNING,
"Could not remove msgs from unknown folder %s\n", folder);
17623 if (!(vmu =
find_user(&vmus, context, mailbox))) {
17624 ast_log(LOG_WARNING,
"Can't find voicemail user to remove msg from (%s@%s)\n", mailbox, context);
17633 if ((res = open_mailbox(&vms, vmu, folder_index)) < 0) {
17634 ast_log(LOG_WARNING,
"Could not open mailbox %s\n", mailbox);
17636 goto vm_remove_cleanup;
17641 if ((vms.lastmsg + 1) < num_msgs) {
17642 ast_log(LOG_WARNING,
"Folder %s has less than %zu messages\n", folder, num_msgs);
17644 goto vm_remove_cleanup;
17647 msg_nums =
ast_alloca(
sizeof(
int) * num_msgs);
17650 goto vm_remove_cleanup;
17653 for (i = 0; i < num_msgs; i++) {
17654 vms.deleted[msg_nums[i]] = 1;
17658 if ((res = close_mailbox(&vms, vmu) == ERROR_LOCK_PATH)) {
17660 ast_log(AST_LOG_ERROR,
"Failed to close mailbox folder %s while removing msgs\n", folder);
17661 goto vm_remove_cleanup;
17667 close_mailbox(&vms, vmu);
17669 #ifdef IMAP_STORAGE
17671 vmstate_delete(&vms);
17676 notify_new_state(vmu);
17684 const char *mailbox,
17685 const char *context,
17686 const char *folder,
17687 const char *msg_id,
17695 char filename[PATH_MAX];
17701 if (ast_strlen_zero(mailbox)) {
17702 ast_log(LOG_WARNING,
"Cannot play message because no mailbox was specified\n");
17706 if (ast_strlen_zero(folder)) {
17707 ast_log(LOG_WARNING,
"Cannot play message because no folder was specified\n");
17711 if (ast_strlen_zero(msg_id)) {
17712 ast_log(LOG_WARNING,
"Cannot play message because no message number was specified\n");
17716 memset(&vmus, 0,
sizeof(vmus));
17717 memset(&vms, 0,
sizeof(vms));
17719 if (ast_strlen_zero(context)) {
17720 context =
"default";
17723 if (!(vmu =
find_user(&vmus, context, mailbox))) {
17727 i = get_folder_by_name(folder);
17730 if ((res = open_mailbox(&vms, vmu, i)) < 0) {
17731 ast_log(LOG_WARNING,
"Could not open mailbox %s\n", mailbox);
17732 goto play2_msg_cleanup;
17738 goto play2_msg_cleanup;
17742 make_file(vms.fn,
sizeof(vms.fn), vms.curdir, vms.curmsg);
17743 snprintf(filename,
sizeof(filename),
"%s.txt", vms.fn);
17747 if (!msg_cfg || msg_cfg == CONFIG_STATUS_FILEINVALID) {
17748 DISPOSE(vms.curdir, vms.curmsg);
17750 goto play2_msg_cleanup;
17752 if ((value = ast_variable_retrieve(msg_cfg,
"message",
"duration"))) {
17753 duration = atoi(value);
17757 #ifdef IMAP_STORAGE
17761 if (!ast_strlen_zero(vms.introfn) &&
ast_fileexists(vms.introfn, NULL, NULL) > 0) {
17762 wait_file(chan, &vms, vms.introfn);
17766 cb(chan, vms.fn, duration);
17767 }
else if ((wait_file(chan, &vms, vms.fn)) < 0) {
17768 ast_log(AST_LOG_WARNING,
"Playback of message %s failed\n", vms.fn);
17773 vms.heard[vms.curmsg] = 1;
17776 DISPOSE(vms.curdir, vms.curmsg);
17780 close_mailbox(&vms, vmu);
17783 #ifdef IMAP_STORAGE
17785 vmstate_delete(&vms);
17790 notify_new_state(vmu);
17802 .support_level = AST_MODULE_SUPPORT_CORE,
17804 .unload = unload_module,
17806 .optional_modules =
"res_adsi,res_smdi",
unsigned int module_version
The version of this function table.
int ast_filecopy(const char *oldname, const char *newname, const char *fmt)
Copies a file.
struct ast_category * ast_category_new(const char *name, const char *in_file, int lineno)
Create a category.
struct ast_variable * next
#define AST_THREADSTORAGE(name)
Define a thread storage variable.
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.
Main Channel structure associated with a channel.
int ast_adsi_voice_mode(unsigned char *buf, int when)
Puts CPE in voice mode.
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.
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.
char * str
Subscriber phone number (Malloced)
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.
int ast_streamfile(struct ast_channel *c, const char *filename, const char *preflang)
Streams a file.
#define AST_LIST_LOCK(head)
Locks a list.
void( ao2_prnt_fn)(void *where, const char *fmt,...)
Print output.
static void free_vm_zones(void)
Free the zones structure.
Asterisk locking-related definitions:
void astman_append(struct mansession *s, const char *fmt,...)
Asterisk main include file. File version handling, generic pbx functions.
AO2_STRING_FIELD_HASH_FN(transport_monitor, key)
Hashing function for struct transport_monitor.
#define ast_realloc(p, len)
A wrapper for realloc()
static void apply_options_full(struct ast_vm_user *retval, struct ast_variable *var)
Loads the options specific to a voicemail user.
struct ast_json * ast_json_pack(char const *format,...)
Helper for creating complex JSON values.
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.
int pbx_exec(struct ast_channel *c, struct ast_app *app, const char *data)
Execute an application.
static void rename_file(char *sfn, char *dfn)
Renames a message in a mailbox folder.
void ast_unreplace_sigchld(void)
Restore the SIGCHLD handler.
String manipulation functions.
static int manager_list_voicemail_users(struct mansession *s, const struct message *m)
Manager list voicemail users command.
void ast_variables_destroy(struct ast_variable *var)
Free variable list.
int ast_adsi_data_mode(unsigned char *buf)
Puts CPE in data mode.
static void free_vm_users(void)
Free the users structure.
int ast_cli_unregister_multiple(struct ast_cli_entry *e, int len)
Unregister multiple commands.
int(*const write)(struct ast_channel *chan, struct ast_frame *frame)
Write a frame, in standard format (see frame.h)
#define ast_channel_unref(c)
Decrease channel reference count.
The arg parameter is a search key, but is not an object.
static int create_dirpath(char *dest, int len, const char *context, const char *ext, const char *folder)
basically mkdir -p $dest/$context/$ext/$folder
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.
int ast_indicate(struct ast_channel *chan, int condition)
Indicates condition of channel.
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...
Time-related functions and macros.
void ast_json_unref(struct ast_json *value)
Decrease refcount on value. If refcount reaches zero, value is freed.
struct ast_party_name name
Subscriber name.
static int last_message_index(char *dir)
Determines the highest message number in use for a given user and mailbox folder. ...
Convenient Signal Processing routines.
#define ast_odbc_request_obj(name, check)
Get a ODBC connection object.
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 AST_STANDARD_APP_ARGS(args, parse)
Performs the 'standard' argument separation process for an application.
void astman_send_list_complete_start(struct mansession *s, const struct message *m, const char *event_name, int count)
Start the list complete event.
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_gr(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
Greek syntax for 'You have N messages' greeting.
descriptor for a cli entry.
#define AST_LIST_UNLOCK(head)
Attempts to unlock a list.
int ast_file_is_readable(const char *filename)
Test that a file exists and is readable by the effective user.
char * ast_str_buffer(const struct ast_str *buf)
Returns the string buffer within the ast_str buf.
Voicemail greeter function table definition.
static int debug
Global debug status.
#define AST_TASKPROCESSOR_HIGH_WATER_LEVEL
#define ao2_callback(c, flags, cb_fn, arg)
ao2_callback() is a generic function that applies cb_fn() to all objects in a container, as described below.
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...
int ast_unload_realtime(const char *family)
Release any resources cached for a realtime family.
static struct stasis_rest_handlers mailboxes
REST handler for /api-docs/mailboxes.json.
struct ast_smdi_interface * ast_smdi_interface_find(const char *iface_name)
Find an SMDI interface with the specified name.
int ast_odbc_prepare(struct odbc_obj *obj, SQLHSTMT *stmt, const char *sql)
Prepares a SQL query on a statement.
struct ast_tm * ast_localtime(const struct timeval *timep, struct ast_tm *p_tm, const char *zone)
Timezone-independent version of localtime_r(3).
static void copy_plain_file(char *frompath, char *topath)
Copies a voicemail information (envelope) file.
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.
int ast_check_realtime(const char *family)
Check if realtime engine is configured for family.
Structure for variables, used for configurations and for channel variables.
void ast_close_fds_above_n(int n)
Common routine for child processes, to close all fds prior to exec(2)
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 count_messages(struct ast_vm_user *vmu, char *dir)
Find all .txt files - even if they are not in sequence from 0000.
int ast_adsi_set_keys(unsigned char *buf, unsigned char *keys)
Set which soft keys should be displayed.
#define AST_LIST_NEXT(elm, field)
Returns the next entry in the list after the given entry.
int ast_adsi_load_session(struct ast_channel *chan, unsigned char *app, int ver, int data)
Check if scripts for a given app are already loaded. Version may be -1, if any version is okay...
void ast_str_substitute_variables(struct ast_str **buf, ssize_t maxlen, struct ast_channel *chan, const char *templ)
int ast_say_digit_str(struct ast_channel *chan, const char *num, const char *ints, const char *lang)
says digits of a string
void( ast_vm_msg_play_cb)(struct ast_channel *chan, const char *playfile, int duration)
Voicemail playback callback function definition.
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.
int ast_adsi_download_disconnect(unsigned char *buf)
Disconnects (and hopefully saves) a downloaded script.
AO2_STRING_FIELD_CMP_FN(transport_monitor, key)
Comparison function for struct transport_monitor.
ast_channel_state
ast_channel states
char * str
Subscriber name (Malloced)
static void free_zone(struct minivm_zone *z)
Free Mini Voicemail timezone.
#define VM_ODBC_AUDIO_ON_DISK
int ast_str_append(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Append to a thread local dynamic string.
#define ast_cli_register_multiple(e, len)
Register multiple commands.
void ast_vm_unregister(const char *module_name)
Unregister the specified voicemail provider.
void ao2_iterator_destroy(struct ao2_iterator *iter)
Destroy a container iterator.
static int copy(char *infile, char *outfile)
Utility function to copy a file.
struct timeval ast_tvnow(void)
Returns current timeval. Meant to replace calls to gettimeofday().
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...
#define AST_LIST_EMPTY(head)
Checks whether the specified list contains any entries.
void astman_send_ack(struct mansession *s, const struct message *m, char *msg)
Send ack in manager transaction.
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 ast_strdup(str)
A wrapper for strdup()
static int check_mime(const char *str)
Check if the string would need encoding within the MIME standard, to avoid confusing certain mail sof...
void ast_mwi_state_callback_subscribed(on_mwi_state handler, void *data)
For each managed mailbox that has a subscriber call the given handler.
Generic File Format Support. Should be included by clients of the file handling routines. File service providers should instead include mod_format.h.
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.
char * ast_category_browse(struct ast_config *config, const char *prev_name)
Browse categories.
int ast_unlock_path(const char *path)
Unlock a path.
struct ast_mwi_state * ast_mwi_subscriber_data(struct ast_mwi_subscriber *sub)
Retrieves the state data object associated with the MWI subscriber.
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.
Definitions to aid in the use of thread local storage.
int ast_filedelete(const char *filename, const char *fmt)
Deletes a file.
ADSI Support (built upon Caller*ID)
int ast_mwi_add_observer(struct ast_mwi_observer *observer)
Add an observer to receive MWI state related events.
static int inboxcount2(const char *mailbox, int *urgentmsgs, int *newmsgs, int *oldmsgs)
Check the given mailbox's message count.
int ast_channel_setoption(struct ast_channel *channel, int option, void *data, int datalen, int block)
Sets an option on a channel.
list of users found in the config file
void(* on_subscribe)(const char *mailbox, struct ast_mwi_subscriber *sub)
Raised when MWI is being subscribed.
int ast_unregister_application(const char *app)
Unregister an application.
#define AST_LIST_TRAVERSE_SAFE_END
Closes a safe loop traversal block.
int ast_update_realtime(const char *family, const char *keyfield, const char *lookup,...) attribute_sentinel
Update realtime configuration.
char context[MAX_VM_CONTEXT_LEN]
int ast_atomic_fetchadd_int(volatile int *p, int v)
Atomically add v to *p and return the previous value of *p.
int ast_custom_function_unregister(struct ast_custom_function *acf)
Unregister a custom function.
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.
static int get_date(char *s, int len)
Gets the current date and time, as formatted string.
const char * pbx_builtin_getvar_helper(struct ast_channel *chan, const char *name)
Return a pointer to the value of the corresponding channel variable.
#define ast_asprintf(ret, fmt,...)
A wrapper for asprintf()
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.
const char * astman_get_header(const struct message *m, char *var)
Get header from manager transaction.
int ast_update2_realtime(const char *family,...) attribute_sentinel
Update realtime configuration.
All configuration options for http media cache.
off_t ast_tellstream(struct ast_filestream *fs)
Tell where we are in a stream.
static int make_file(char *dest, const int len, const char *dir, const int num)
Creates a file system path expression for a folder within the voicemail data folder and the appropria...
int ast_smdi_mwi_set(struct ast_smdi_interface *iface, const char *mailbox)
Set the MWI indicator for a mailbox.
#define AST_APP_OPTIONS(holder, options...)
Declares an array of options for an application.
void ast_category_append(struct ast_config *config, struct ast_category *category)
Appends a category to a config.
Custom localtime functions for multiple timezones.
int ast_str_set(struct ast_str **buf, ssize_t max_len, const char *fmt,...)
Set a dynamic string using variable arguments.
struct ast_party_id id
Caller party ID.
enum AST_LOCK_RESULT ast_lock_path(const char *path)
Lock a filesystem path.
Configuration File Parser.
static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
The handler for the change password option.
void ao2_container_unregister(const char *name)
Unregister a container for CLI stats and integrity check.
static int vm_browse_messages_vi(struct ast_channel *chan, struct vm_state *vms, struct ast_vm_user *vmu)
Vietnamese syntax for 'You have N messages' greeting.
#define force_reload_config()
Forcibly reload voicemail.conf, even if it has not changed. This is necessary after running unit test...
int ast_app_inboxcount2(const char *mailboxes, int *urgentmsgs, int *newmsgs, int *oldmsgs)
Determine number of urgent/new/old messages in a mailbox.
int ast_get_time_t(const char *src, time_t *dst, time_t _default, int *consumed)
Parse a time (integer) string.
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.
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.
int ast_adsi_set_line(unsigned char *buf, int page, int line)
Sets the current line and page.
static void cleanup(void)
Clean up any old apps that we don't need any more.
#define ast_config_load(filename, flags)
Load a config file.
int ast_adsi_input_format(unsigned char *buf, int num, int dir, int wrap, char *format1, char *format2)
Set input format.
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.
int ast_store_realtime(const char *family,...) attribute_sentinel
Create realtime configuration.
int ast_build_string(char **buffer, size_t *space, const char *fmt,...)
Build a string in a buffer, designed to be called repeatedly.
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.
General Asterisk PBX channel definitions.
int ast_realtime_require_field(const char *family,...) attribute_sentinel
Inform realtime what fields that may be stored.
Asterisk file paths, configured in asterisk.conf.
void astman_send_list_complete_end(struct mansession *s)
End the list complete event.
#define ast_string_field_init(x, size)
Initialize a field pool and fields.
#define ast_strdupa(s)
duplicate a string in memory from the stack
static int change_password_realtime(struct ast_vm_user *vmu, const char *password)
Performs a change of the voicemail passowrd in the realtime engine.
#define ast_dummy_channel_alloc()
Create a fake channel structure.
Data structure associated with a custom dialplan function.
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.
#define VM_EMAIL_EXT_RECS
#define ao2_ref(o, delta)
Reference/unreference an object and return the old refcount.
#define AST_MAX_EXTENSION
Caller Party information.
#define AST_LIST_REMOVE_CURRENT(field)
Removes the current entry from a list during a traversal.
structure to hold extensions
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 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_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...
In case you didn't read that giant block of text above the mansession_session struct, the mansession is named this solely to keep the API the same in Asterisk. This structure really represents data that is different from Manager action to Manager action. The mansession_session pointer contained within points to session-specific data.
struct timeval ast_samp2tv(unsigned int _nsamp, unsigned int _rate)
Returns a timeval corresponding to the duration of n samples at rate r. Useful to convert samples to ...
static int check_password(struct ast_vm_user *vmu, char *password)
Check that password meets minimum required length.
static void generate_msg_id(char *dst)
Sets the destination string to a uniquely identifying msg_id string.
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.
char * ast_format_str_reduce(char *fmts)
#define ast_malloc(len)
A wrapper for malloc()
#define ast_debug(level,...)
Log a DEBUG message.
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 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 AST_LIST_REMOVE_HEAD(head, field)
Removes and returns the head entry from a list.
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_exists_extension(struct ast_channel *c, const char *context, const char *exten, int priority, const char *callerid)
Determine whether an extension exists.
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.
static int vm_delete(char *file)
Removes the voicemail sound and information file.
struct ast_config * ast_config_new(void)
Create a new base configuration structure.
int ast_ratestream(struct ast_filestream *fs)
Return the sample rate of the stream's format.
struct ast_vm_mailbox_snapshot * ast_vm_mailbox_snapshot_destroy(struct ast_vm_mailbox_snapshot *mailbox_snapshot)
destroy a snapshot
Structure to describe a channel "technology", ie a channel driver See for examples: ...
static void apply_options(struct ast_vm_user *vmu, const char *options)
Destructively Parse options and apply.
Core PBX routines and definitions.
int ast_check_hangup(struct ast_channel *chan)
Check to see if a channel is needing hang up.
void ast_vm_greeter_unregister(const char *module_name)
Unregister the specified voicemail greeter provider.
#define AST_LIST_HEAD_STATIC(name, type)
Defines a structure to be used to hold a list of specified type, statically initialized.
static int get_folder2(struct ast_channel *chan, char *fn, int start)
plays a prompt and waits for a keypress.
#define ast_test_suite_event_notify(s, f,...)
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.
#define ast_alloca(size)
call __builtin_alloca to ensure we get gcc builtin semantics
static void apply_option(struct ast_vm_user *vmu, const char *var, const char *value)
Sets a specific property value.
#define ast_vm_register(vm_table)
See __ast_vm_register()
#define ASTERISK_USERNAME
int ast_manager_unregister(const char *action)
Unregister a registered manager command.
#define DEFAULT_POLL_FREQ
The AMI - Asterisk Manager Interface - is a TCP protocol created to manage Asterisk with third-party ...
struct ast_config * ast_load_realtime_multientry(const char *family,...) attribute_sentinel
Retrieve realtime configuration.
#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_INSERT_TAIL(head, elm, field)
Appends a list entry to the tail of a list.
#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.
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.
SQLHSTMT ast_odbc_direct_execute(struct odbc_obj *obj, SQLHSTMT(*exec_cb)(struct odbc_obj *obj, void *data), void *data)
Executes an non prepared statement and returns the resulting statement handle.
int attribute_pure ast_true(const char *val)
Make sure something is true. Determine if a string containing a boolean value is "true". This function checks to see whether a string passed to it is an indication of an "true" value. It checks to see if the string is "yes", "true", "y", "t", "on" or "1".
Support for dynamic strings.
int ast_safe_system(const char *s)
Safely spawn an OS shell command while closing file descriptors.
void ast_mwi_remove_observer(struct ast_mwi_observer *observer)
Remove an MWI state observer.
#define AST_OPTION_RXGAIN
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.
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.
#define AST_APP_OPTION_ARG(option, flagno, argno)
Declares an application option that accepts an argument.
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.
const char * module_name
The name of the module that provides the voicemail greeter functionality.
static unsigned int poll_mailboxes
#define AST_NONSTANDARD_APP_ARGS(args, parse, sep)
Performs the 'nonstandard' argument separation process for an application.
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.
int ast_safe_fork(int stop_reaper)
Common routine to safely fork without a chance of a signal handler firing badly in the child...
struct timeval ast_tvadd(struct timeval a, struct timeval b)
Returns the sum of two timevals a + b.
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.
int ast_goto_if_exists(struct ast_channel *chan, const char *context, const char *exten, int priority)
int ast_seekstream(struct ast_filestream *fs, off_t sample_offset, int whence)
Seeks into stream.
#define AST_LIST_TRAVERSE(head, var, field)
Loops over (traverses) the entries in a list.
#define AST_LIST_ENTRY(type)
Declare a forward link structure inside a list entry.
#define AST_LIST_INSERT_HEAD(head, elm, field)
Inserts a list entry at the head of a list.
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 int save_to_folder(struct ast_vm_user *vmu, struct vm_state *vms, int msg, int box, int *newmsg, int move)
void ast_mwi_state_callback_all(on_mwi_state handler, void *data)
For each managed mailbox call the given handler.
#define ast_calloc(num, len)
A wrapper for calloc()
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.
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.
int ast_closestream(struct ast_filestream *f)
Closes a stream.
void ast_hangup(struct ast_channel *chan)
Hang up a channel.
static int load_module(void)
Load the module.
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.
SMDI support for Asterisk.
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.
Support for logging to various files, console and syslog Configuration in file logger.conf.
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.
Module has failed to load, may be in an inconsistent state.
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...
#define ast_publish_mwi_state_channel(mailbox, context, new_msgs, old_msgs, channel_id)
Publish a MWI state update associated with some channel.
An API for managing task processing threads that can be shared across modules.
char language[MAX_LANGUAGE]
structure to hold users read from users.conf
Structure used to handle boolean flags.
const ast_string_field uniqueid
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". If folder is "INBOX", includes the number of messages in the "Urgent" folder.
Options for leaving voicemail with the voicemail() application.
int ast_app_messagecount(const char *mailbox_id, const char *folder)
Get the number of messages in a given mailbox folder.
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 SENDMAIL
Default mail command to mail voicemail. Change it with the mailcmd= command in voicemail.conf.
struct ast_frame ast_null_frame
int ast_waitfordigit(struct ast_channel *c, int ms)
Waits for a digit.
const char * module_name
The name of the module that provides the voicemail functionality.
SQLRETURN ast_odbc_execute_sql(struct odbc_obj *obj, SQLHSTMT *stmt, const char *sql)
Execute a unprepared SQL query.
void ast_str_reset(struct ast_str *buf)
Reset the content of a dynamic string. Useful before a series of ast_str_append.
size_t ast_str_strlen(const struct ast_str *buf)
Returns the current length of the string stored within buf.
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.
int ast_adsi_available(struct ast_channel *chan)
Returns non-zero if Channel does or might support ADSI.
Structure used for ast_copy_recording_to_vm in order to cleanly supply data needed for making the rec...
A ast_taskprocessor structure is a singleton by name.
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.
This structure is allocated by file.c in one chunk, together with buf_size and desc_size bytes of mem...
When we need to walk through a container, we use an ao2_iterator to keep track of the current positio...
int ast_say_number(struct ast_channel *chan, int num, const char *ints, const char *lang, const char *options)
says a number
Standard Command Line Interface.
int ast_destroy_realtime(const char *family, const char *keyfield, const char *lookup,...) attribute_sentinel
Destroy realtime configuration.
static int has_voicemail(const char *mailbox, const char *folder)
Determines if the given folder has messages.
void ast_copy_string(char *dst, const char *src, size_t size)
Size-limited null-terminating string copy.
#define S_OR(a, b)
returns the equivalent of logic or for strings: first one if not empty, otherwise second one...
void * ast_taskprocessor_unreference(struct ast_taskprocessor *tps)
Unreference the specified taskprocessor and its reference count will decrement.
FILE * ast_file_mkftemp(char *template_name, mode_t mode)
same as mkstemp, but return a FILE
ast_app: A registered application
int attribute_pure ast_false(const char *val)
Make sure something is false. Determine if a string containing a boolean value is "false"...
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...
MWI state event interface.
int ast_waitstream(struct ast_channel *c, const char *breakon)
Waits for a stream to stop or digit to be pressed.
int ast_fileexists(const char *filename, const char *fmt, const char *preflang)
Checks for the existence of a given file.
static char * handle_voicemail_reload(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
Reload voicemail configuration from the CLI.
int ast_answer(struct ast_channel *chan)
Answer a channel.
const char * ast_config_option(struct ast_config *cfg, const char *cat, const char *var)
Retrieve a configuration variable within the configuration set.
static int load_users(void)
Callback that loads the users from phoneprov sections.
Data structure associated with a single frame of data.
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.
#define AST_TEST_DEFINE(hdr)
Abstract JSON element (object, array, string, int, ...).
unsigned int module_version
The version of this function table.
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.
int ast_filerename(const char *oldname, const char *newname, const char *fmt)
Renames a 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.
static int is_valid_dtmf(const char *key)
Determines if a DTMF key entered is valid.
#define AST_LIST_TRAVERSE_SAFE_BEGIN(head, var, field)
Loops safely over (traverses) the entries in a list.
int ast_adsi_input_control(unsigned char *buf, int page, int line, int display, int format, int just)
Set input information.
struct ast_str * ast_str_thread_get(struct ast_threadstorage *ts, size_t init_len)
Retrieve a thread locally stored dynamic string.
unsigned char valid
TRUE if the name information is valid/present.
int ast_smdi_mwi_unset(struct ast_smdi_interface *iface, const char *mailbox)
Unset the MWI indicator for a mailbox.
int ast_readstring(struct ast_channel *c, char *s, int len, int timeout, int rtimeout, char *enders)
Reads multiple digits.
#define AST_APP_OPTION(option, flagno)
Declares an application option that does not accept an argument.
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_LIST_INSERT_BEFORE_CURRENT(elm, field)
Inserts a list entry before the current entry during a traversal.
void ast_config_destroy(struct ast_config *cfg)
Destroys a config.
static void run_externnotify(struct ast_channel *chan, struct minivm_account *vmu)
Run external notification for voicemail message.
static int load_config_force(int reload, int force)
Reload voicemail.conf.
void ast_odbc_release_obj(struct odbc_obj *obj)
Releases an ODBC object previously allocated by ast_odbc_request_obj()
The structure that contains MWI state.
struct ast_app * pbx_findapp(const char *app)
Look up an application.
void ast_party_caller_init(struct ast_party_caller *init)
Initialize the given caller structure.
#define ast_manager_register_xml(action, authority, func)
Register a manager callback using XML documentation to describe the manager.
Say numbers and dates (maybe words one day too)
#define ASTERISK_GPL_KEY
The text the key() function should return.
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.
#define ast_channel_alloc(needqueue, state, cid_num, cid_name, acctcode, exten, context, assignedids, requestor, amaflag,...)
Create a channel structure.
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.
int ast_dsp_get_threshold_from_settings(enum threshold which)
Get silence threshold from dsp.conf.
void astman_send_error(struct mansession *s, const struct message *m, char *error)
Send error in manager transaction.
Asterisk module definitions.
Voicemail function table definition.
#define RAII_VAR(vartype, varname, initval, dtor)
Declare a variable that will call a destructor function when it goes out of scope.
static struct ast_flags globalflags
char mailbox[MAX_VM_MBOX_ID_LEN]
#define AST_DECLARE_APP_ARGS(name, arglist)
Declare a structure to hold an application's arguments.
#define ast_string_field_free_memory(x)
free all memory - to be called before destroying the object
#define ast_vm_greeter_register(vm_table)
See __ast_vm_greeter_register()
Application convenience functions, designed to give consistent look and feel to Asterisk apps...
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.
unsigned char valid
TRUE if the number information is valid/present.
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 ...
struct ao2_iterator ao2_iterator_init(struct ao2_container *c, int flags) attribute_warn_unused_result
Create an iterator for a container.
static int valid_config(const struct ast_config *cfg)
Check if configuration file is valid.
#define ast_custom_function_register(acf)
Register a custom function.
int ast_stopstream(struct ast_channel *c)
Stops a stream.
#define ast_register_application_xml(app, execute)
Register an application using XML documentation.
Structure for mutex and tracking information.
An SMDI message waiting indicator message.
static int reset_user_pw(const char *context, const char *mailbox, const char *newpass)
Resets a user password to a specified password.
void ast_manager_publish_event(const char *type, int class_type, struct ast_json *obj)
Publish an event to AMI.
static unsigned int poll_freq
#define ast_str_create(init_len)
Create a malloc'ed dynamic length string.
int ast_app_inboxcount(const char *mailboxes, int *newmsgs, int *oldmsgs)
Determine number of new/old messages in a mailbox.
static void populate_defaults(struct ast_vm_user *vmu)
Sets default voicemail system options to a voicemail user.
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'.
#define AST_APP_ARG(name)
Define an application argument.
int ast_mkdir(const char *path, int mode)
Recursively create directory path.
int ast_callerid_parse(char *instr, char **name, char **location)
Destructively parse inbuf into name and location (or number)
#define ast_string_field_set(x, field, data)
Set a field to a simple string value.
void astman_send_listack(struct mansession *s, const struct message *m, char *msg, char *listflag)
Send ack in manager transaction to begin a list.
struct ast_party_number number
Subscriber phone number.
#define ao2_link(container, obj)
Add an object to a container.