mirror of
				https://github.com/asterisk/asterisk.git
				synced 2025-10-31 02:37:10 +00:00 
			
		
		
		
	Merge tilghman's voicemail changes
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@1250 65c4cc65-6c06-0410-ace0-fbb531ad65f3
This commit is contained in:
		| @@ -52,23 +52,17 @@ | ||||
| #define INTRO "vm-intro" | ||||
|  | ||||
| #define MAXMSG 100 | ||||
|  | ||||
| #define MAX_OTHER_FORMATS 10 | ||||
|  | ||||
| #define VM_SPOOL_DIR AST_SPOOL_DIR "/vm" | ||||
|  | ||||
| #define BASEMAXINLINE 256 | ||||
|  | ||||
| #define BASELINELEN 72 | ||||
|  | ||||
| #include <stdio.h> | ||||
| #include <stdlib.h> | ||||
| #include <unistd.h> | ||||
|  | ||||
| #define BASEMAXINLINE 256 | ||||
| #define BASELINELEN 72 | ||||
| #define eol "\r\n" | ||||
|  | ||||
| #define MAX_DATETIME_FORMAT	512 | ||||
| #define DIGITS_DIR	AST_SOUNDS "/digits/" | ||||
| struct baseio { | ||||
| 	int iocp; | ||||
| 	int iolen; | ||||
| @@ -85,11 +79,19 @@ struct ast_vm_user { | ||||
| 	char email[80]; | ||||
| 	char pager[80]; | ||||
| 	char serveremail[80]; | ||||
| 	char zonetag[80]; | ||||
| 	int attach; | ||||
| 	int alloced; | ||||
| 	struct ast_vm_user *next; | ||||
| }; | ||||
|  | ||||
| struct vm_zone { | ||||
| 	char name[80]; | ||||
| 	char timezone[80]; | ||||
| 	char msg_format[512]; | ||||
| 	struct vm_zone *next; | ||||
| }; | ||||
|  | ||||
| static char *tdesc = "Comedian Mail (Voicemail System)"; | ||||
|  | ||||
| static char *adapp = "CoMa"; | ||||
| @@ -134,6 +136,8 @@ static char *app2 = "VoiceMailMain2"; | ||||
| static pthread_mutex_t vmlock = AST_MUTEX_INITIALIZER; | ||||
| struct ast_vm_user *users; | ||||
| struct ast_vm_user *usersl; | ||||
| struct vm_zone *zones = NULL; | ||||
| struct vm_zone *zonesl = NULL; | ||||
| static int attach_voicemail; | ||||
| static int maxsilence; | ||||
| static int silencethreshold = 128; | ||||
| @@ -156,7 +160,7 @@ LOCAL_USER_DECL; | ||||
| static void apply_options(struct ast_vm_user *vmu, char *options) | ||||
| { | ||||
| 	/* Destructively Parse options and apply */ | ||||
| 	char *stringp = options; | ||||
| 	char *stringp = strdupa(options); | ||||
| 	char *s; | ||||
| 	char *var, *value; | ||||
| 	while((s = strsep(&stringp, "|"))) { | ||||
| @@ -169,6 +173,8 @@ static void apply_options(struct ast_vm_user *vmu, char *options) | ||||
| 					vmu->attach = 0; | ||||
| 			} else if (!strcasecmp(var, "serveremail")) { | ||||
| 				strncpy(vmu->serveremail, value, sizeof(vmu->serveremail) - 1); | ||||
| 			} else if (!strcasecmp(var, "tz")) { | ||||
| 				strncpy(vmu->zonetag, value, sizeof(vmu->zonetag) - 1); | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| @@ -212,62 +218,64 @@ static struct ast_vm_user *find_user(struct ast_vm_user *ivm, char *context, cha | ||||
|  | ||||
| 	retval=malloc(sizeof(struct ast_vm_user)); | ||||
|  | ||||
| 	*retval->mailbox='\0'; | ||||
| 	*retval->context='\0'; | ||||
| 	*retval->password='\0'; | ||||
| 	*retval->fullname='\0'; | ||||
| 	*retval->email='\0'; | ||||
| 	*retval->pager='\0'; | ||||
| 	*retval->serveremail='\0'; | ||||
| 	retval->attach=-1; | ||||
| 	retval->alloced=1; | ||||
| 	retval->next=NULL; | ||||
| 	if (mailbox) { | ||||
| 		strcpy(retval->mailbox, mailbox); | ||||
| 	} | ||||
| 	if (context) { | ||||
| 		strcpy(retval->context, context); | ||||
| 	} | ||||
| 	if (retval) { | ||||
| 		*retval->mailbox='\0'; | ||||
| 		*retval->context='\0'; | ||||
| 		*retval->password='\0'; | ||||
| 		*retval->fullname='\0'; | ||||
| 		*retval->email='\0'; | ||||
| 		*retval->pager='\0'; | ||||
| 		*retval->serveremail='\0'; | ||||
| 		retval->attach=-1; | ||||
| 		retval->alloced=1; | ||||
| 		retval->next=NULL; | ||||
| 		if (mailbox) { | ||||
| 			strcpy(retval->mailbox, mailbox); | ||||
| 		} | ||||
| 		if (context) { | ||||
| 			strcpy(retval->context, context); | ||||
| 		} | ||||
|  | ||||
| 	if (*retval->context) { | ||||
| 		sprintf(query, "SELECT password,fullname,email,pager,options FROM users WHERE context='%s' AND mailbox='%s'", context, mailbox); | ||||
| 	} else { | ||||
| 		sprintf(query, "SELECT password,fullname,email,pager,options FROM users WHERE mailbox='%s'", mailbox); | ||||
| 	} | ||||
| 	pthread_mutex_lock(&mysqllock); | ||||
| 	mysql_query(dbhandler, query); | ||||
| 	if ((result=mysql_store_result(dbhandler))!=NULL) { | ||||
| 		if ((rowval=mysql_fetch_row(result))!=NULL) { | ||||
| 			numFields=mysql_num_fields(result); | ||||
| 			fields=mysql_fetch_fields(result); | ||||
| 			for (i=0; i<numFields; i++) { | ||||
| 				if (rowval[i]) { | ||||
| 					if (!strcmp(fields[i].name, "password")) { | ||||
| 						strcpy(retval->password, rowval[i]); | ||||
| 					} else if (!strcmp(fields[i].name, "fullname")) { | ||||
| 						strcpy(retval->fullname, rowval[i]); | ||||
| 					} else if (!strcmp(fields[i].name, "email")) { | ||||
| 						strcpy(retval->email, rowval[i]); | ||||
| 					} else if (!strcmp(fields[i].name, "pager")) { | ||||
| 						strcpy(retval->pager, rowval[i]); | ||||
| 					} else if (!strcmp(fields[i].name, "options")) { | ||||
| 						strncpy(options, rowval[i], sizeof(options) - 1); | ||||
| 						apply_options(retval, options); | ||||
| 		if (*retval->context) { | ||||
| 			sprintf(query, "SELECT password,fullname,email,pager,options FROM users WHERE context='%s' AND mailbox='%s'", context, mailbox); | ||||
| 		} else { | ||||
| 			sprintf(query, "SELECT password,fullname,email,pager,options FROM users WHERE mailbox='%s'", mailbox); | ||||
| 		} | ||||
| 		pthread_mutex_lock(&mysqllock); | ||||
| 		mysql_query(dbhandler, query); | ||||
| 		if ((result=mysql_store_result(dbhandler))!=NULL) { | ||||
| 			if ((rowval=mysql_fetch_row(result))!=NULL) { | ||||
| 				numFields=mysql_num_fields(result); | ||||
| 				fields=mysql_fetch_fields(result); | ||||
| 				for (i=0; i<numFields; i++) { | ||||
| 					if (rowval[i]) { | ||||
| 						if (!strcmp(fields[i].name, "password")) { | ||||
| 							strcpy(retval->password, rowval[i]); | ||||
| 						} else if (!strcmp(fields[i].name, "fullname")) { | ||||
| 							strcpy(retval->fullname, rowval[i]); | ||||
| 						} else if (!strcmp(fields[i].name, "email")) { | ||||
| 							strcpy(retval->email, rowval[i]); | ||||
| 						} else if (!strcmp(fields[i].name, "pager")) { | ||||
| 							strcpy(retval->pager, rowval[i]); | ||||
| 						} else if (!strcmp(fields[i].name, "options")) { | ||||
| 							strncpy(options, rowval[i], sizeof(options) - 1); | ||||
| 							apply_options(retval, options); | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 				mysql_free_result(result); | ||||
| 				pthread_mutex_unlock(&mysqllock); | ||||
| 				return(retval); | ||||
| 			} else { | ||||
| 				mysql_free_result(result); | ||||
| 				pthread_mutex_unlock(&mysqllock); | ||||
| 				free(retval); | ||||
| 				return(NULL); | ||||
| 			} | ||||
| 			mysql_free_result(result); | ||||
| 			pthread_mutex_unlock(&mysqllock); | ||||
| 			return(retval); | ||||
| 		} else { | ||||
| 			mysql_free_result(result); | ||||
| 			pthread_mutex_unlock(&mysqllock); | ||||
| 			free(retval); | ||||
| 			return(NULL); | ||||
| 		} | ||||
| 		pthread_mutex_unlock(&mysqllock); | ||||
| 		free(retval); | ||||
| 	} | ||||
| 	pthread_mutex_unlock(&mysqllock); | ||||
| 	free(retval); | ||||
| 	return(NULL); | ||||
| } | ||||
|  | ||||
| @@ -946,6 +954,11 @@ static void free_user(struct ast_vm_user *vmu) | ||||
| 		free(vmu); | ||||
| } | ||||
|  | ||||
| static void free_zone(struct vm_zone *z) | ||||
| { | ||||
| 	free(z); | ||||
| } | ||||
|  | ||||
| static int leave_voicemail(struct ast_channel *chan, char *ext, int silent, int busy, int unavail) | ||||
| { | ||||
| 	char comment[256]; | ||||
| @@ -1864,7 +1877,354 @@ static int wait_file(struct ast_channel *chan, struct vm_state *vms, char *file) | ||||
| 	return res; | ||||
| } | ||||
|  | ||||
| static int play_message(struct ast_channel *chan, struct vm_state *vms, int msg) | ||||
| static int play_datetime_format(struct ast_channel *chan, time_t time, struct vm_state *vms, struct vm_zone *zone) | ||||
| { | ||||
| 	int d = 0, offset = 0, sndoffset = 0; | ||||
| 	char sndfile[256], nextmsg[256]; | ||||
| 	struct tm tm; | ||||
| 	char *tzenv, current_tz[256] = "", *qmark; | ||||
|  | ||||
| 	tzenv = getenv("TZ"); | ||||
| 	if (tzenv != NULL) | ||||
| 		strncpy(current_tz, tzenv, sizeof(current_tz) - 1); | ||||
| 	if (zone->timezone && strcmp(current_tz,zone->timezone)) { | ||||
| 		setenv("TZ", zone->timezone, 1); | ||||
| 		tzset(); | ||||
| 		localtime_r(&time, &tm); | ||||
| 		if (tzenv != NULL) | ||||
| 			setenv("TZ", current_tz, 1); | ||||
| 		else | ||||
| 			unsetenv("TZ"); | ||||
| 	} else { | ||||
| 		/* No need to change the timezone */ | ||||
| 		localtime_r(&time, &tm); | ||||
| 	} | ||||
|  | ||||
| 	/* Check for a subexpression */ | ||||
| 	if ((qmark = index(zone->msg_format, '?'))) { | ||||
| 		/* TODO Allow subexpressions - we probably need to implement a parser here. */ | ||||
| 	} | ||||
|  | ||||
| 	for (offset=0 ; zone->msg_format[offset] != '\0' ; offset++) { | ||||
| 		ast_log(LOG_NOTICE, "Parsing %c in %s\n", zone->msg_format[offset], zone->msg_format); | ||||
| 		switch (zone->msg_format[offset]) { | ||||
| 			/* NOTE:  if you add more options here, please try to be consistent with strftime(3) */ | ||||
| 			case '\'': | ||||
| 				/* Literal name of a sound file */ | ||||
| 				sndoffset=0; | ||||
| 				for (sndoffset=0 ; zone->msg_format[++offset] != '\'' ; sndoffset++) | ||||
| 					sndfile[sndoffset] = zone->msg_format[offset]; | ||||
| 				sndfile[sndoffset] = '\0'; | ||||
| 				snprintf(nextmsg,sizeof(nextmsg), AST_SOUNDS "/%s", sndfile); | ||||
| 				d = wait_file(chan,vms,nextmsg); | ||||
| 				break; | ||||
| 			case '$': | ||||
| 				/* Ooooh, variables and/or expressions */ | ||||
| 				{ | ||||
| 					struct vm_zone z; | ||||
| 					memcpy(&z,zone,sizeof(struct vm_zone)); | ||||
| 					pbx_substitute_variables_helper(chan, zone->msg_format + offset, z.msg_format, sizeof(z.msg_format)); | ||||
| 					d = play_datetime_format(chan, time, vms, &z); | ||||
| 					/* Subtract one, so that when the for loop increments, we point at the nil */ | ||||
| 					offset = strlen(zone->msg_format) - 1; | ||||
| 				} | ||||
| 				break; | ||||
| 			case 'A': | ||||
| 			case 'a': | ||||
| 				/* Sunday - Saturday */ | ||||
| 				snprintf(nextmsg,sizeof(nextmsg), DIGITS_DIR "day-%d", tm.tm_wday); | ||||
| 				d = wait_file(chan,vms,nextmsg); | ||||
| 				break; | ||||
| 			case 'B': | ||||
| 			case 'b': | ||||
| 			case 'h': | ||||
| 				/* January - December */ | ||||
| 				snprintf(nextmsg,sizeof(nextmsg), DIGITS_DIR "mon-%d", tm.tm_mon); | ||||
| 				d = wait_file(chan,vms,nextmsg); | ||||
| 				break; | ||||
| 			case 'd': | ||||
| 			case 'e': | ||||
| 				/* First - Thirtyfirst */ | ||||
| 				if ((tm.tm_mday < 21) || (tm.tm_mday == 30)) { | ||||
| 					snprintf(nextmsg,sizeof(nextmsg), DIGITS_DIR "h-%d", tm.tm_mday); | ||||
| 					d = wait_file(chan,vms,nextmsg); | ||||
| 				} else if (tm.tm_mday == 31) { | ||||
| 					/* "Thirty" and "first" */ | ||||
| 					d = wait_file(chan,vms,DIGITS_DIR "30"); | ||||
| 					if (!d) { | ||||
| 						d = wait_file(chan,vms,DIGITS_DIR "h-1"); | ||||
| 					} | ||||
| 				} else { | ||||
| 					/* Between 21 and 29 - two sounds */ | ||||
| 					d = wait_file(chan,vms,DIGITS_DIR "20"); | ||||
| 					if (!d) { | ||||
| 						snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "h-%d", tm.tm_mday - 20); | ||||
| 						d = wait_file(chan,vms,nextmsg); | ||||
| 					} | ||||
| 				} | ||||
| 				break; | ||||
| 			case 'Y': | ||||
| 				/* Year */ | ||||
| 				if (tm.tm_year > 99) { | ||||
| 					d = wait_file(chan,vms,DIGITS_DIR "2"); | ||||
| 					if (!d) { | ||||
| 						d = wait_file(chan,vms,DIGITS_DIR "thousand"); | ||||
| 					} | ||||
| 					if (tm.tm_year > 100) { | ||||
| 						if (!d) { | ||||
| 							/* This works until the end of 2020 */ | ||||
| 							snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", tm.tm_year - 100); | ||||
| 							d = wait_file(chan,vms,nextmsg); | ||||
| 						} | ||||
| 					} | ||||
| 				} else { | ||||
| 					if (tm.tm_year < 1) { | ||||
| 						/* I'm not going to handle 1900 and prior */ | ||||
| 						/* We'll just be silent on the year, instead of bombing out. */ | ||||
| 					} else { | ||||
| 						d = wait_file(chan,vms,DIGITS_DIR "19"); | ||||
| 						if (!d) { | ||||
| 							if (tm.tm_year < 20) { | ||||
| 								/* 1901 - 1920 */ | ||||
| 								snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", tm.tm_year); | ||||
| 								d = wait_file(chan,vms,nextmsg); | ||||
| 							} else { | ||||
| 								/* 1921 - 1999 */ | ||||
| 								int ten, one; | ||||
| 								ten = tm.tm_year / 10; | ||||
| 								one = tm.tm_year % 10; | ||||
| 								snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", ten * 10); | ||||
| 								d = wait_file(chan,vms,nextmsg); | ||||
| 								if (!d) { | ||||
| 									if (one != 0) { | ||||
| 										snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", one); | ||||
| 										d = wait_file(chan,vms,nextmsg); | ||||
| 									} | ||||
| 								} | ||||
| 							} | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 				break; | ||||
| 			case 'I': | ||||
| 			case 'l': | ||||
| 				/* 12-Hour */ | ||||
| 				if (tm.tm_hour == 0) | ||||
| 					snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "12"); | ||||
| 				else if (tm.tm_hour > 12) | ||||
| 					snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", tm.tm_hour - 12); | ||||
| 				else | ||||
| 					snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", tm.tm_hour); | ||||
| 				d = wait_file(chan,vms,nextmsg); | ||||
| 				break; | ||||
| 			case 'H': | ||||
| 			case 'k': | ||||
| 				/* 24-Hour */ | ||||
| 				if (zone->msg_format[offset] == 'H') { | ||||
| 					/* e.g. oh-eight */ | ||||
| 					if (tm.tm_hour < 10) { | ||||
| 						d = wait_file(chan,vms,DIGITS_DIR "oh"); | ||||
| 					} | ||||
| 				} else { | ||||
| 					/* e.g. eight */ | ||||
| 					if (tm.tm_hour == 0) { | ||||
| 						d = wait_file(chan,vms,DIGITS_DIR "oh"); | ||||
| 					} | ||||
| 				} | ||||
| 				if (!d) { | ||||
| 					if (tm.tm_hour != 0) { | ||||
| 						snprintf(nextmsg,sizeof(nextmsg), AST_SOUNDS "/digits/%d", tm.tm_hour); | ||||
| 						d = wait_file(chan,vms,nextmsg); | ||||
| 					} | ||||
| 				} | ||||
| 				break; | ||||
| 			case 'M': | ||||
| 				/* Minute */ | ||||
| 				if (tm.tm_min == 0) { | ||||
| 					d = wait_file(chan,vms,DIGITS_DIR "oclock"); | ||||
| 				} else if (tm.tm_min < 10) { | ||||
| 					d = wait_file(chan,vms,DIGITS_DIR "oh"); | ||||
| 					if (!d) { | ||||
| 						snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", tm.tm_min); | ||||
| 						d = wait_file(chan,vms,nextmsg); | ||||
| 					} | ||||
| 				} else if ((tm.tm_min < 21) || (tm.tm_min % 10 == 0)) { | ||||
| 					snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", tm.tm_min); | ||||
| 					d = wait_file(chan,vms,nextmsg); | ||||
| 				} else { | ||||
| 					int ten, one; | ||||
| 					ten = (tm.tm_min / 10) * 10; | ||||
| 					one = (tm.tm_min % 10); | ||||
| 					snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", ten); | ||||
| 					d = wait_file(chan,vms,nextmsg); | ||||
| 					if (!d) { | ||||
| 						/* Fifty, not fifty-zero */ | ||||
| 						if (one != 0) { | ||||
| 							snprintf(nextmsg,sizeof(nextmsg),DIGITS_DIR "%d", one); | ||||
| 							d = wait_file(chan,vms,nextmsg); | ||||
| 						} | ||||
| 					} | ||||
| 				} | ||||
| 				break; | ||||
| 			case 'P': | ||||
| 			case 'p': | ||||
| 				/* AM/PM */ | ||||
| 				if ((tm.tm_hour == 0) || (tm.tm_hour > 12)) | ||||
| 					snprintf(nextmsg,sizeof(nextmsg), DIGITS_DIR "p-m"); | ||||
| 				else | ||||
| 					snprintf(nextmsg,sizeof(nextmsg), DIGITS_DIR "a-m"); | ||||
| 				d = wait_file(chan,vms,nextmsg); | ||||
| 				break; | ||||
| 			case 'Q': | ||||
| 				/* Shorthand for "Today", "Yesterday", or ABdY */ | ||||
| 				{ | ||||
| 					struct timeval now; | ||||
| 					struct tm tmnow; | ||||
| 					time_t beg_today; | ||||
|  | ||||
| 					gettimeofday(&now,NULL); | ||||
| 					localtime_r(&now.tv_sec,&tmnow); | ||||
| 					tmnow.tm_hour = 0; | ||||
| 					tmnow.tm_min = 0; | ||||
| 					tmnow.tm_sec = 0; | ||||
| 					beg_today = mktime(&tmnow); | ||||
| 					if (beg_today < time) { | ||||
| 						/* Today */ | ||||
| 						d = wait_file(chan,vms,DIGITS_DIR "today"); | ||||
| 					} else if (beg_today - 86400 < time) { | ||||
| 						/* Yesterday */ | ||||
| 						d = wait_file(chan,vms,DIGITS_DIR "yesterday"); | ||||
| 					} else { | ||||
| 						struct vm_zone z; | ||||
| 						memcpy(&z, zone, sizeof(struct vm_zone)); | ||||
| 						strcpy(z.msg_format, "ABdY"); | ||||
| 						d = play_datetime_format(chan, time, vms, &z); | ||||
| 					} | ||||
| 				} | ||||
| 				break; | ||||
| 			case 'q': | ||||
| 				/* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */ | ||||
| 				{ | ||||
| 					struct timeval now; | ||||
| 					struct tm tmnow; | ||||
| 					time_t beg_today; | ||||
|  | ||||
| 					gettimeofday(&now,NULL); | ||||
| 					localtime_r(&now.tv_sec,&tmnow); | ||||
| 					tmnow.tm_hour = 0; | ||||
| 					tmnow.tm_min = 0; | ||||
| 					tmnow.tm_sec = 0; | ||||
| 					beg_today = mktime(&tmnow); | ||||
| 					if (beg_today < time) { | ||||
| 						/* Today */ | ||||
| 					} else if (beg_today - 86400 < time) { | ||||
| 						/* Yesterday */ | ||||
| 						d = wait_file(chan,vms,DIGITS_DIR "yesterday"); | ||||
| 					} else if (beg_today - 86400 * 6 < time) { | ||||
| 						/* Within the last week */ | ||||
| 						struct vm_zone z; | ||||
| 						memcpy(&z, zone, sizeof(struct vm_zone)); | ||||
| 						strcpy(z.msg_format, "A"); | ||||
| 						d = play_datetime_format(chan, time, vms, &z); | ||||
| 					} else { | ||||
| 						struct vm_zone z; | ||||
| 						memcpy(&z, zone, sizeof(struct vm_zone)); | ||||
| 						strcpy(z.msg_format, "ABdY"); | ||||
| 						d = play_datetime_format(chan, time, vms, &z); | ||||
| 					} | ||||
| 				} | ||||
| 				break; | ||||
| 			case 'R': | ||||
| 				{ | ||||
| 					struct vm_zone z; | ||||
| 					memcpy(&z, zone, sizeof(struct vm_zone)); | ||||
| 					strcpy(z.msg_format, "HM"); | ||||
| 					d = play_datetime_format(chan, time, vms, &z); | ||||
| 				} | ||||
| 				break; | ||||
| 			case ' ': | ||||
| 			case '	': | ||||
| 				/* Just ignore spaces and tabs */ | ||||
| 				break; | ||||
| 			default: | ||||
| 				/* Unknown character */ | ||||
| 				ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c\n", zone->msg_format, zone->msg_format[offset]); | ||||
| 		} | ||||
| 		/* Jump out on DTMF */ | ||||
| 		if (d) { | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	return d; | ||||
| } | ||||
|  | ||||
| static int play_message_datetime(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms) | ||||
| { | ||||
| 	int res = 0; | ||||
| 	char filename[256], *origtime, temp[256]; | ||||
| 	struct vm_zone *the_zone = NULL; | ||||
| 	struct ast_config *msg_cfg; | ||||
| 	time_t t; | ||||
| 	struct timeval tv_now; | ||||
| 	struct tm time_now, time_then; | ||||
|  | ||||
| 	make_file(vms->fn2, sizeof(vms->fn2), vms->curdir, vms->curmsg);  | ||||
| 	snprintf(filename,sizeof(filename), "%s.txt", vms->fn2); | ||||
| 	msg_cfg = ast_load(filename); | ||||
| 	if (!msg_cfg) { | ||||
| 		ast_log(LOG_WARNING, "No message attribute file?!! (%s)\n", filename); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if (!(origtime = ast_variable_retrieve(msg_cfg, "message", "origtime"))) | ||||
| 		return 0; | ||||
| 	if (sscanf(origtime,"%ld",&t) < 1) { | ||||
| 		ast_log(LOG_WARNING, "Couldn't find origtime in %s\n", filename); | ||||
| 		return 0; | ||||
| 	} | ||||
| 	ast_destroy(msg_cfg); | ||||
|  | ||||
| 	/* Does this user have a timezone specified? */ | ||||
| 	if (strlen(vmu->zonetag)) { | ||||
| 		/* Find the zone in the list */ | ||||
| 		struct vm_zone *z; | ||||
| 		z = zones; | ||||
| 		while (z) { | ||||
| 			if (!strcmp(z->name, vmu->zonetag)) { | ||||
| 				the_zone = z; | ||||
| 				break; | ||||
| 			} | ||||
| 			z = z->next; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* If no zone, use a default */ | ||||
| 	if (!the_zone) { | ||||
| 		the_zone = alloca(sizeof(struct vm_zone)); | ||||
| 		memset(the_zone,0,sizeof(struct vm_zone)); | ||||
| 		strncpy(the_zone->msg_format, "'vm-received' q 'digits/at' IMp", sizeof(the_zone->msg_format) - 1); | ||||
| 	} | ||||
|  | ||||
| 	/* Set the DIFF_* variables */ | ||||
| 	localtime_r(&t, &time_now); | ||||
| 	gettimeofday(&tv_now,NULL); | ||||
| 	localtime_r(&tv_now.tv_sec,&time_then); | ||||
|  | ||||
| 	/* Day difference */ | ||||
| 	if (time_now.tm_year == time_then.tm_year) | ||||
| 		sprintf(temp,"%d",time_now.tm_yday); | ||||
| 	else | ||||
| 		sprintf(temp,"%d",(time_now.tm_year - time_then.tm_year) * 365 + (time_now.tm_yday - time_then.tm_yday)); | ||||
| 	pbx_builtin_setvar_helper(chan, "DIFF_DAY", temp); | ||||
|  | ||||
| 	/* Can't think of how other diffs might be helpful, but I'm sure somebody will think of something. */ | ||||
|  | ||||
| 	res = play_datetime_format(chan, t, vms, the_zone); | ||||
| 	pbx_builtin_setvar_helper(chan, "DIFF_DAY", NULL); | ||||
| 	return res; | ||||
| } | ||||
|  | ||||
| static int play_message(struct ast_channel *chan, struct ast_vm_user *vmu, struct vm_state *vms, int msg) | ||||
| { | ||||
| 	int res = 0; | ||||
| 	vms->starting = 0;  | ||||
| @@ -1881,7 +2241,10 @@ static int play_message(struct ast_channel *chan, struct vm_state *vms, int msg) | ||||
| 				res = ast_say_number(chan, msg + 1, AST_DIGIT_ANY, chan->language); | ||||
| 		} | ||||
| 	} | ||||
| 	 | ||||
|  | ||||
| 	if (!res) | ||||
| 		res = play_message_datetime(chan,vmu,vms); | ||||
|  | ||||
| 	if (!res) { | ||||
| 		make_file(vms->fn, sizeof(vms->fn), vms->curdir, msg); | ||||
| 		vms->heard[msg] = 1; | ||||
| @@ -2255,7 +2618,7 @@ static int vm_execmain(struct ast_channel *chan, void *data) | ||||
| 				/* Fall through */ | ||||
| 			case '5': | ||||
| 				if (vms.lastmsg > -1) { | ||||
| 					cmd = play_message(chan, &vms, vms.curmsg); | ||||
| 					cmd = play_message(chan, vmu, &vms, vms.curmsg); | ||||
| 				} else { | ||||
| 					cmd = play_and_wait(chan, "vm-youhave"); | ||||
| 					if (!cmd)  | ||||
| @@ -2291,7 +2654,7 @@ static int vm_execmain(struct ast_channel *chan, void *data) | ||||
| 			case '4': | ||||
| 				if (vms.curmsg) { | ||||
| 					vms.curmsg--; | ||||
| 					cmd = play_message(chan, &vms, vms.curmsg); | ||||
| 					cmd = play_message(chan, vmu, &vms, vms.curmsg); | ||||
| 				} else { | ||||
| 					cmd = play_and_wait(chan, "vm-nomore"); | ||||
| 				} | ||||
| @@ -2299,7 +2662,7 @@ static int vm_execmain(struct ast_channel *chan, void *data) | ||||
| 			case '6': | ||||
| 				if (vms.curmsg < vms.lastmsg) { | ||||
| 					vms.curmsg++; | ||||
| 					cmd = play_message(chan, &vms, vms.curmsg); | ||||
| 					cmd = play_message(chan, vmu, &vms, vms.curmsg); | ||||
| 				} else { | ||||
| 					cmd = play_and_wait(chan, "vm-nomore"); | ||||
| 				} | ||||
| @@ -2471,6 +2834,7 @@ static int append_mailbox(char *context, char *mbox, char *data) | ||||
| static int load_config(void) | ||||
| { | ||||
| 	struct ast_vm_user *cur, *l; | ||||
| 	struct vm_zone *zcur, *zl; | ||||
| 	struct ast_config *cfg; | ||||
| 	char *cat; | ||||
| 	struct ast_variable *var; | ||||
| @@ -2490,6 +2854,14 @@ static int load_config(void) | ||||
| 		cur = cur->next; | ||||
| 		free_user(l); | ||||
| 	} | ||||
| 	zcur = zones; | ||||
| 	while(zcur) { | ||||
| 		zl = zcur; | ||||
| 		zcur = zcur->next; | ||||
| 		free_zone(zl); | ||||
| 	} | ||||
| 	zones = NULL; | ||||
| 	zonesl = NULL; | ||||
| 	users = NULL; | ||||
| 	usersl = NULL; | ||||
| 	if (cfg) { | ||||
| @@ -2568,20 +2940,55 @@ static int load_config(void) | ||||
| 		} else { | ||||
| 			strcpy(dbname, s); | ||||
| 		} | ||||
| #else | ||||
| #endif | ||||
| 		cat = ast_category_browse(cfg, NULL); | ||||
| 		while(cat) { | ||||
| 			if (strcasecmp(cat, "general")) { | ||||
| 				/* Process mailboxes in this context */ | ||||
| 				var = ast_variable_browse(cfg, cat); | ||||
| 				while(var) { | ||||
| 					append_mailbox(cat, var->name, var->value); | ||||
| 					var = var->next; | ||||
| 				if (strcasecmp(cat, "zonemessages")) { | ||||
| #ifndef USEMYSQLVM | ||||
| 					/* Process mailboxes in this context */ | ||||
| 					while(var) { | ||||
| 						append_mailbox(cat, var->name, var->value); | ||||
| 						var = var->next; | ||||
| 					} | ||||
| #endif | ||||
| 				} else { | ||||
| 					/* Timezones in this context */ | ||||
| 					while(var) { | ||||
| 						struct vm_zone *z; | ||||
| 						z = malloc(sizeof(struct vm_zone)); | ||||
| 						if (z != NULL) { | ||||
| 							char *msg_format, *timezone; | ||||
| 							msg_format = strdupa(var->value); | ||||
| 							if (msg_format != NULL) { | ||||
| 								timezone = strsep(&msg_format, "|"); | ||||
| 								strncpy(z->name, var->name, sizeof(z->name) - 1); | ||||
| 								strncpy(z->timezone, timezone, sizeof(z->timezone) - 1); | ||||
| 								strncpy(z->msg_format, msg_format, sizeof(z->msg_format) - 1); | ||||
| 								z->next = NULL; | ||||
| 								if (zones) { | ||||
| 									zonesl->next = z; | ||||
| 									zonesl = z; | ||||
| 								} else { | ||||
| 									zones = z; | ||||
| 									zonesl = z; | ||||
| 								} | ||||
| 							} else { | ||||
| 								ast_log(LOG_WARNING, "Out of memory while reading voicemail config\n"); | ||||
| 								free(z); | ||||
| 								return -1; | ||||
| 							} | ||||
| 						} else { | ||||
| 							ast_log(LOG_WARNING, "Out of memory while reading voicemail config\n"); | ||||
| 							return -1; | ||||
| 						} | ||||
| 						var = var->next; | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			cat = ast_category_browse(cfg, cat); | ||||
| 		} | ||||
| #endif | ||||
| 		memset(fromstring,0,sizeof(fromstring)); | ||||
| 		memset(emailtitle,0,sizeof(emailtitle)); | ||||
| 		if (emailbody) { | ||||
|   | ||||
| @@ -37,7 +37,7 @@ maxlogins=3 | ||||
| ; | ||||
| [default] | ||||
| 1234 => 4242,Example Mailbox,root@localhost | ||||
| ;4200 => 9855,Mark Spencer,markster@linux-support.net,mypager@digium.com,attach=no|serveremail=myaddy@digium.com | ||||
| ;4200 => 9855,Mark Spencer,markster@linux-support.net,mypager@digium.com,attach=no|serveremail=myaddy@digium.com|tz=central | ||||
| ;4300 => 3456,Ben Rigas,ben@american-computer.net | ||||
| ;4310 => 5432,Sales,sales@marko.net | ||||
| ;4069 => 6522,Matt Brooks,matt@marko.net | ||||
| @@ -51,3 +51,13 @@ maxlogins=3 | ||||
| [other] | ||||
| 1234 => 5678,Company2 User,root@localhost | ||||
|  | ||||
| ; | ||||
| ; Users may be located in different timezones.  Set the message and the | ||||
| ; timezone each user hears here.  Set the user into one of these zones with | ||||
| ; the tz= attribute in the options field of the mailbox. | ||||
| ; | ||||
| [zonemessages] | ||||
| eastern=America/NewYork|'vm-received' Q 'digits/at' IMp | ||||
| central=America/Chicago|'vm-received' Q 'digits/at' IMp | ||||
| central24=America/Chicago|'vm-received' 'digits/at' H 'digits/hundred' M | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user