Index: apps/app_voicemail.c =================================================================== --- apps/app_voicemail.c (revision 98558) +++ apps/app_voicemail.c (working copy) @@ -380,6 +380,7 @@ unsigned int flags; /*!< VM_ flags */ int saydurationm; int maxmsg; /*!< Maximum number of msgs per folder for this mailbox */ + int maxdeletedmsg; /*!< Maximum number of deleted msgs saved for this mailbox */ int maxsecs; /*!< Maximum number of seconds per message for this mailbox */ #ifdef IMAP_STORAGE char imapuser[80]; /*!< IMAP server login */ @@ -563,6 +564,7 @@ static AST_LIST_HEAD_STATIC(zones, vm_zone); static int maxsilence; static int maxmsg; +static int maxdeletedmsg; static int silencethreshold = 128; static char serveremail[80]; static char mailcmd[160]; /* Configurable mail cmd */ @@ -683,6 +685,8 @@ vmu->maxsecs = vmmaxsecs; if (maxmsg) vmu->maxmsg = maxmsg; + if (maxdeletedmsg) + vmu->maxdeletedmsg = maxdeletedmsg; vmu->volgain = volgain; } @@ -757,6 +761,21 @@ ast_log(LOG_WARNING, "Maximum number of messages per folder is %d. Cannot accept value maxmsg=%s\n", MAXMSGLIMIT, value); vmu->maxmsg = MAXMSGLIMIT; } + } else if (!strcasecmp(var, "backupdeleted")) { + if (sscanf(value, "%d", &x) == 1) + vmu->maxdeletedmsg = x; + else if (ast_true(value)) + vmu->maxdeletedmsg = MAXMSG; + else + vmu->maxdeletedmsg = 0; + + if (vmu->maxdeletedmsg < 0) { + ast_log(LOG_WARNING, "Invalid number of deleted messages saved per mailbox backupdeleted=%s. Using default value %d\n", value, MAXMSG); + vmu->maxdeletedmsg = MAXMSG; + } else if (vmu->maxdeletedmsg > MAXMSGLIMIT) { + ast_log(LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %d. Cannot accept value backupdeleted=%s\n", MAXMSGLIMIT, value); + vmu->maxdeletedmsg = MAXMSGLIMIT; + } } else if (!strcasecmp(var, "volgain")) { sscanf(value, "%lf", &vmu->volgain); } else if (!strcasecmp(var, "options")) { @@ -2286,6 +2305,7 @@ "Cust3", "Cust4", "Cust5", + "Deleted", }; return (id >= 0 && id < (sizeof(msgs)/sizeof(msgs[0]))) ? msgs[id] : "Unknown"; } @@ -2319,6 +2339,8 @@ return 8; else if (!strcasecmp(folder, "Cust5")) return 9; + else if (!strcasecmp(folder, "Deleted")) + return 10; else /*assume they meant INBOX if folder is not found otherwise*/ return 0; } @@ -3456,20 +3478,33 @@ char dfn[PATH_MAX]; char ddir[PATH_MAX]; const char *dbox = mbox(box); - int x; - make_file(sfn, sizeof(sfn), dir, msg); + int x, i; create_dirpath(ddir, sizeof(ddir), context, username, dbox); if (vm_lock_path(ddir)) return ERROR_LOCK_PATH; x = last_message_index(vmu, ddir) + 1; - make_file(dfn, sizeof(dfn), ddir, x); - if (x >= vmu->maxmsg) { - ast_unlock_path(ddir); - return -1; + if (box == 10 && x >= vmu->maxdeletedmsg) { /* "Deleted" folder*/ + x--; + for (i = 1; i <= x; i++) { + /* Push files down a "slot". The oldest file (msg0000) will be deleted. */ + make_file(sfn, sizeof(sfn), ddir, i); + make_file(dfn, sizeof(dfn), ddir, i - 1); + if (EXISTS(ddir, i, sfn, NULL)) { + RENAME(ddir, i, vmu->mailbox, vmu->context, ddir, i - 1, sfn, dfn); + } else + break; + } + } else { + if (x >= vmu->maxmsg) { + ast_unlock_path(ddir); + return -1; + } } + make_file(sfn, sizeof(sfn), dir, msg); + make_file(dfn, sizeof(dfn), ddir, x); if (strcmp(sfn, dfn)) { COPY(dir, msg, ddir, x, username, context, sfn, dfn); } @@ -5251,14 +5286,23 @@ vms->deleted[x] = 0; vms->heard[x] = 0; --x; - } + } + } else if (vms->deleted[x] && vmu->maxdeletedmsg) { + /* Move to deleted folder */ + res = save_to_folder(vmu, vms, x, 10); + if (res == ERROR_LOCK_PATH) { + /* If save failed do not delete the message */ + vms->deleted[x] = 0; + vms->heard[x] = 0; + --x; + } } else if (vms->deleted[x] && ast_check_realtime("voicemail_data")) { /* If realtime storage enabled - we should explicitly delete this message, cause RENAME() will overwrite files, but will keep duplicate records in RT-storage */ make_file(vms->fn, sizeof(vms->fn), vms->curdir, x); if (EXISTS(vms->curdir, x, vms->fn, NULL)) DELETE(vms->curdir, x, vms->fn); - } + } } /* Delete ALL remaining messages */ @@ -8177,6 +8221,25 @@ } } + if (!(val = ast_variable_retrieve(cfg, "general", "backupdeleted"))) { + maxdeletedmsg = 0; + } else { + if (sscanf(val, "%d", &x) == 1) + maxdeletedmsg = x; + else if (ast_true(val)) + maxdeletedmsg = MAXMSG; + else + maxdeletedmsg = 0; + + if (maxdeletedmsg < 0) { + ast_log(LOG_WARNING, "Invalid number of deleted messages saved per mailbox '%s'. Using default value %i\n", val, MAXMSG); + maxdeletedmsg = MAXMSG; + } else if (maxdeletedmsg > MAXMSGLIMIT) { + ast_log(LOG_WARNING, "Maximum number of deleted messages saved per mailbox is %i. Cannot accept value '%s'\n", MAXMSGLIMIT, val); + maxdeletedmsg = MAXMSGLIMIT; + } + } + /* Load date format config for voicemail mail */ if ((val = ast_variable_retrieve(cfg, "general", "emaildateformat"))) { ast_copy_string(emaildateformat, val, sizeof(emaildateformat)); Index: configs/voicemail.conf.sample =================================================================== --- configs/voicemail.conf.sample (revision 98558) +++ configs/voicemail.conf.sample (working copy) @@ -265,7 +265,14 @@ ; listen-control-restart-key=2 ; Customize the key that restarts message playback ; listen-control-stop-key=13456789 ; Customize the keys that interrupt message playback, probably all keys not set above +; Maximum number of messages allowed in the 'Deleted' folder. If set to 0 +; or no then no deleted messages will be moved. If non-zero (max 9999) then up +; to this number of messages will be automagically saved when they are +; 'deleted' on a FIFO basis. +; default is 100 +; backupdeleted=100 + [zonemessages] eastern=America/New_York|'vm-received' Q 'digits/at' IMp central=America/Chicago|'vm-received' Q 'digits/at' IMp