Fix VM "goodbye" for real
[asterisk/asterisk.git] / apps / app_voicemail2.c
index 53b7940..50d7bc4 100755 (executable)
@@ -136,6 +136,7 @@ static char vmfmts[80];
 static int vmmaxmessage;
 static int maxgreet;
 static int skipms;
+static int maxlogins;
 
 STANDARD_LOCAL_USER;
 
@@ -182,6 +183,27 @@ static struct ast_vm_user *find_user(struct ast_vm_user *ivm, char *context, cha
        return vmu;
 }
 
+static int reset_user_pw(char *context, char *mailbox, char *newpass)
+{
+       /* This function could be made to generate one from a database, too */
+       struct ast_vm_user *cur;
+       int res = -1;
+       ast_pthread_mutex_lock(&vmlock);
+       cur = users;
+       while(cur) {
+               if ((!context || !strcasecmp(context, cur->context)) &&
+                       (!strcasecmp(mailbox, cur->mailbox)))
+                               break;
+               cur=cur->next;
+       }
+       if (cur) {
+               strncpy(cur->password, newpass, sizeof(cur->password) - 1);
+               res = 0;
+       }
+       ast_pthread_mutex_unlock(&vmlock);
+       return res;
+}
+
 static int vm_change_password(struct ast_vm_user *vmu, char *newpassword)
 {
         /*  There's probably a better way of doing this. */
@@ -256,6 +278,8 @@ static int vm_change_password(struct ast_vm_user *vmu, char *newpassword)
 
         unlink((char *)tmpin);
         rename((char *)tmpout,(char *)tmpin);
+       reset_user_pw(vmu->context, vmu->mailbox, newpassword);
+       strncpy(vmu->password, newpassword, sizeof(vmu->password) - 1);
        return(1);
 }
 
@@ -545,6 +569,10 @@ static int play_and_record(struct ast_channel *chan, char *playfile, char *recor
        char *sfmt[MAX_OTHER_FORMATS];
        char *stringp=NULL;
        time_t start, end;
+       struct ast_dsp *sildet;         /* silence detector dsp */
+       int totalsilence = 0;
+       int dspsilence = 0;
+       int gotsilence = 0;             /* did we timeout for silence? */
        
        
        ast_log(LOG_DEBUG,"play_and_record: %s, %s, '%s'\n", playfile ? playfile : "<None>", recordfile, fmt);
@@ -585,6 +613,23 @@ static int play_and_record(struct ast_channel *chan, char *playfile, char *recor
                        break;
                }
        }
+       
+       sildet = ast_dsp_new(); //Create the silence detector
+       if (!sildet) {
+               ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
+               return -1;
+       }
+       ast_dsp_set_threshold(sildet, 50);
+       
+       if (maxsilence > 0) {
+               //rfmt = chan->readformat;
+               res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
+               if (res < 0) {
+                       ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
+                       return -1;
+               }
+       }
+                                               
        if (x == fmtcnt) {
        /* Loop forever, writing the packets we read to the writer(s), until
           we read a # or get a hangup */
@@ -613,6 +658,24 @@ static int play_and_record(struct ast_channel *chan, char *playfile, char *recor
                                for (x=0;x<fmtcnt;x++) {
                                        res = ast_writestream(others[x], f);
                                }
+                               
+                               /* Silence Detection */
+                               if (maxsilence > 0) {
+                                       dspsilence = 0;
+                                       ast_dsp_silence(sildet, f, &dspsilence);
+                                       if (dspsilence)
+                                               totalsilence = dspsilence;
+                                       else
+                                               totalsilence = 0;
+                                       
+                                       if (totalsilence > maxsilence) {
+                                       /* Ended happily with silence */
+                                       ast_frfree(f);
+                                       gotsilence = 1;
+                                       outmsg=2;
+                                       break;
+                                       }
+                               }
                                /* Exit on any error */
                                if (res) {
                                        ast_log(LOG_WARNING, "Error writing frame\n");
@@ -654,6 +717,11 @@ static int play_and_record(struct ast_channel *chan, char *playfile, char *recor
        for (x=0;x<fmtcnt;x++) {
                if (!others[x])
                        break;
+               if (gotsilence)
+                       ast_stream_rewind(others[x], totalsilence-1000);
+               else
+                       ast_stream_rewind(others[x], 1000);
+               ast_truncstream(others[x]);
                ast_closestream(others[x]);
        }
        if (outmsg) {
@@ -681,7 +749,6 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int
        FILE *txt;
        int res = 0;
        int msgnum;
-       int maxmessage=0;
        char date[256];
        char dir[256];
        char fn[256];
@@ -692,14 +759,6 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int
        char *stringp;
        time_t start;
        time_t end;
-#if 0
-       /* XXX Need to be moved to play_and_record */
-       struct ast_dsp *sildet;         /* silence detector dsp */
-       int totalsilence = 0;
-       int dspsilence = 0;
-       int gotsilence = 0;             /* did we timeout for silence? */
-#endif 
-
        char tmp[256] = "";
        struct ast_vm_user *vmu;
        struct ast_vm_user svm;
@@ -822,7 +881,9 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int
                                        fclose(txt);
                                } else
                                        ast_log(LOG_WARNING, "Error opening text file for output\n");
-                               res = play_and_record(chan, NULL, fn, maxmessage, fmt);
+                               res = play_and_record(chan, NULL, fn, vmmaxmessage, fmt);
+                               if (res > 0)
+                                       res = 0;
                                txt = fopen(txtfile, "a");
                                if (txt) {
                                        time(&end);
@@ -839,24 +900,7 @@ static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int
                        } else
                                ast_log(LOG_WARNING, "No more messages possible\n");
                } else
-                       ast_log(LOG_WARNING, "No format for saving voicemail?\n");
-       
-#if 0
-                                               sildet = ast_dsp_new(); //Create the silence detector
-                                               if (silence > 0) {
-                                                       rfmt = chan->readformat;
-                                                       res = ast_set_read_format(chan, AST_FORMAT_SLINEAR);
-                                                       if (res < 0) {
-                                                               ast_log(LOG_WARNING, "Unable to set to linear mode, giving up\n");
-                                                               return -1;
-                                                       }
-                                                       if (!sildet) {
-                                                               ast_log(LOG_WARNING, "Unable to create silence detector :(\n");
-                                                               return -1;
-                                                       }
-                                                       ast_dsp_set_threshold(sildet, 50);
-                                               }
-#endif                                         
+                       ast_log(LOG_WARNING, "No format for saving voicemail?\n");                                      
                free_user(vmu);
        } else
                ast_log(LOG_WARNING, "No entry in voicemail config file for '%s'\n", ext);
@@ -1843,6 +1887,7 @@ static int vm_execmain(struct ast_channel *chan, void *data)
        char fmtc[256] = "";
        char password[80];
        struct vm_state vms;
+       int logretries = 0;
        struct ast_vm_user *vmu = NULL, vmus;
        char *context=NULL;
 
@@ -1897,7 +1942,7 @@ static int vm_execmain(struct ast_channel *chan, void *data)
        
        /* Authenticate them and get their mailbox/password */
        
-       while (!valid) {
+       while (!valid && (logretries < maxlogins)) {
                /* Prompt for, and read in the username */
                if (!skipuser && ast_readstring(chan, vms.username, sizeof(vms.username) - 1, 2000, 10000, "#") < 0) {
                        ast_log(LOG_WARNING, "Couldn't read username\n");
@@ -1941,6 +1986,13 @@ static int vm_execmain(struct ast_channel *chan, void *data)
                        if (ast_streamfile(chan, "vm-incorrect", chan->language))
                                break;
                }
+               logretries++;
+       }
+       if (!valid && (logretries >= maxlogins)) {
+               ast_stopstream(chan);
+               res = play_and_wait(chan, "vm-goodbye");
+               if (res > 0)
+                       res = 0;
        }
 
        if (valid) {
@@ -2082,19 +2134,12 @@ static int vm_execmain(struct ast_channel *chan, void *data)
                        case '0':
                                cmd = vm_options(chan, vmu, &vms, vmfmts);
                                break;
-                       case '#':
-                               ast_stopstream(chan);
-                               adsi_goodbye(chan);
-                               cmd = play_and_wait(chan, "vm-goodbye");
-                               if (cmd > 0)
-                                       cmd = '#';
-                               break;
                        default:        /* Nothing */
                                cmd = vm_instructions(chan, &vms);
                                break;
                        }
                }
-               if (cmd == 't') {
+               if ((cmd == 't') || (cmd == '#')) {
                        /* Timeout */
                        res = 0;
                } else {
@@ -2106,6 +2151,9 @@ out:
        if (res > -1) {
                ast_stopstream(chan);
                adsi_goodbye(chan);
+               res = play_and_wait(chan, "vm-goodbye");
+               if (res > 0)
+                       res = 0;
                if (useadsi)
                        adsi_unload_session(chan);
        }
@@ -2264,6 +2312,15 @@ static int load_users(void)
                        }
                }
 
+               maxlogins = 3;
+               if ((s = ast_variable_retrieve(cfg, "general", "maxlogins"))) {
+                       if (sscanf(s, "%d", &x) == 1) {
+                               maxlogins = x;
+                       } else {
+                               ast_log(LOG_WARNING, "Invalid max failed login attempts\n");
+                       }
+               }
+
                cat = ast_category_browse(cfg, NULL);
                while(cat) {
                        if (strcasecmp(cat, "general")) {