--- app_voicemail.c.orig	2006-12-20 05:56:09.000000000 +0300
+++ app_voicemail.c	2007-01-14 01:44:50.188542932 +0300
@@ -297,6 +297,7 @@
 	char context[AST_MAX_CONTEXT];   /*!< Voicemail context */
 	char mailbox[AST_MAX_EXTENSION]; /*!< Mailbox id, unique within vm context */
 	char password[80];               /*!< Secret pin code, numbers only */
+	char password_hash[33];               /*!< Secret pin code, md5hash */
 	char fullname[80];               /*!< Full name, for directory app */
 	char email[80];                  /*!< E-mail address */
 	char pager[80];                  /*!< E-mail address to pager (no attachment) */
@@ -751,6 +752,125 @@
 	return res;
 }
 
+static void load_passwd_encrypted(struct ast_vm_user *vmu)
+{
+	FILE *f;
+	char buf[256], passwd_file[PATH_MAX];
+	char *context, *mailbox, *md5hash;
+	
+	snprintf(passwd_file, sizeof(passwd_file), "%s/vmpasswd", ast_config_AST_CONFIG_DIR);
+	f = fopen(passwd_file,"r");
+	if (!f) return;
+	
+	while(!feof(f)) {
+		fgets(buf, sizeof(buf), f);
+		if (ast_strlen_zero(buf)) continue;
+		buf[strlen(buf) - 1] = '\0';
+		context = buf;
+		mailbox = strchr(buf, ':');
+		if (mailbox == NULL) continue;
+		*mailbox = '\0';
+		mailbox++;
+		md5hash = strchr(mailbox, ':');
+		if (md5hash == NULL) continue;
+		*md5hash = '\0';
+		md5hash++;
+		if (strlen(md5hash) < 32) {
+			ast_log(LOG_WARNING,"Wrong length of encrypted password for %s@%s\n", mailbox, context);
+			continue;
+		}
+		if (!strcasecmp(context, vmu->context) && !strcasecmp(mailbox, vmu->mailbox)) {
+			ast_copy_string(vmu->password_hash, md5hash, sizeof(vmu->password_hash));
+			break;
+		}
+	}
+	fclose(f);
+}
+
+static int save_passwd_encrypted(struct ast_vm_user *vmu, const char *newpassword)
+{
+	FILE *f, *ftmp;
+	char buf[256], buf2[256], passwd_file[PATH_MAX], passwd_file_tmp[PATH_MAX], newpasswd_hash[33]="";
+	char *context, *mailbox, *md5hash;
+	struct stat statbuf;
+	int count=0;
+
+	snprintf(passwd_file_tmp, sizeof(passwd_file_tmp), "%s/vmpasswd.LOCK", ast_config_AST_CONFIG_DIR);
+	f = fopen(passwd_file_tmp,"r");
+	if (f) {
+		/* password being changed by another process */
+		fclose(f);
+		sleep(1);
+		f = fopen(passwd_file_tmp,"r");
+		if (f) {
+			fclose(f);
+			ast_log(LOG_WARNING,"vmpasswd file being used by another process\n");
+			return 1;
+		}
+	}
+	snprintf(passwd_file, sizeof(passwd_file), "%s/vmpasswd", ast_config_AST_CONFIG_DIR);
+	f = fopen(passwd_file,"r");
+	if (!f) {
+		/* file doesn't exists, try to create */
+		f = fopen(passwd_file, "w+");
+		fclose(f);
+		f = fopen(passwd_file,"r");
+	}
+	ftmp = fopen(passwd_file_tmp, "w+");
+	if (!f || !ftmp) {
+		if (f) fclose(f);
+		if (ftmp) {
+			fclose(ftmp);
+			unlink(passwd_file_tmp);
+		}
+		return 2;
+	}
+	
+	while(!feof(f)) {
+		fgets(buf, sizeof(buf), f);
+		if (ast_strlen_zero(buf)) continue;
+		buf[strlen(buf) - 1] = '\0';
+		ast_copy_string(buf2, buf, sizeof(buf2));
+		context = buf;
+		mailbox = strchr(buf, ':');
+		if (mailbox == NULL) continue;
+		*mailbox = '\0';
+		mailbox++;
+		md5hash = strchr(mailbox, ':');
+		if (md5hash == NULL) continue;
+		*md5hash = '\0';
+		md5hash++;
+		if (strlen(md5hash) < 32) {
+			ast_log(LOG_WARNING,"Wrong length of encrypted password for %s@%s\n", mailbox, context);
+			continue;
+		}
+		if (!strcasecmp(context, vmu->context) && !strcasecmp(mailbox, vmu->mailbox)) {
+			ast_md5_hash(newpasswd_hash, (char *)newpassword);
+			ast_copy_string(vmu->password_hash, newpasswd_hash, sizeof(vmu->password_hash));
+			snprintf(buf2, sizeof(buf2), "%s:%s:%s", context, mailbox, newpasswd_hash);
+			count++;
+		}
+		fprintf(ftmp, "%s\n", buf2);
+	}
+	if (!count) {
+		/* file was empty */
+		ast_md5_hash(newpasswd_hash, (char *)newpassword);
+		ast_copy_string(vmu->password_hash, newpasswd_hash, sizeof(vmu->password_hash));
+		snprintf(buf2, sizeof(buf2), "%s:%s:%s", vmu->context, vmu->mailbox, newpasswd_hash);
+		fprintf(ftmp, "%s\n", buf2);
+	}
+	fclose(f);
+	fclose(ftmp);
+        stat(passwd_file, &statbuf);
+	chmod(passwd_file_tmp, statbuf.st_mode);
+	chown(passwd_file_tmp, statbuf.st_uid, statbuf.st_gid);
+	unlink(passwd_file);
+	rename(passwd_file_tmp, passwd_file);
+	reset_user_pw(vmu->context, vmu->mailbox, newpassword);
+	ast_copy_string(vmu->password, newpassword, sizeof(vmu->password));
+	return 0;
+}
+
 static void vm_change_password(struct ast_vm_user *vmu, const char *newpassword)
 {
 	/*  There's probably a better way of doing this. */
@@ -769,6 +889,9 @@
 
 	if (!change_password_realtime(vmu, newpassword))
 		return;
+	
+	if (!save_passwd_encrypted(vmu, newpassword))
+		return;
 
 	snprintf(tmpin, sizeof(tmpin), "%s/voicemail.conf", ast_config_AST_CONFIG_DIR);
 	snprintf(tmpout, sizeof(tmpout), "%s/voicemail.conf.new", ast_config_AST_CONFIG_DIR);
@@ -6045,9 +6168,15 @@
 			passptr = vmu->password;
 			if (passptr[0] == '-') passptr++;
 		}
-		if (vmu && !strcmp(passptr, password))
+		if (vmu && !ast_strlen_zero(vmu->password_hash)) {
+			/* we have encrypted password */
+			char md5hash[33] = "";
+			ast_md5_hash(md5hash, password);
+			if (!strcmp(md5hash, vmu->password_hash))
+				valid++;
+		} else if (vmu && !strcmp(passptr, password))
 			valid++;
-		else {
+		if (!valid) {
 			if (option_verbose > 2)
 				ast_verbose( VERBOSE_PREFIX_3 "Incorrect password '%s' for user '%s' (context = %s)\n", password, mailbox, context ? context : "default");
 			if (!ast_strlen_zero(prefix))
@@ -6759,6 +6888,7 @@
 			ast_copy_string(vmu->pager, s, sizeof(vmu->pager));
 		if (stringp && (s = strsep(&stringp, ","))) 
 			apply_options(vmu, s);
+		load_password_encrypted(vmu);
 	}
 	return 0;
 }
@@ -7338,6 +7468,7 @@
 					populate_defaults(cur);
 					apply_options_full(cur, ast_variable_browse(ucfg, cat));
 					ast_copy_string(cur->context, userscontext, sizeof(cur->context));
+					load_passwd_encrypted(cur);
 				}
 			}
 			ast_config_destroy(ucfg);
