diff --git a/pbx/pbx_config.c b/pbx/pbx_config.c
index d882863c51df51ab0846c03fa889690d6747d5f3..2d47c4db183d634a6ee0e375c076a5e1e8de3ff1 100755
--- a/pbx/pbx_config.c
+++ b/pbx/pbx_config.c
@@ -462,7 +462,7 @@ static int fix_complete_args(char *line, char **word, int *pos)
 static char *complete_context_remove_extension(char *line, char *word, int pos,
 	int state)
 {
-	char *ret;
+	char *ret = NULL;
 	int which = 0;
 
 #ifdef BROKEN_READLINE
diff --git a/say.c b/say.c
index 5a318e8c014b1c124d4aa666116cb1a0bd6aac10..1a88efeb0a3df975016d8af22aa0cbb215e65a89 100755
--- a/say.c
+++ b/say.c
@@ -414,13 +414,23 @@ int ast_say_digits_full(struct ast_channel *chan, int num, char *ints, char *lan
  For Portuguese, we're using m & f options to saynumber() to indicate if the gender is masculine or feminine.
  For Danish, we're using c & n options to saynumber() to indicate if the gender is commune or neutrum.
  This still needs to be implemented for French, Spanish & German.
+ 
+ Date/Time functions currently have less languages supported than saynumber().
 
  Note that in future, we need to move to a model where we can differentiate further - e.g. between en_US & en_UK
 
  See contrib/i18n.testsuite.conf for some examples of the different syntaxes
 
- OEJ 2004-04-25
- FPB 2004-05-01
+ Portuguese sound files needed for Time/Date functions:
+ pt-ah
+ pt-ao
+ pt-de
+ pt-e
+ pt-ora
+ pt-meianoite
+ pt-meiodia
+ pt-sss
+
 */
 
 static int ast_say_number_full_en(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd);
@@ -431,6 +441,30 @@ static int ast_say_number_full_fr(struct ast_channel *chan, int num, char *ints,
 static int ast_say_number_full_it(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd);
 static int ast_say_number_full_nl(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd);
 static int ast_say_number_full_pt(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd);
+static int ast_say_date_en(struct ast_channel *chan, time_t t, char *ints, char *lang);
+static int ast_say_date_nl(struct ast_channel *chan, time_t t, char *ints, char *lang);
+static int ast_say_date_pt(struct ast_channel *chan, time_t t, char *ints, char *lang);
+static int ast_say_date_with_format_en(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone);
+static int ast_say_date_with_format_nl(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone);
+static int ast_say_date_with_format_pt(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone);
+static int ast_say_time_en(struct ast_channel *chan, time_t t, char *ints, char *lang);
+static int ast_say_time_nl(struct ast_channel *chan, time_t t, char *ints, char *lang);
+static int ast_say_time_pt(struct ast_channel *chan, time_t t, char *ints, char *lang);
+static int ast_say_datetime_en(struct ast_channel *chan, time_t t, char *ints, char *lang);
+static int ast_say_datetime_nl(struct ast_channel *chan, time_t t, char *ints, char *lang);
+static int ast_say_datetime_pt(struct ast_channel *chan, time_t t, char *ints, char *lang);
+static int ast_say_datetime_from_now_en(struct ast_channel *chan, time_t t, char *ints, char *lang);
+static int ast_say_datetime_from_now_pt(struct ast_channel *chan, time_t t, char *ints, char *lang);
+
+static int wait_file(struct ast_channel *chan, char *ints, char *file, char *lang) 
+{
+	int res;
+	if ((res = ast_streamfile(chan, file, lang)))
+		ast_log(LOG_WARNING, "Unable to play message %s\n", file);
+	if (!res)
+		res = ast_waitstream(chan, ints);
+	return res;
+}
 
 /*--- ast_say_number_full: call language-specific functions */
 /* Called from AGI */
@@ -501,12 +535,10 @@ static int ast_say_number_full_en(struct ast_channel *chan, int num, char *ints,
 			if (playh) {
 				snprintf(fn, sizeof(fn), "digits/hundred");
 				playh = 0;
-			} else
-			if (num < 20) {
+			} else	if (num < 20) {
 				snprintf(fn, sizeof(fn), "digits/%d", num);
 				num = 0;
-			} else
-			if (num < 100) {
+			} else	if (num < 100) {
 				snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
 				num -= ((num / 10) * 10);
 			} else {
@@ -535,14 +567,14 @@ static int ast_say_number_full_en(struct ast_channel *chan, int num, char *ints,
 					}
 				}
 			}
-			 if (!res) {
-                                if(!ast_streamfile(chan, fn, language)) {
-                                    if (audiofd && ctrlfd)
-                                        res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
-                                    else
-                                         res = ast_waitstream(chan, ints);
-                                }
-                                ast_stopstream(chan);
+			if (!res) {
+				if(!ast_streamfile(chan, fn, language)) {
+					if (audiofd && ctrlfd)
+						res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
+					else
+						res = ast_waitstream(chan, ints);
+				}
+				ast_stopstream(chan);
 
                         }
 			
@@ -550,87 +582,6 @@ static int ast_say_number_full_en(struct ast_channel *chan, int num, char *ints,
 	return res;
 }
 
-
-/*--- ast_say_number_full_fr: French syntax */
-static int ast_say_number_full_fr(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd)
-{
-	int res = 0;
-	int playh = 0;
-	int playa = 0;	/* For french */
-	char fn[256] = "";
-	if (!num) 
-		return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
-           while(!res && (num || playh || playa)) {
-                       if (playh) {
-                               snprintf(fn, sizeof(fn), "digits/hundred");
-                               playh = 0;
-                       } else
-                       if (playa) {
-                               snprintf(fn, sizeof(fn), "digits/et");
-                               playa = 0;
-                       } else
-                       if (num < 21) {
-                               snprintf(fn, sizeof(fn), "digits/%d", num);
-                               num = 0;
-                       } else
-                         if (num < 70) {
-                                 snprintf(fn, sizeof(fn), "digits/%d", (num/10)*10);
-                                 if ((num % 10) == 1) playa++;
-                                 num = num % 10;
-                         } else
-                         if (num < 80) {
-                                 snprintf(fn, sizeof(fn), "digits/60");
-                                 if ((num % 10) == 1) playa++;
-                                 num = num - 60;
-                         } else
-                         if (num < 100) {
-                                 snprintf(fn, sizeof(fn), "digits/80");
-                                 num = num - 80;
-                         } else
-                         if (num < 200) {
-                                 snprintf(fn, sizeof(fn), "digits/hundred");
-                                 num = num - 100;
-                         } else
-                         if (num < 1000) {
-                                 snprintf(fn, sizeof(fn), "digits/%d", (num/100));
-                                 playh++;
-                                 num = num % 100;
-                         } else
-                         if (num < 2000) {
-                                 snprintf(fn, sizeof(fn), "digits/thousand");
-                                 num = num - 1000;
-                         } else
-                         if (num < 1000000) {
-                                 res = ast_say_number_full_fr(chan, num / 1000, ints, language, audiofd, ctrlfd);
-                                 if (res) return res;
-                                 snprintf(fn, sizeof(fn), "digits/thousand");
-                                 num = num % 1000;
-                         } else
-			 if (num < 1000000000) {
-                                 res = ast_say_number_full_fr(chan, num / 1000000, ints, language, audiofd, ctrlfd);
-                                 if (res) return res;
-                                 snprintf(fn, sizeof(fn), "digits/million");
-                                 num = num % 1000000;
-                         } else {
-                                 ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
-                                 res = -1;
-                         }
- 			if (!res) {
-                                if(!ast_streamfile(chan, fn, language)) {
-                                    if (audiofd && ctrlfd)
-                                        res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
-                                    else
-                                         res = ast_waitstream(chan, ints);
-                                }
-                                ast_stopstream(chan);
-
-                        }
-
-
-	}
-	return res;
-}
-
 /*--- ast_say_number_full_da: Danish syntax */
 /* New files:
  In addition to English, the following sounds are required: "1N", "millions", "and" and "1-and" through "9-and" 
@@ -648,92 +599,86 @@ static int ast_say_number_full_da(struct ast_channel *chan, int num, char *ints,
 	if (options && !strncasecmp(options, "n",1)) cn = -1;
 
 	while(!res && (num || playh || playa )) {
-               /* The grammar for Danish numbers is the same as for English except
-                * for the following:
+		/* The grammar for Danish numbers is the same as for English except
+		* for the following:
 		* - 1 exists in both commune ("en", file "1N") and neutrum ("et", file "1")
-                * - numbers 20 through 99 are said in reverse order, i.e. 21 is
-                *   "one-and twenty" and 68 is "eight-and sixty".
-                * - "million" is different in singular and plural form
-                * - numbers > 1000 with zero as the third digit from last have an
-                *   "and" before the last two digits, i.e. 2034 is "two thousand and
-                *   four-and thirty" and 1000012 is "one million and twelve".
-                */
-                       if (playh) {
-                               snprintf(fn, sizeof(fn), "digits/hundred");
-                               playh = 0;
-                       } else
-                       if (playa) {
-                               snprintf(fn, sizeof(fn), "digits/and");
-                               playa = 0;
-                       } else
-		       if (num == 1 && cn == -1) {
-			 	snprintf(fn, sizeof(fn), "digits/1N");
+		* - numbers 20 through 99 are said in reverse order, i.e. 21 is
+		*   "one-and twenty" and 68 is "eight-and sixty".
+		* - "million" is different in singular and plural form
+		* - numbers > 1000 with zero as the third digit from last have an
+		*   "and" before the last two digits, i.e. 2034 is "two thousand and
+		*   four-and thirty" and 1000012 is "one million and twelve".
+		*/
+		if (playh) {
+			snprintf(fn, sizeof(fn), "digits/hundred");
+			playh = 0;
+		} else if (playa) {
+			snprintf(fn, sizeof(fn), "digits/and");
+			playa = 0;
+		} else if (num == 1 && cn == -1) {
+			snprintf(fn, sizeof(fn), "digits/1N");
+			num = 0;
+		} else if (num < 20) {
+			snprintf(fn, sizeof(fn), "digits/%d", num);
+			num = 0;
+		} else if (num < 100) {
+			int ones = num % 10;
+			if (ones) {
+				snprintf(fn, sizeof(fn), "digits/%d-and", ones);
+				num -= ones;
+			} else {
+				snprintf(fn, sizeof(fn), "digits/%d", num);
 				num = 0;
-                       } else
-                       if (num < 20) {
-                               snprintf(fn, sizeof(fn), "digits/%d", num);
-                               num = 0;
-                       } else
-                       if (num < 100) {
-                               int ones = num % 10;
-                               if (ones) {
-                                       snprintf(fn, sizeof(fn), "digits/%d-and", ones);
-                                       num -= ones;
-                               } else {
-                                       snprintf(fn, sizeof(fn), "digits/%d", num);
-                                       num = 0;
-                               }
-                       } else {
-                               if (num < 1000) {
-					int hundreds = num / 100;
-                                         if (hundreds == 1)
-                                                 snprintf(fn, sizeof(fn), "digits/1N");
-                                         else
-                                                 snprintf(fn, sizeof(fn), "digits/%d", (num / 100));
-
-                                       playh++;
-				       num -= 100 * hundreds;
-                                       if (num)
-                                                 playa++;
-
-                               } else {
-                                       if (num < 1000000) {
-                                               res = ast_say_number_full_da(chan, num / 1000, ints, language, "n", audiofd, ctrlfd);
-                                               if (res)
-                                                       return res;
-                                               num = num % 1000;
-                                               snprintf(fn, sizeof(fn), "digits/thousand");
-                                       } else {
-                                               if (num < 1000000000) {
-                                                       int millions = num / 1000000;
-                                                       res = ast_say_number_full_da(chan, millions, ints, language, "c", audiofd, ctrlfd);
-                                                       if (res)
-                                                               return res;
-                                                       if (millions == 1)
-                                                               snprintf(fn, sizeof(fn), "digits/million");
-                                                       else
-                                                              snprintf(fn, sizeof(fn), "digits/millions");
-                                                       num = num % 1000000;
+			}
+		} else {
+			if (num < 1000) {
+				int hundreds = num / 100;
+				if (hundreds == 1)
+					snprintf(fn, sizeof(fn), "digits/1N");
+				else
+					snprintf(fn, sizeof(fn), "digits/%d", (num / 100));
+
+				playh++;
+				num -= 100 * hundreds;
+				if (num)
+					playa++;
+
+			} else {
+				if (num < 1000000) {
+					res = ast_say_number_full_da(chan, num / 1000, ints, language, "n", audiofd, ctrlfd);
+					if (res)
+						return res;
+					num = num % 1000;
+					snprintf(fn, sizeof(fn), "digits/thousand");
+				} else {
+					if (num < 1000000000) {
+						int millions = num / 1000000;
+						res = ast_say_number_full_da(chan, millions, ints, language, "c", audiofd, ctrlfd);
+						if (res)
+							return res;
+						if (millions == 1)
+							snprintf(fn, sizeof(fn), "digits/million");
+						else
+							snprintf(fn, sizeof(fn), "digits/millions");
+						num = num % 1000000;
 					} else {
-                                                       ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
-                                                       res = -1;
-                                               }
-                                       }
-                                       if (num && num < 100)
-                                               playa++;
-                               }
-                       }
-			if (!res) {
-                                if(!ast_streamfile(chan, fn, language)) {
-                                    if (audiofd && ctrlfd) 
-                                        res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
-                                    else  
-                                         res = ast_waitstream(chan, ints);
+						ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
+						res = -1;
+					}
 				}
-				ast_stopstream(chan);
-	
+				if (num && num < 100)
+					playa++;
 			}
-			
+		}
+		if (!res) {
+			if(!ast_streamfile(chan, fn, language)) {
+				if (audiofd && ctrlfd) 
+					res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
+				else  
+					res = ast_waitstream(chan, ints);
+			}
+			ast_stopstream(chan);
+		}
 	}
 	return res;
 }
@@ -752,217 +697,252 @@ static int ast_say_number_full_de(struct ast_channel *chan, int num, char *ints,
 		return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
 
 	while(!res && (num || playh || playa )) {
-               /* The grammar for German numbers is the same as for English except
-                * for the following:
-                * - numbers 20 through 99 are said in reverse order, i.e. 21 is
-                *   "one-and twenty" and 68 is "eight-and sixty".
-                * - "million" is different in singular and plural form
-                * - numbers > 1000 with zero as the third digit from last have an
-                *   "and" before the last two digits, i.e. 2034 is "two thousand and
-                *   four-and thirty" and 1000012 is "one million and twelve".
-                */
-                       if (playh) {
-                               snprintf(fn, sizeof(fn), "digits/hundred");
-                               playh = 0;
-                       } else
-                       if (playa) {
-                               snprintf(fn, sizeof(fn), "digits/and");
-                               playa = 0;
-                       } else
-                       if (num < 20) {
-                               snprintf(fn, sizeof(fn), "digits/%d", num);
-                               num = 0;
-                       } else
-                       if (num < 100) {
-                               int ones = num % 10;
-                               if (ones) {
-                                       snprintf(fn, sizeof(fn), "digits/%d-and", ones);
-                                       num -= ones;
-                               } else {
-                                       snprintf(fn, sizeof(fn), "digits/%d", num);
-                                       num = 0;
-                               }
-                       } else {
-                               if (num < 1000) {
-					int hundreds = num / 100;
-                                         if (hundreds == 1)
-                                                 snprintf(fn, sizeof(fn), "digits/1N");
-                                         else
-                                                 snprintf(fn, sizeof(fn), "digits/%d", (num / 100));
-
-                                       playh++;
-				       num -= 100 * hundreds;
-                                       if (num)
-                                                 playa++;
-
-                               } else {
-                                       if (num < 1000000) {
-                                               res = ast_say_number_full_da(chan, num / 1000, ints, language, "n", audiofd, ctrlfd);
-                                               if (res)
-                                                       return res;
-                                               num = num % 1000;
-                                               snprintf(fn, sizeof(fn), "digits/thousand");
-                                       } else {
-                                               if (num < 1000000000) {
-                                                       int millions = num / 1000000;
-                                                       res = ast_say_number_full_da(chan, millions, ints, language, "c", audiofd, ctrlfd);
-                                                       if (res)
-                                                               return res;
-                                                       if (millions == 1)
-                                                               snprintf(fn, sizeof(fn), "digits/million");
-                                                       else
-                                                              snprintf(fn, sizeof(fn), "digits/millions");
-                                                       num = num % 1000000;
+		/* The grammar for German numbers is the same as for English except
+		* for the following:
+		* - numbers 20 through 99 are said in reverse order, i.e. 21 is
+		*   "one-and twenty" and 68 is "eight-and sixty".
+		* - "million" is different in singular and plural form
+		* - numbers > 1000 with zero as the third digit from last have an
+		*   "and" before the last two digits, i.e. 2034 is "two thousand and
+		*   four-and thirty" and 1000012 is "one million and twelve".
+		*/
+		if (playh) {
+			snprintf(fn, sizeof(fn), "digits/hundred");
+			playh = 0;
+		} else if (playa) {
+			snprintf(fn, sizeof(fn), "digits/and");
+			playa = 0;
+		} else if (num < 20) {
+			snprintf(fn, sizeof(fn), "digits/%d", num);
+			num = 0;
+		} else if (num < 100) {
+			int ones = num % 10;
+			if (ones) {
+				snprintf(fn, sizeof(fn), "digits/%d-and", ones);
+				num -= ones;
+			} else {
+				snprintf(fn, sizeof(fn), "digits/%d", num);
+				num = 0;
+			}
+		} else {
+			if (num < 1000) {
+				int hundreds = num / 100;
+				if (hundreds == 1)
+					snprintf(fn, sizeof(fn), "digits/1N");
+				else
+					snprintf(fn, sizeof(fn), "digits/%d", (num / 100));
+				playh++;
+				num -= 100 * hundreds;
+				if (num)
+					playa++;
+			} else {
+				if (num < 1000000) {
+					res = ast_say_number_full_da(chan, num / 1000, ints, language, "n", audiofd, ctrlfd);
+					if (res)
+						return res;
+					num = num % 1000;
+					snprintf(fn, sizeof(fn), "digits/thousand");
+				} else {
+					if (num < 1000000000) {
+						int millions = num / 1000000;
+						res = ast_say_number_full_da(chan, millions, ints, language, "c", audiofd, ctrlfd);
+						if (res)
+							return res;
+						if (millions == 1)
+							snprintf(fn, sizeof(fn), "digits/million");
+						else
+							snprintf(fn, sizeof(fn), "digits/millions");
+						num = num % 1000000;
 					} else {
-                                                       ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
-                                                       res = -1;
-                                               }
-                                       }
-                                       if (num && num < 100)
-                                               playa++;
-                               }
-                       }
-			if (!res) {
-                                if(!ast_streamfile(chan, fn, language)) {
-                                    if (audiofd && ctrlfd) 
-                                        res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
-                                    else  
-                                         res = ast_waitstream(chan, ints);
+						ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
+						res = -1;
+					}
 				}
-				ast_stopstream(chan);
-	
+				if (num && num < 100)
+					playa++;
 			}
-			
+		}
+		if (!res) {
+			if(!ast_streamfile(chan, fn, language)) {
+				if (audiofd && ctrlfd) 
+					res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
+				else  
+					res = ast_waitstream(chan, ints);
+			}
+			ast_stopstream(chan);
+		}
 	}
 	return res;
 }
 
-/*------------ Portuguese ----------------------*/
-/* ast_say_number_full_pt: Portuguese syntax */
-/* 	Extra sounds needed: */
-/* 	For feminin all sound files end with F */
-/*	100E for 100+ something */
-/*	1000000S for plural */
-/*	pt-e for 'and' */
-static int ast_say_number_full_pt(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd)
+/*--- ast_say_number_full_es: spanish syntax */
+/* New files:
+ Requires a few new audios:
+   21.gsm thru 29.gsm, cien.gsm, mil.gsm, millon.gsm, millones.gsm, 100.gsm, 200.gsm, 300.gsm, 400.gsm, 500.gsm, 600.gsm, 700.gsm, 800.gsm, 900.gsm, y.gsm 
+ */
+static int ast_say_number_full_es(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd)
 {
 	int res = 0;
-	int playh = 0;
-	int mf = 1;                            /* +1 = Masculin; -1 = Feminin */
-
+	int playa = 0;
 	char fn[256] = "";
-
 	if (!num) 
 		return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
+	while (!res && num) {
+		if (playa) {
+			snprintf(fn, sizeof(fn), "digits/y");
+			playa = 0;
+		} else if (num < 31) {
+			snprintf(fn, sizeof(fn), "digits/%d", num);
+			num = 0;
+		} else if (num < 100) {
+			snprintf(fn, sizeof(fn), "digits/%d", (num/10)*10);
+			num -= ((num/10)*10);
+			if (num)
+				playa++;
+		} else if (num == 100) {
+			snprintf(fn, sizeof(fn), "digits/cien");
+			num = 0;
+		} else {
+			if (num < 1000) {
+				snprintf(fn, sizeof(fn), "digits/%d", (num/100)*100);
+				num -= ((num/100)*100);
+			} else {
+				if (num < 1000000) {
+					res = ast_say_number_full_es(chan, num / 1000, ints, language, audiofd, ctrlfd);
+					if (res)
+						return res;
+					num = num % 1000;
+					snprintf(fn, sizeof(fn), "digits/mil");
+				} else {
+					if (num < 2147483640) {
+						res = ast_say_number_full_es(chan, num / 1000000, ints, language, audiofd, ctrlfd);
+						if (res)
+							return res;
+						if ((num/1000000) == 1) {
+							snprintf(fn, sizeof(fn), "digits/millon");
+						} else {
+							snprintf(fn, sizeof(fn), "digits/millones");
+						}
+						num = num % 1000000;
+					} else {
+						ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
+						res = -1;
+					}
+				}
+			}
+		}
 
-	if (options && !strncasecmp(options, "f",1)) mf = -1;
-
-         while(!res && num ) {
-
-			if (num < 20) {
-                                 if ((num == 1 || num == 2) && (mf < 0))
-                                     snprintf(fn, sizeof(fn), "digits/%dF", num);
-                                 else
-                                     snprintf(fn, sizeof(fn), "digits/%d", num);
-                                 num = 0;
-                         } else
-                         if (num < 100) {
-                                 snprintf(fn, sizeof(fn), "digits/%d", (num / 10) * 10);
-                                 if (num % 10)
-                                     playh = 1;
-                                 num = num % 10;
-                         } else
-                         if (num < 1000) {
-                                 if (num == 100)
-                                     snprintf(fn, sizeof(fn), "digits/100");
-                                 else if (num < 200)
-                                     snprintf(fn, sizeof(fn), "digits/100E");
-                                 else {
-                                     if (mf < 0 && num > 199)
-                                         snprintf(fn, sizeof(fn), "digits/%dF", (num / 100) * 100);
-                                     else
-                                         snprintf(fn, sizeof(fn), "digits/%d", (num / 100) * 100);
-                                     if (num % 100)
-                                         playh = 1;
-                                 }
-                                 num = num % 100;
-                         } else
-                         if (num < 1000000) {
-                                 if (num > 1999) {
-                                    res = ast_say_number_full_pt(chan, (num / 1000) * mf, ints, language, options, audiofd, ctrlfd);
-                                    if (res)
-                                         return res;
-                                 }
-                                 snprintf(fn, sizeof(fn), "digits/1000");
-                                 if ((num % 1000) && ((num % 1000) < 100  || !(num % 100)))
-                                     playh = 1;
-                                 num = num % 1000;
-                         } else
-                         if (num < 1000000000) {
-                                res = ast_say_number_full_pt(chan, (num / 1000000), ints, language, options, audiofd, ctrlfd );
-                                if (res)
-                                     return res;
- 
-                                 if (num < 2000000)
-                                     snprintf(fn, sizeof(fn), "digits/1000000");
-                                 else
-                                     snprintf(fn, sizeof(fn), "digits/1000000S");
- 
-                                 if ((num % 1000000) &&
-                                   // no thousands
-                                   ((!((num / 1000) % 1000) && ((num % 1000) < 100 || !(num % 100))) ||
-                                   // no hundreds and below
-                                   (!(num % 1000) && (((num / 1000) % 1000) < 100 || !((num / 1000) % 100))) ) )
-                                         playh = 1;
-                                 num = num % 1000000;
-                         }
-			if (!res && playh) {
-                                res = wait_file(chan, ints, "digits/pt-e", language);
-                                ast_stopstream(chan);
-                                playh = 0;
-                        }
- 			if (!res) {
-                                if(!ast_streamfile(chan, fn, language)) {
-                                    if (audiofd && ctrlfd)
-                                        res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
-                                    else
-                                         res = ast_waitstream(chan, ints);
-                                }
-                                ast_stopstream(chan);
-
-                        }
+		if (!res) {
+			if(!ast_streamfile(chan, fn, language)) {
+				if (audiofd && ctrlfd)
+					res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
+				else
+					res = ast_waitstream(chan, ints);
+			}
+			ast_stopstream(chan);
 
+		}
+			
 	}
 	return res;
 }
 
 
-/*--- ast_say_number_full_it:  italian */
+/*--- ast_say_number_full_fr: French syntax */
+static int ast_say_number_full_fr(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd)
+{
+	int res = 0;
+	int playh = 0;
+	int playa = 0;
+	char fn[256] = "";
+	if (!num) 
+		return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
+	while(!res && (num || playh || playa)) {
+		if (playh) {
+			snprintf(fn, sizeof(fn), "digits/hundred");
+			playh = 0;
+		} else if (playa) {
+			snprintf(fn, sizeof(fn), "digits/et");
+			playa = 0;
+		} else if (num < 21) {
+			snprintf(fn, sizeof(fn), "digits/%d", num);
+			num = 0;
+		} else if (num < 70) {
+			snprintf(fn, sizeof(fn), "digits/%d", (num/10)*10);
+			if ((num % 10) == 1) playa++;
+			num = num % 10;
+		} else if (num < 80) {
+			snprintf(fn, sizeof(fn), "digits/60");
+			if ((num % 10) == 1) playa++;
+			num = num - 60;
+		} else if (num < 100) {
+			snprintf(fn, sizeof(fn), "digits/80");
+			num = num - 80;
+		} else if (num < 200) {
+			snprintf(fn, sizeof(fn), "digits/hundred");
+			num = num - 100;
+		} else if (num < 1000) {
+			snprintf(fn, sizeof(fn), "digits/%d", (num/100));
+			playh++;
+			num = num % 100;
+		} else if (num < 2000) {
+			snprintf(fn, sizeof(fn), "digits/thousand");
+			num = num - 1000;
+		} else if (num < 1000000) {
+			res = ast_say_number_full_fr(chan, num / 1000, ints, language, audiofd, ctrlfd);
+			if (res)
+				return res;
+			snprintf(fn, sizeof(fn), "digits/thousand");
+			num = num % 1000;
+		} else	if (num < 1000000000) {
+			res = ast_say_number_full_fr(chan, num / 1000000, ints, language, audiofd, ctrlfd);
+			if (res)
+				return res;
+			snprintf(fn, sizeof(fn), "digits/million");
+			num = num % 1000000;
+		} else {
+			ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
+			res = -1;
+		}
+		if (!res) {
+			if(!ast_streamfile(chan, fn, language)) {
+				if (audiofd && ctrlfd)
+					res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
+				else
+					res = ast_waitstream(chan, ints);
+			}
+			ast_stopstream(chan);
+		}
+	}
+	return res;
+}
+
+/*--- ast_say_number_full_it:  Italian */
 static int ast_say_number_full_it(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd)
 {
-        int res = 0;
-        int playh = 0;
-        int tempnum = 0;
-        char fn[256] = "";
+	int res = 0;
+	int playh = 0;
+	int tempnum = 0;
+	char fn[256] = "";
 
-        if (!num)
+	if (!num)
 		return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
 
 		/*
 		Italian support
 
-		Like english, numbers till 20 are a single 'word', and other
+		Like english, numbers up to 20 are a single 'word', and others
  		compound, but with exceptions.
-		For example 21 is not twenty-one, but is a single word in it.
+		For example 21 is not twenty-one, but there is a single word in 'it'.
 		Idem for 28 (ie when a the 2nd part of a compund number
-		starts with a wovel)
+		starts with a vowel)
 
-		There're exceptions also for hundred, thounsand and million.
+		There are exceptions also for hundred, thousand and million.
 		In english 100 = one hundred, 200 is two hundred.
 		In italian 100 = cento , like to say hundred (without one),
 		200 and more are like english.
 		
-		Same apply for thousand:
+		Same applies for thousand:
 		1000 is one thousand in en, 2000 is two thousand.
 		In it we have 1000 = mille , 2000 = 2 mila 
 
@@ -972,289 +952,293 @@ static int ast_say_number_full_it(struct ast_channel *chan, int num, char *ints,
 		So the right file is provided.
 		*/
 
-        	while(!res && (num || playh)) {
-                        if (playh) {
-                                snprintf(fn, sizeof(fn), "digits/hundred");
-                                playh = 0;
-                        } else
-                        if (num < 20) {
-                                snprintf(fn, sizeof(fn), "digits/%d", num);
-                                num = 0;
-                        } else
-                        if (num == 21) {
-                                snprintf(fn, sizeof(fn), "digits/%d", num);
-                                num = 0;
-                        } else
-                        if (num == 28) {
-                                snprintf(fn, sizeof(fn), "digits/%d", num);
-                                num = 0;
-                        } else
-                        if (num == 31) {
-                                snprintf(fn, sizeof(fn), "digits/%d", num);
-                                num = 0;
-                        } else
-                        if (num == 38) {
-                                snprintf(fn, sizeof(fn), "digits/%d", num);
-                                num = 0;
-                        } else
-                        if (num == 41) {
-                                snprintf(fn, sizeof(fn), "digits/%d", num);
-                                num = 0;
-                        } else
-                        if (num == 48) {
-                                snprintf(fn, sizeof(fn), "digits/%d", num);
-                                num = 0;
-                        } else
-                        if (num == 51) {
-                                snprintf(fn, sizeof(fn), "digits/%d", num);
-                                num = 0;
-                        } else
-                        if (num == 58) {
-                                snprintf(fn, sizeof(fn), "digits/%d", num);
-                                num = 0;
-                        } else
-                        if (num == 61) {
-                                snprintf(fn, sizeof(fn), "digits/%d", num);
-                                num = 0;
-                        } else
-                        if (num == 68) {
-                                snprintf(fn, sizeof(fn), "digits/%d", num);
-                                num = 0;
-                        } else
-                        if (num == 71) {
-                                snprintf(fn, sizeof(fn), "digits/%d", num);
-                                num = 0;
-                        } else
-                        if (num == 78) {
-                                snprintf(fn, sizeof(fn), "digits/%d", num);
-                                num = 0;
-                        } else
-                        if (num == 81) {
-                                snprintf(fn, sizeof(fn), "digits/%d", num);
-                                num = 0;
-                        } else
-                        if (num == 88) {
-                                snprintf(fn, sizeof(fn), "digits/%d", num);
-                                num = 0;
-                        } else
-                        if (num == 91) {
-                                snprintf(fn, sizeof(fn), "digits/%d", num);
-                                num = 0;
-                        } else
-                        if (num == 98) {
-                                snprintf(fn, sizeof(fn), "digits/%d", num);
-                                num = 0;
-                        } else
-                        if (num < 100) {
-                                snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
-                                num -= ((num / 10) * 10);
-                        } else {
-                                if (num < 1000){
-                                        if ((num / 100) > 1) {
-                                                snprintf(fn, sizeof(fn), "digits/%d", (num/100));
-                                                playh++;
-                                        }
-                                        else {
-                                                snprintf(fn, sizeof(fn), "digits/hundred");
-                                        }
-                                        num -= ((num / 100) * 100);
-                                } else {
-                                        if (num < 1000000) { /* 1,000,000 */
-                                                if ((num/1000) > 1)
-                                                        res = ast_say_number_full(chan, num / 1000, ints, language, audiofd, ctrlfd);
-                                                if (res)
-                                                        return res;
-                                                tempnum = num;
-                                                num = num % 1000;
-                                                if ((tempnum / 1000) < 2)
-                                                        snprintf(fn, sizeof(fn), "digits/thousand");
-                                                else /* for 1000 it says mille, for >1000 (eg 2000) says mila */
-                                                        snprintf(fn, sizeof(fn), "digits/thousands");
-                                        } else {
-                                                if (num < 1000000000) { /* 1,000,000,000 */
-                                                        if ((num / 1000000) > 1)
-                                                                res = ast_say_number_full(chan, num / 1000000, ints, language, audiofd, ctrlfd);
-                                                        if (res)
-                                                                return res;
-                                                        tempnum = num;
-                                                        num = num % 1000000;
-                                                        if ((tempnum / 1000000) < 2)
-                                                                snprintf(fn, sizeof(fn), "digits/million");
-                                                        else
-                                                                snprintf(fn, sizeof(fn), "digits/millions");
-                                                } else {
-                                                        ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
-                                                        res = -1;
-                                                }
-                                        }
-                                }
-                        }
-			 if (!res) {
-                                if(!ast_streamfile(chan, fn, language)) {
-                                    if (audiofd && ctrlfd)
-                                        res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
-                                    else
-                                         res = ast_waitstream(chan, ints);
-                                }
-                                ast_stopstream(chan);
-
-                        }
-                }
-        return res;
+		while(!res && (num || playh)) {
+			if (playh) {
+				snprintf(fn, sizeof(fn), "digits/hundred");
+				playh = 0;
+			} else if (num < 20) {
+				snprintf(fn, sizeof(fn), "digits/%d", num);
+				num = 0;
+			} else if (num == 21) {
+				snprintf(fn, sizeof(fn), "digits/%d", num);
+				num = 0;
+			} else if (num == 28) {
+				snprintf(fn, sizeof(fn), "digits/%d", num);
+				num = 0;
+			} else if (num == 31) {
+				snprintf(fn, sizeof(fn), "digits/%d", num);
+				num = 0;
+			} else if (num == 38) {
+				snprintf(fn, sizeof(fn), "digits/%d", num);
+				num = 0;
+			} else if (num == 41) {
+				snprintf(fn, sizeof(fn), "digits/%d", num);
+				num = 0;
+			} else if (num == 48) {
+				snprintf(fn, sizeof(fn), "digits/%d", num);
+				num = 0;
+			} else if (num == 51) {
+				snprintf(fn, sizeof(fn), "digits/%d", num);
+				num = 0;
+			} else if (num == 58) {
+				snprintf(fn, sizeof(fn), "digits/%d", num);
+				num = 0;
+			} else if (num == 61) {
+				snprintf(fn, sizeof(fn), "digits/%d", num);
+				num = 0;
+			} else if (num == 68) {
+				snprintf(fn, sizeof(fn), "digits/%d", num);
+				num = 0;
+			} else if (num == 71) {
+				snprintf(fn, sizeof(fn), "digits/%d", num);
+				num = 0;
+			} else if (num == 78) {
+				snprintf(fn, sizeof(fn), "digits/%d", num);
+				num = 0;
+			} else if (num == 81) {
+				snprintf(fn, sizeof(fn), "digits/%d", num);
+				num = 0;
+			} else if (num == 88) {
+				snprintf(fn, sizeof(fn), "digits/%d", num);
+				num = 0;
+			} else if (num == 91) {
+				snprintf(fn, sizeof(fn), "digits/%d", num);
+				num = 0;
+			} else if (num == 98) {
+				snprintf(fn, sizeof(fn), "digits/%d", num);
+				num = 0;
+			} else if (num < 100) {
+				snprintf(fn, sizeof(fn), "digits/%d", (num /10) * 10);
+				num -= ((num / 10) * 10);
+			} else {
+				if (num < 1000) {
+					if ((num / 100) > 1) {
+						snprintf(fn, sizeof(fn), "digits/%d", (num/100));
+						playh++;
+					} else {
+						snprintf(fn, sizeof(fn), "digits/hundred");
+					}
+					num -= ((num / 100) * 100);
+				} else {
+					if (num < 1000000) { /* 1,000,000 */
+						if ((num/1000) > 1)
+							res = ast_say_number_full(chan, num / 1000, ints, language, audiofd, ctrlfd);
+						if (res)
+							return res;
+						tempnum = num;
+						num = num % 1000;
+						if ((tempnum / 1000) < 2)
+							snprintf(fn, sizeof(fn), "digits/thousand");
+						else /* for 1000 it says mille, for >1000 (eg 2000) says mila */
+							snprintf(fn, sizeof(fn), "digits/thousands");
+					} else {
+						if (num < 1000000000) { /* 1,000,000,000 */
+							if ((num / 1000000) > 1)
+								res = ast_say_number_full(chan, num / 1000000, ints, language, audiofd, ctrlfd);
+							if (res)
+								return res;
+							tempnum = num;
+							num = num % 1000000;
+							if ((tempnum / 1000000) < 2)
+								snprintf(fn, sizeof(fn), "digits/million");
+							else
+								snprintf(fn, sizeof(fn), "digits/millions");
+						} else {
+							ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
+							res = -1;
+						}
+					}
+				}
+			}
+			if (!res) {
+				if(!ast_streamfile(chan, fn, language)) {
+					if (audiofd && ctrlfd)
+						res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
+					else
+						res = ast_waitstream(chan, ints);
+				}
+				ast_stopstream(chan);
+			}
+		}
+	return res;
 }
- 
 
-/*--- ast_say_number_full_es: spanish syntax */
-/* New files:
- Requires a few new audios:
-   21.gsm thru 29.gsm, cien.gsm, mil.gsm, millon.gsm, millones.gsm, 100.gsm, 200.gsm, 300.gsm, 400.gsm, 500.gsm, 600.gsm, 700.gsm, 800.gsm, 900.gsm, y.gsm 
+/*--- ast_say_number_full_nl: dutch syntax */
+/* New files: digits/nl-en
  */
-static int ast_say_number_full_es(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd)
+static int ast_say_number_full_nl(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd)
 {
 	int res = 0;
-	int playa = 0;
+	int playh = 0;
+	int units = 0;
 	char fn[256] = "";
 	if (!num) 
 		return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
-	while (!res && num) {
-                                if (playa) {
-                                        snprintf(fn, sizeof(fn), "digits/y");
-                                        playa = 0;
-                                } else 
-                                if (num < 31) {
-                                        snprintf(fn, sizeof(fn), "digits/%d", num);
-                                        num = 0;
-                                } else  
-                                if (num < 100) {
-                                        snprintf(fn, sizeof(fn), "digits/%d", (num/10)*10);
-                                        num -= ((num/10)*10);
-                                        if (num)
-                                                playa++;
-                                } else
-                                if (num == 100) {
-                                        snprintf(fn, sizeof(fn), "digits/cien");
-                                        num = 0;
-                                } else {
-                                        if (num < 1000) {
-                                                snprintf(fn, sizeof(fn), "digits/%d", (num/100)*100);
-                                                num -= ((num/100)*100);
-                                        } else {
-                                                if (num < 1000000) {
-                                                        res = ast_say_number_full_es(chan, num / 1000, ints, language, audiofd, ctrlfd);
-                                                        if (res)
-                                                                return res;
-                                                        num = num % 1000;
-                                                        snprintf(fn, sizeof(fn), "digits/mil");
-                                                } else {
-                                                        if (num < 2147483640) {
-                                                                res = ast_say_number_full_es(chan, num / 1000000, ints, language, audiofd, ctrlfd);
-                                                                if (res)
-                                                                        return res;
-                                                                if ((num/1000000) == 1) {
-                                                                        snprintf(fn, sizeof(fn), "digits/millon");
-                                                                } else {
-                                                                        snprintf(fn, sizeof(fn), "digits/millones");
-                                                                }
-                                                                num = num % 1000000;
-                                                        } else {
-                                                                ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
-                                                                res = -1;
-                                                        }
-                                                }
-                                        }
-                                }
-
-			 if (!res) {
-                                if(!ast_streamfile(chan, fn, language)) {
-                                    if (audiofd && ctrlfd)
-                                        res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
-                                    else
-                                         res = ast_waitstream(chan, ints);
-                                }
-                                ast_stopstream(chan);
+	while (!res && (num || playh )) {
+		if (playh) {
+			snprintf(fn, sizeof(fn), "digits/hundred");
+			playh = 0;
+		} else if (num < 20) {
+			snprintf(fn, sizeof(fn), "digits/%d", num);
+			num = 0;
+		} else if (num < 100) {
+			units = num % 10;
+			if (units > 0) {
+				res = ast_say_number_full_nl(chan, units, ints, language, audiofd, ctrlfd);
+				if (res)
+					return res;
+				num = num - units;
+				snprintf(fn, sizeof(fn), "digits/nl-en");
+			} else {
+				snprintf(fn, sizeof(fn), "digits/%d", num - units);
+				num = 0;
+			}
+		} else {
+			if (num < 1000) {
+				snprintf(fn, sizeof(fn), "digits/%d", (num/100));
+				playh++;
+				num -= ((num / 100) * 100);
+			} else {
+				if (num < 1000000) { /* 1,000,000 */
+					res = ast_say_number_full_en(chan, num / 1000, ints, language, audiofd, ctrlfd);
+					if (res)
+						return res;
+					num = num % 1000;
+					snprintf(fn, sizeof(fn), "digits/thousand");
+				} else {
+					if (num < 1000000000) { /* 1,000,000,000 */
+						res = ast_say_number_full_en(chan, num / 1000000, ints, language, audiofd, ctrlfd);
+						if (res)
+							return res;
+						num = num % 1000000;
+						snprintf(fn, sizeof(fn), "digits/million");
+					} else {
+						ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
+						res = -1;
+					}
+				}
+			}
+		}
 
-                        }
-			
+		if (!res) {
+			if(!ast_streamfile(chan, fn, language)) {
+				if (audiofd && ctrlfd)
+					res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
+				else
+					res = ast_waitstream(chan, ints);
+			}
+			ast_stopstream(chan);
+		}
 	}
 	return res;
 }
 
-/*--- ast_say_number_full_nl: dutch syntax */
-/* New files: ???
- */
-static int ast_say_number_full_nl(struct ast_channel *chan, int num, char *ints, char *language, int audiofd, int ctrlfd)
+/* ast_say_number_full_pt: Portuguese syntax */
+/* 	Extra sounds needed: */
+/* 	For feminin all sound files end with F */
+/*	100E for 100+ something */
+/*	1000000S for plural */
+/*	pt-e for 'and' */
+static int ast_say_number_full_pt(struct ast_channel *chan, int num, char *ints, char *language, char *options, int audiofd, int ctrlfd)
 {
 	int res = 0;
 	int playh = 0;
-	int units = 0;
+	int mf = 1;                            /* +1 = Masculin; -1 = Feminin */
 	char fn[256] = "";
+
 	if (!num) 
 		return ast_say_digits_full(chan, 0,ints, language, audiofd, ctrlfd);
-	while (!res && (num || playh )) {
-		 if (playh) {
-                     snprintf(fn, sizeof(fn), "digits/hundred");
-                     playh = 0;
-                 } else
-                 if (num < 20) {
-                     snprintf(fn, sizeof(fn), "digits/%d", num);
-                     num = 0;
-                 } else
-                 if (num < 100) {
-		     units = num % 10;
-		     if (units > 0) {
-			res = ast_say_number_full_nl(chan, units, ints, language, audiofd, ctrlfd);
-                        if (res)
-                            return res;
-                        num = num - units;
-                        snprintf(fn, sizeof(fn), "digits/nl-en");
-                     } else {
-                        snprintf(fn, sizeof(fn), "digits/%d", num - units);
-                        num = 0;
-                     }
-                 } else {
-                     if (num < 1000){
-                        snprintf(fn, sizeof(fn), "digits/%d", (num/100));
-                        playh++;
-                        num -= ((num / 100) * 100);
-                     } else {
-                        if (num < 1000000) { /* 1,000,000 */
-                           res = ast_say_number_full_en(chan, num / 1000, ints, language, audiofd, ctrlfd);
-                           if (res)
-                              return res;
-                           num = num % 1000;
-                           snprintf(fn, sizeof(fn), "digits/thousand");
-                       } else {
-                         if (num < 1000000000) { /* 1,000,000,000 */
-                            res = ast_say_number_full_en(chan, num / 1000000, ints, language, audiofd, ctrlfd);
-                            if (res)
-                               return res;
-                            num = num % 1000000;
-                            snprintf(fn, sizeof(fn), "digits/million");
-                         } else {
-                            ast_log(LOG_DEBUG, "Number '%d' is too big for me\n", num);
-                            res = -1;
-                         }
-                      } 
-                   }
-                }
-
-	        if (!res) {
-                   if(!ast_streamfile(chan, fn, language)) {
-                       if (audiofd && ctrlfd)
-                          res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);
-                       else
-                          res = ast_waitstream(chan, ints);
-                   }
-                   ast_stopstream(chan);
-
-              }
-			
-	}
-	return res;
-}
 
+	if (options && !strncasecmp(options, "f",1))
+		mf = -1;
+
+	while(!res && num ) {
+		if (num < 20) {
+			if ((num == 1 || num == 2) && (mf < 0))
+				snprintf(fn, sizeof(fn), "digits/%dF", num);
+			else
+				snprintf(fn, sizeof(fn), "digits/%d", num);
+			num = 0;
+		} else if (num < 100) {
+			snprintf(fn, sizeof(fn), "digits/%d", (num / 10) * 10);
+			if (num % 10)
+				playh = 1;
+			num = num % 10;
+		} else if (num < 1000) {
+			if (num == 100)
+				snprintf(fn, sizeof(fn), "digits/100");
+			else if (num < 200)
+				snprintf(fn, sizeof(fn), "digits/100E");
+			else {
+				if (mf < 0 && num > 199)
+					snprintf(fn, sizeof(fn), "digits/%dF", (num / 100) * 100);
+				else
+					snprintf(fn, sizeof(fn), "digits/%d", (num / 100) * 100);
+				if (num % 100)
+					playh = 1;
+			}
+			num = num % 100;
+		} else if (num < 1000000) {
+			if (num > 1999) {
+				res = ast_say_number_full_pt(chan, (num / 1000) * mf, ints, language, options, audiofd, ctrlfd);
+				if (res)
+					return res;
+			}
+			snprintf(fn, sizeof(fn), "digits/1000");
+			if ((num % 1000) && ((num % 1000) < 100  || !(num % 100)))
+				playh = 1;
+			num = num % 1000;
+		} else if (num < 1000000000) {
+			res = ast_say_number_full_pt(chan, (num / 1000000), ints, language, options, audiofd, ctrlfd );
+			if (res)
+				return res;
+			if (num < 2000000)
+				snprintf(fn, sizeof(fn), "digits/1000000");
+			else
+				snprintf(fn, sizeof(fn), "digits/1000000S");
+ 
+			if ((num % 1000000) &&
+				// no thousands
+				((!((num / 1000) % 1000) && ((num % 1000) < 100 || !(num % 100))) ||
+				// no hundreds and below
+				(!(num % 1000) && (((num / 1000) % 1000) < 100 || !((num / 1000) % 100))) ) )
+				playh = 1;
+			num = num % 1000000;
+		}
+		if (!res && playh) {
+			res = wait_file(chan, ints, "digits/pt-e", language);
+			ast_stopstream(chan);
+			playh = 0;
+		}
+		if (!res) {
+			if(!ast_streamfile(chan, fn, language)) {
+				if (audiofd && ctrlfd)
+					res = ast_waitstream_full(chan, ints, audiofd, ctrlfd);			else
+					res = ast_waitstream(chan, ints);
+			}
+			ast_stopstream(chan);
+		}
+	}
+	return res;
+}
 
 int ast_say_date(struct ast_channel *chan, time_t t, char *ints, char *lang)
+{
+	if (!strcasecmp(lang,"en") ) {	/* English syntax */
+		return(ast_say_date_en(chan, t, ints, lang));
+	} else if (!strcasecmp(lang, "nl") ) {	/* Dutch syntax */
+		return(ast_say_date_nl(chan, t, ints, lang));
+	} else if (!strcasecmp(lang, "pt") ) {	/* Portuguese syntax */
+		return(ast_say_date_pt(chan, t, ints, lang));
+	}
+
+	/* Default to English */
+	return(ast_say_date_en(chan, t, ints, lang));
+}
+
+
+/* English syntax */
+int ast_say_date_en(struct ast_channel *chan, time_t t, char *ints, char *lang)
 {
 	struct tm tm;
 	char fn[256];
@@ -1274,8 +1258,6 @@ int ast_say_date(struct ast_channel *chan, time_t t, char *ints, char *lang)
 	}
 	if (!res)
 		res = ast_say_number(chan, tm.tm_mday, ints, lang, (char * ) NULL);
-		/* Should portuguese add a gender here?  Defaults to masculin */
-
 	if (!res)
 		res = ast_waitstream(chan, ints);
 	if (!res)
@@ -1283,17 +1265,76 @@ int ast_say_date(struct ast_channel *chan, time_t t, char *ints, char *lang)
 	return res;
 }
 
-static int wait_file(struct ast_channel *chan, char *ints, char *file, char *lang) 
+/* Dutch syntax */
+int ast_say_date_nl(struct ast_channel *chan, time_t t, char *ints, char *lang)
 {
-	int res;
-	if ((res = ast_streamfile(chan, file, lang)))
-		ast_log(LOG_WARNING, "Unable to play message %s\n", file);
+	struct tm tm;
+	char fn[256];
+	int res = 0;
+	ast_localtime(&t,&tm,NULL);
+	if (!res) {
+		snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
+		res = ast_streamfile(chan, fn, lang);
+		if (!res)
+			res = ast_waitstream(chan, ints);
+	}
+	if (!res)
+		res = ast_say_number(chan, tm.tm_mday, ints, lang, (char * ) NULL);
+	if (!res) {
+		snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
+		res = ast_streamfile(chan, fn, lang);
+		if (!res)
+			res = ast_waitstream(chan, ints);
+	}
 	if (!res)
 		res = ast_waitstream(chan, ints);
+	if (!res)
+		res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
+	return res;
+}
+
+/* Portuguese syntax */
+int ast_say_date_pt(struct ast_channel *chan, time_t t, char *ints, char *lang)
+{
+	struct tm tm;
+	char fn[256];
+	int res = 0;
+	ast_localtime(&t,&tm,NULL);
+	localtime_r(&t,&tm);
+	snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
+	if (!res)
+		res = wait_file(chan, ints, fn, lang);
+	if (!res)
+		res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL);
+	if (!res)
+		res = wait_file(chan, ints, "digits/pt-de", lang);
+	snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
+	if (!res)
+		res = wait_file(chan, ints, fn, lang);
+	if (!res)
+		res = wait_file(chan, ints, "digits/pt-de", lang);
+	if (!res)
+		res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
+
 	return res;
 }
 
 int ast_say_date_with_format(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone)
+{
+	if (!strcasecmp(lang, "en") ) {	/* English syntax */
+		return(ast_say_date_with_format_en(chan, time, ints, lang, format, timezone));
+	} else if (!strcasecmp(lang, "nl") ) {	/* Dutch syntax */
+		return(ast_say_date_with_format_nl(chan, time, ints, lang, format, timezone));
+	} else if (!strcasecmp(lang, "pt") ) {	/* Portuguese syntax */
+		return(ast_say_date_with_format_pt(chan, time, ints, lang, format, timezone));
+	}
+
+	/* Default to English */
+	return(ast_say_date_with_format_en(chan, time, ints, lang, format, timezone));
+}
+
+/* English syntax */
+int ast_say_date_with_format_en(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone)
 {
 	struct tm tm;
 	int res=0, offset, sndoffset;
@@ -1350,79 +1391,524 @@ int ast_say_date_with_format(struct ast_channel *chan, time_t time, char *ints,
 				break;
 			case 'Y':
 				/* Year */
-				if (tm.tm_year > 99) {
-					res = wait_file(chan,ints, "digits/2",lang);
-					if (!res) {
-						res = wait_file(chan,ints, "digits/thousand",lang);
-					}
-					if (tm.tm_year > 100) {
-						if (!res) {
-							/* This works until the end of 2020 */
-							snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year - 100);
-							res = wait_file(chan,ints,nextmsg,lang);
-						}
-					}
-				} 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 {
-						res = wait_file(chan,ints, "digits/19",lang);
-						if (!res) {
-							if (tm.tm_year <= 9) {
-								/* 1901 - 1909 */
-								res = wait_file(chan,ints, "digits/oh",lang);
-								if (!res) {
-									snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year);
-									res = wait_file(chan,ints,nextmsg,lang);
-								}
-							} else if (tm.tm_year <= 20) {
-								/* 1910 - 1920 */
-								snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year);
-								res = wait_file(chan,ints,nextmsg,lang);
-							} else {
-								/* 1921 - 1999 */
-								int ten, one;
-								ten = tm.tm_year / 10;
-								one = tm.tm_year % 10;
-								snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten * 10);
-								res = wait_file(chan,ints,nextmsg,lang);
-								if (!res) {
-									if (one != 0) {
-										snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one);
-										res = wait_file(chan,ints,nextmsg,lang);
-									}
-								}
-							}
-						}
-					}
-				}
+				if (tm.tm_year > 99) {
+					res = wait_file(chan,ints, "digits/2",lang);
+					if (!res) {
+						res = wait_file(chan,ints, "digits/thousand",lang);
+					}
+					if (tm.tm_year > 100) {
+						if (!res) {
+							/* This works until the end of 2020 */
+							snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year - 100);
+							res = wait_file(chan,ints,nextmsg,lang);
+						}
+					}
+				} 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 {
+						res = wait_file(chan,ints, "digits/19",lang);
+						if (!res) {
+							if (tm.tm_year <= 9) {
+								/* 1901 - 1909 */
+								res = wait_file(chan,ints, "digits/oh",lang);
+								if (!res) {
+									snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year);
+									res = wait_file(chan,ints,nextmsg,lang);
+								}
+							} else if (tm.tm_year <= 20) {
+								/* 1910 - 1920 */
+								snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year);
+								res = wait_file(chan,ints,nextmsg,lang);
+							} else {
+								/* 1921 - 1999 */
+								int ten, one;
+								ten = tm.tm_year / 10;
+								one = tm.tm_year % 10;
+								snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten * 10);
+								res = wait_file(chan,ints,nextmsg,lang);
+								if (!res) {
+									if (one != 0) {
+										snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one);
+										res = wait_file(chan,ints,nextmsg,lang);
+									}
+								}
+							}
+						}
+					}
+				}
+				break;
+			case 'I':
+			case 'l':
+				/* 12-Hour */
+				if (tm.tm_hour == 0)
+					snprintf(nextmsg,sizeof(nextmsg), "digits/12");
+				else if (tm.tm_hour > 12)
+					snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour - 12);
+				else
+					snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour);
+				res = wait_file(chan,ints,nextmsg,lang);
+				break;
+			case 'H':
+			case 'k':
+				/* 24-Hour */
+				if (format[offset] == 'H') {
+					/* e.g. oh-eight */
+					if (tm.tm_hour < 10) {
+						res = wait_file(chan,ints, "digits/oh",lang);
+					}
+				} else {
+					/* e.g. eight */
+					if (tm.tm_hour == 0) {
+						res = wait_file(chan,ints, "digits/oh",lang);
+					}
+				}
+				if (!res) {
+					if (tm.tm_hour != 0) {
+						int remainder = tm.tm_hour;
+						if (tm.tm_hour > 20) {
+							res = wait_file(chan,ints, "digits/20",lang);
+							remainder -= 20;
+						}
+						if (!res) {
+							snprintf(nextmsg,sizeof(nextmsg), "digits/%d", remainder);
+							res = wait_file(chan,ints,nextmsg,lang);
+						}
+					}
+				}
+				break;
+			case 'M':
+				/* Minute */
+				if (tm.tm_min == 0) {
+					res = wait_file(chan,ints, "digits/oclock",lang);
+				} else if (tm.tm_min < 10) {
+					res = wait_file(chan,ints, "digits/oh",lang);
+					if (!res) {
+						snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min);
+						res = wait_file(chan,ints,nextmsg,lang);
+					}
+				} else if ((tm.tm_min < 21) || (tm.tm_min % 10 == 0)) {
+					snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min);
+					res = wait_file(chan,ints,nextmsg,lang);
+				} else {
+					int ten, one;
+					ten = (tm.tm_min / 10) * 10;
+					one = (tm.tm_min % 10);
+					snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten);
+					res = wait_file(chan,ints,nextmsg,lang);
+					if (!res) {
+						/* Fifty, not fifty-zero */
+						if (one != 0) {
+							snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one);
+							res = wait_file(chan,ints,nextmsg,lang);
+						}
+					}
+				}
+				break;
+			case 'P':
+			case 'p':
+				/* AM/PM */
+				if (tm.tm_hour > 11)
+					snprintf(nextmsg,sizeof(nextmsg), "digits/p-m");
+				else
+					snprintf(nextmsg,sizeof(nextmsg), "digits/a-m");
+				res = wait_file(chan,ints,nextmsg,lang);
+				break;
+			case 'Q':
+				/* Shorthand for "Today", "Yesterday", or ABdY */
+				{
+					struct timeval now;
+					struct tm tmnow;
+					time_t beg_today;
+
+					gettimeofday(&now,NULL);
+					ast_localtime(&now.tv_sec,&tmnow,timezone);
+					/* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
+					/* In any case, it saves not having to do ast_mktime() */
+					beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec);
+					if (beg_today < time) {
+						/* Today */
+						res = wait_file(chan,ints, "digits/today",lang);
+					} else if (beg_today - 86400 < time) {
+						/* Yesterday */
+						res = wait_file(chan,ints, "digits/yesterday",lang);
+					} else {
+						res = ast_say_date_with_format(chan, time, ints, lang, "ABdY", timezone);
+					}
+				}
+				break;
+			case 'q':
+				/* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */
+				{
+					struct timeval now;
+					struct tm tmnow;
+					time_t beg_today;
+
+					gettimeofday(&now,NULL);
+					ast_localtime(&now.tv_sec,&tmnow,timezone);
+					/* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
+					/* In any case, it saves not having to do ast_mktime() */
+					beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec);
+					if (beg_today < time) {
+						/* Today */
+					} else if ((beg_today - 86400) < time) {
+						/* Yesterday */
+						res = wait_file(chan,ints, "digits/yesterday",lang);
+					} else if (beg_today - 86400 * 6 < time) {
+						/* Within the last week */
+						res = ast_say_date_with_format(chan, time, ints, lang, "A", timezone);
+					} else {
+						res = ast_say_date_with_format(chan, time, ints, lang, "ABdY", timezone);
+					}
+				}
+				break;
+			case 'R':
+				res = ast_say_date_with_format(chan, time, ints, lang, "HM", timezone);
+				break;
+			case 'S':
+				/* Seconds */
+				if (tm.tm_sec == 0) {
+					snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec);
+					res = wait_file(chan,ints,nextmsg,lang);
+				} else if (tm.tm_sec < 10) {
+					res = wait_file(chan,ints, "digits/oh",lang);
+					if (!res) {
+						snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec);
+						res = wait_file(chan,ints,nextmsg,lang);
+					}
+				} else if ((tm.tm_sec < 21) || (tm.tm_sec % 10 == 0)) {
+					snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec);
+					res = wait_file(chan,ints,nextmsg,lang);
+				} else {
+					int ten, one;
+					ten = (tm.tm_sec / 10) * 10;
+					one = (tm.tm_sec % 10);
+					snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten);
+					res = wait_file(chan,ints,nextmsg,lang);
+					if (!res) {
+						/* Fifty, not fifty-zero */
+						if (one != 0) {
+							snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one);
+							res = wait_file(chan,ints,nextmsg,lang);
+						}
+					}
+				}
+				break;
+			case 'T':
+				res = ast_say_date_with_format(chan, time, ints, lang, "HMS", timezone);
+				break;
+			case ' ':
+			case '	':
+				/* Just ignore spaces and tabs */
+				break;
+			default:
+				/* Unknown character */
+				ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset);
+		}
+		/* Jump out on DTMF */
+		if (res) {
+			break;
+		}
+	}
+	return res;
+}
+
+/* Dutch syntax */
+int ast_say_date_with_format_nl(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone)
+{
+	struct tm tm;
+	int res=0, offset, sndoffset;
+	char sndfile[256], nextmsg[256];
+
+	ast_localtime(&time,&tm,timezone);
+
+	for (offset=0 ; format[offset] != '\0' ; offset++) {
+		ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format);
+		switch (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 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++)
+					sndfile[sndoffset] = format[offset];
+				sndfile[sndoffset] = '\0';
+				snprintf(nextmsg,sizeof(nextmsg), AST_SOUNDS "/%s", sndfile);
+				res = wait_file(chan,ints,nextmsg,lang);
+				break;
+			case 'A':
+			case 'a':
+				/* Sunday - Saturday */
+				snprintf(nextmsg,sizeof(nextmsg), "digits/day-%d", tm.tm_wday);
+				res = wait_file(chan,ints,nextmsg,lang);
+				break;
+			case 'B':
+			case 'b':
+			case 'h':
+				/* January - December */
+				snprintf(nextmsg,sizeof(nextmsg), "digits/mon-%d", tm.tm_mon);
+				res = wait_file(chan,ints,nextmsg,lang);
+				break;
+			case 'd':
+			case 'e':
+				/* First - Thirtyfirst */
+				res = ast_say_number(chan, tm.tm_mday, ints, lang, NULL);
+				break;
+			case 'Y':
+				/* Year */
+				if (tm.tm_year > 99) {
+					res = wait_file(chan,ints, "digits/2",lang);
+					if (!res) {
+						res = wait_file(chan,ints, "digits/thousand",lang);
+					}
+					if (tm.tm_year > 100) {
+						if (!res) {
+							/* This works until the end of 2020 */
+							snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year - 100);
+							res = wait_file(chan,ints,nextmsg,lang);
+						}
+					}
+				} 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 {
+						res = wait_file(chan,ints, "digits/19",lang);
+						if (!res) {
+							if (tm.tm_year <= 9) {
+								/* 1901 - 1909 */
+								res = wait_file(chan,ints, "digits/oh",lang);
+								if (!res) {
+									snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year);
+									res = wait_file(chan,ints,nextmsg,lang);
+								}
+							} else if (tm.tm_year <= 20) {
+								/* 1910 - 1920 */
+								snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_year);
+								res = wait_file(chan,ints,nextmsg,lang);
+							} else {
+								/* 1921 - 1999 */
+								int ten, one;
+								ten = tm.tm_year / 10;
+								one = tm.tm_year % 10;
+								snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten * 10);
+								res = wait_file(chan,ints,nextmsg,lang);
+								if (!res) {
+									if (one != 0) {
+										snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one);
+										res = wait_file(chan,ints,nextmsg,lang);
+									}
+								}
+							}
+						}
+					}
+				}
+				break;
+			case 'I':
+			case 'l':
+				/* 12-Hour */
+				if (tm.tm_hour == 0)
+					snprintf(nextmsg,sizeof(nextmsg), "digits/12");
+				else if (tm.tm_hour > 12)
+					snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour - 12);
+				else
+					snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour);
+				res = wait_file(chan,ints,nextmsg,lang);
+				break;
+			case 'H':
+			case 'k':
+				/* 24-Hour */
+				res = ast_say_number(chan, tm.tm_hour, ints, lang, (char *) NULL);
+				if (!res) {
+					res = wait_file(chan,ints, "digits/nl-uur",lang);
+				}
+				break;
+			case 'M':
+				/* Minute */
+				res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL);
+				break;
+			case 'P':
+			case 'p':
+				/* AM/PM */
+				if (tm.tm_hour > 11)
+					snprintf(nextmsg,sizeof(nextmsg), "digits/p-m");
+				else
+					snprintf(nextmsg,sizeof(nextmsg), "digits/a-m");
+				res = wait_file(chan,ints,nextmsg,lang);
+				break;
+			case 'Q':
+				/* Shorthand for "Today", "Yesterday", or ABdY */
+				{
+					struct timeval now;
+					struct tm tmnow;
+					time_t beg_today;
+
+					gettimeofday(&now,NULL);
+					ast_localtime(&now.tv_sec,&tmnow,timezone);
+					/* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
+					/* In any case, it saves not having to do ast_mktime() */
+					beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec);
+					if (beg_today < time) {
+						/* Today */
+						res = wait_file(chan,ints, "digits/today",lang);
+					} else if (beg_today - 86400 < time) {
+						/* Yesterday */
+						res = wait_file(chan,ints, "digits/yesterday",lang);
+					} else {
+						res = ast_say_date_with_format(chan, time, ints, lang, "ABdY", timezone);
+					}
+				}
+				break;
+			case 'q':
+				/* Shorthand for "" (today), "Yesterday", A (weekday), or ABdY */
+				{
+					struct timeval now;
+					struct tm tmnow;
+					time_t beg_today;
+
+					gettimeofday(&now,NULL);
+					ast_localtime(&now.tv_sec,&tmnow,timezone);
+					/* This might be slightly off, if we transcend a leap second, but never more off than 1 second */
+					/* In any case, it saves not having to do ast_mktime() */
+					beg_today = now.tv_sec - (tmnow.tm_hour * 3600) - (tmnow.tm_min * 60) - (tmnow.tm_sec);
+					if (beg_today < time) {
+						/* Today */
+					} else if ((beg_today - 86400) < time) {
+						/* Yesterday */
+						res = wait_file(chan,ints, "digits/yesterday",lang);
+					} else if (beg_today - 86400 * 6 < time) {
+						/* Within the last week */
+						res = ast_say_date_with_format(chan, time, ints, lang, "A", timezone);
+					} else {
+						res = ast_say_date_with_format(chan, time, ints, lang, "ABdY", timezone);
+					}
+				}
+				break;
+			case 'R':
+				res = ast_say_date_with_format(chan, time, ints, lang, "HM", timezone);
+				break;
+			case 'S':
+				/* Seconds */
+				if (tm.tm_sec == 0) {
+					snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec);
+					res = wait_file(chan,ints,nextmsg,lang);
+				} else if (tm.tm_sec < 10) {
+					res = wait_file(chan,ints, "digits/oh",lang);
+					if (!res) {
+						snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec);
+						res = wait_file(chan,ints,nextmsg,lang);
+					}
+				} else if ((tm.tm_sec < 21) || (tm.tm_sec % 10 == 0)) {
+					snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_sec);
+					res = wait_file(chan,ints,nextmsg,lang);
+				} else {
+					int ten, one;
+					ten = (tm.tm_sec / 10) * 10;
+					one = (tm.tm_sec % 10);
+					snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten);
+					res = wait_file(chan,ints,nextmsg,lang);
+					if (!res) {
+						/* Fifty, not fifty-zero */
+						if (one != 0) {
+							snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one);
+							res = wait_file(chan,ints,nextmsg,lang);
+						}
+					}
+				}
+				break;
+			case 'T':
+				res = ast_say_date_with_format(chan, time, ints, lang, "HMS", timezone);
+				break;
+			case ' ':
+			case '	':
+				/* Just ignore spaces and tabs */
+				break;
+			default:
+				/* Unknown character */
+				ast_log(LOG_WARNING, "Unknown character in datetime format %s: %c at pos %d\n", format, format[offset], offset);
+		}
+		/* Jump out on DTMF */
+		if (res) {
+			break;
+		}
+	}
+	return res;
+}
+
+/* Portuguese syntax */
+int ast_say_date_with_format_pt(struct ast_channel *chan, time_t time, char *ints, char *lang, char *format, char *timezone)
+{
+	struct tm tm;
+	int res=0, offset, sndoffset;
+	char sndfile[256], nextmsg[256];
+
+	ast_localtime(&time,&tm,timezone);
+
+	for (offset=0 ; format[offset] != '\0' ; offset++) {
+		ast_log(LOG_DEBUG, "Parsing %c (offset %d) in %s\n", format[offset], offset, format);
+		switch (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 ; (format[++offset] != '\'') && (sndoffset < 256) ; sndoffset++)
+					sndfile[sndoffset] = format[offset];
+				sndfile[sndoffset] = '\0';
+				snprintf(nextmsg,sizeof(nextmsg), "%s", sndfile);
+				res = wait_file(chan,ints,nextmsg,lang);
+				break;
+			case 'A':
+			case 'a':
+				/* Sunday - Saturday */
+				snprintf(nextmsg,sizeof(nextmsg), "digits/day-%d", tm.tm_wday);
+				res = wait_file(chan,ints,nextmsg,lang);
+				break;
+			case 'B':
+			case 'b':
+			case 'h':
+				/* January - December */
+				snprintf(nextmsg,sizeof(nextmsg), "digits/mon-%d", tm.tm_mon);
+				res = wait_file(chan,ints,nextmsg,lang);
+				break;
+			case 'd':
+			case 'e':
+				/* First - Thirtyfirst */
+				res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL);
+				break;
+			case 'Y':
+				/* Year */
+				res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
 				break;
 			case 'I':
 			case 'l':
 				/* 12-Hour */
-				if (tm.tm_hour == 0)
-					snprintf(nextmsg,sizeof(nextmsg), "digits/12");
-				else if (tm.tm_hour > 12)
-					snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour - 12);
-				else
-					snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_hour);
-				res = wait_file(chan,ints,nextmsg,lang);
+				if (tm.tm_hour == 0) {
+					if (format[offset] == 'I')
+						res = wait_file(chan, ints, "digits/pt-ah", lang);
+					if (!res)
+						res = wait_file(chan, ints, "digits/pt-meianoite", lang);
+				}
+				else if (tm.tm_hour == 12) {
+					if (format[offset] == 'I')
+						res = wait_file(chan, ints, "digits/pt-ao", lang);
+					if (!res)
+						res = wait_file(chan, ints, "digits/pt-meiodia", lang);
+				}
+				else {
+					if (format[offset] == 'I') {
+						res = wait_file(chan, ints, "digits/pt-ah", lang);
+						if ((tm.tm_hour % 12) != 1)
+							if (!res)
+								res = wait_file(chan, ints, "digits/pt-sss", lang);
+					}
+					if (!res)
+						res = ast_say_number(chan, (tm.tm_hour % 12), ints, lang, "f");
+				}
 				break;
 			case 'H':
 			case 'k':
 				/* 24-Hour */
-				if (format[offset] == 'H') {
-					/* e.g. oh-eight */
-					if (tm.tm_hour < 10) {
-						res = wait_file(chan,ints, "digits/oh",lang);
-					}
-				} else {
-					/* e.g. eight */
-					if (tm.tm_hour == 0) {
-						res = wait_file(chan,ints, "digits/oh",lang);
-					}
-				}
+				res = ast_say_number(chan, -tm.tm_hour, ints, lang, NULL);
 				if (!res) {
 					if (tm.tm_hour != 0) {
 						int remainder = tm.tm_hour;
@@ -1440,39 +1926,22 @@ int ast_say_date_with_format(struct ast_channel *chan, time_t time, char *ints,
 			case 'M':
 				/* Minute */
 				if (tm.tm_min == 0) {
-					res = wait_file(chan,ints, "digits/oclock",lang);
-				} else if (tm.tm_min < 10) {
-					res = wait_file(chan,ints, "digits/oh",lang);
-					if (!res) {
-						snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min);
-						res = wait_file(chan,ints,nextmsg,lang);
-					}
-				} else if ((tm.tm_min < 21) || (tm.tm_min % 10 == 0)) {
-					snprintf(nextmsg,sizeof(nextmsg), "digits/%d", tm.tm_min);
-					res = wait_file(chan,ints,nextmsg,lang);
-				} else {
-					int ten, one;
-					ten = (tm.tm_min / 10) * 10;
-					one = (tm.tm_min % 10);
-					snprintf(nextmsg,sizeof(nextmsg), "digits/%d", ten);
-					res = wait_file(chan,ints,nextmsg,lang);
-					if (!res) {
-						/* Fifty, not fifty-zero */
-						if (one != 0) {
-							snprintf(nextmsg,sizeof(nextmsg), "digits/%d", one);
-							res = wait_file(chan,ints,nextmsg,lang);
-						}
-					}
+					res = wait_file(chan, ints, "digits/pt-hora", lang);
+					if (tm.tm_hour != 1)
+						if (!res)
+							res = wait_file(chan, ints, "digits/pt-sss", lang);			} else {
+					res = wait_file(chan,ints,"digits/pt-e",lang);
+					if (!res)
+						res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL);	
 				}
 				break;
 			case 'P':
 			case 'p':
 				/* AM/PM */
-				if (tm.tm_hour > 11)
-					snprintf(nextmsg,sizeof(nextmsg), "digits/p-m");
-				else
-					snprintf(nextmsg,sizeof(nextmsg), "digits/a-m");
-				res = wait_file(chan,ints,nextmsg,lang);
+				if (tm.tm_hour > 12)
+					res = wait_file(chan, ints, "digits/p-m", lang);
+				else if (tm.tm_hour  && tm.tm_hour < 12)
+					res = wait_file(chan, ints, "digits/a-m", lang);
 				break;
 			case 'Q':
 				/* Shorthand for "Today", "Yesterday", or ABdY */
@@ -1493,7 +1962,7 @@ int ast_say_date_with_format(struct ast_channel *chan, time_t time, char *ints,
 						/* Yesterday */
 						res = wait_file(chan,ints, "digits/yesterday",lang);
 					} else {
-						res = ast_say_date_with_format(chan, time, ints, lang, "ABdY", timezone);
+						res = ast_say_date_with_format(chan, time, ints, lang, "Ad 'digits/pt-de' B 'digits/pt-de' Y", timezone);
 					}
 				}
 				break;
@@ -1518,12 +1987,12 @@ int ast_say_date_with_format(struct ast_channel *chan, time_t time, char *ints,
 						/* Within the last week */
 						res = ast_say_date_with_format(chan, time, ints, lang, "A", timezone);
 					} else {
-						res = ast_say_date_with_format(chan, time, ints, lang, "ABdY", timezone);
+						res = ast_say_date_with_format(chan, time, ints, lang, "Ad 'digits/pt-de' B 'digits/pt-de' Y", timezone);
 					}
 				}
 				break;
 			case 'R':
-				res = ast_say_date_with_format(chan, time, ints, lang, "HM", timezone);
+				res = ast_say_date_with_format(chan, time, ints, lang, "H 'digits/pt-e' M", timezone);
 				break;
 			case 'S':
 				/* Seconds */
@@ -1574,6 +2043,21 @@ int ast_say_date_with_format(struct ast_channel *chan, time_t time, char *ints,
 }
 
 int ast_say_time(struct ast_channel *chan, time_t t, char *ints, char *lang)
+{
+	if (!strcasecmp(lang, "en") ) {	/* English syntax */
+		return(ast_say_time_en(chan, t, ints, lang));
+	} else if (!strcasecmp(lang, "nl") ) {	/* Dutch syntax */
+		return(ast_say_time_nl(chan, t, ints, lang));
+	} else if (!strcasecmp(lang, "pt") ) {	/* Portuguese syntax */
+		return(ast_say_time_pt(chan, t, ints, lang));
+	}
+
+	/* Default to English */
+	return(ast_say_time_en(chan, t, ints, lang));
+}
+
+/* English syntax */
+int ast_say_time_en(struct ast_channel *chan, time_t t, char *ints, char *lang)
 {
 	struct tm tm;
 	int res = 0;
@@ -1596,14 +2080,14 @@ int ast_say_time(struct ast_channel *chan, time_t t, char *ints, char *lang)
 			res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL);
 	} else if (tm.tm_min) {
 		if (!res)
-			res = ast_streamfile(chan, "digits/oh", lang);	/* This is very english ! */
+			res = ast_streamfile(chan, "digits/oh", lang);
 		if (!res)
 			res = ast_waitstream(chan, ints);
 		if (!res)
 			res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL);
 	} else {
 		if (!res)
-			res = ast_streamfile(chan, "digits/oclock", lang);	/* This is very english ! */
+			res = ast_streamfile(chan, "digits/oclock", lang);
 		if (!res)
 			res = ast_waitstream(chan, ints);
 	}
@@ -1619,7 +2103,152 @@ int ast_say_time(struct ast_channel *chan, time_t t, char *ints, char *lang)
 	return res;
 }
 
+/* Dutch syntax */
+int ast_say_time_nl(struct ast_channel *chan, time_t t, char *ints, char *lang)
+{
+	struct tm tm;
+	int res = 0;
+	int hour;
+	localtime_r(&t,&tm);
+	hour = tm.tm_hour;
+	if (!res)
+		res = ast_say_number(chan, hour, ints, lang, (char *) NULL);
+
+	if (!res)
+		res = ast_streamfile(chan, "digits/nl-uur", lang);
+	if (!res)
+		res = ast_waitstream(chan, ints);
+	if (!res)
+	    if (tm.tm_min > 0) 
+		res = ast_say_number(chan, tm.tm_min, ints, lang, NULL);
+	return res;
+}
+
+/* Portuguese syntax */
+int ast_say_time_pt(struct ast_channel *chan, time_t t, char *ints, char *lang)
+{
+	struct tm tm;
+	int res = 0;
+	int hour;
+	localtime_r(&t,&tm);
+	hour = tm.tm_hour;
+	if (!res)
+		res = ast_say_number(chan, hour, ints, lang, "f");
+	if (tm.tm_min) {
+		if (!res)
+			res = wait_file(chan, ints, "digits/pt-e", lang);
+		if (!res)
+			res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL);
+	} else {
+		if (!res)
+			res = wait_file(chan, ints, "digits/pt-hora", lang);
+		if (tm.tm_hour != 1)
+			if (!res)
+				res = wait_file(chan, ints, "digits/pt-sss", lang);
+	}
+	if (!res)
+		res = ast_say_number(chan, hour, ints, lang, (char *) NULL);
+	return res;
+}
+
 int ast_say_datetime(struct ast_channel *chan, time_t t, char *ints, char *lang)
+{
+	if (!strcasecmp(lang, "en") ) {	/* English syntax */
+		return(ast_say_datetime_en(chan, t, ints, lang));
+	} else if (!strcasecmp(lang, "nl") ) {	/* Dutch syntax */
+		return(ast_say_datetime_nl(chan, t, ints, lang));
+	} else if (!strcasecmp(lang, "pt") ) {	/* Portuguese syntax */
+		return(ast_say_datetime_pt(chan, t, ints, lang));
+	}
+
+	/* Default to English */
+	return(ast_say_datetime_en(chan, t, ints, lang));
+}
+
+/* English syntax */
+int ast_say_datetime_en(struct ast_channel *chan, time_t t, char *ints, char *lang)
+{
+	struct tm tm;
+	char fn[256];
+	int res = 0;
+	int hour, pm=0;
+	localtime_r(&t,&tm);
+	if (!res) {
+		snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
+		res = ast_streamfile(chan, fn, lang);
+		if (!res)
+			res = ast_waitstream(chan, ints);
+	}
+	if (!res) {
+		snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
+		res = ast_streamfile(chan, fn, lang);
+		if (!res)
+			res = ast_waitstream(chan, ints);
+	}
+	if (!res)
+		res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL);
+
+	hour = tm.tm_hour;
+	if (!hour)
+		hour = 12;
+	else if (hour == 12)
+		pm = 1;
+	else if (hour > 12) {
+		hour -= 12;
+		pm = 1;
+	}
+	if (!res)
+		res = ast_say_number(chan, hour, ints, lang, (char *) NULL);
+
+	if (tm.tm_min > 9) {
+		if (!res)
+			res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL);
+	} else if (tm.tm_min) {
+		if (!res)
+			res = ast_streamfile(chan, "digits/oh", lang);
+		if (!res)
+			res = ast_waitstream(chan, ints);
+		if (!res)
+			res = ast_say_number(chan, tm.tm_min, ints, lang, (char *) NULL);
+	} else {
+		if (!res)
+			res = ast_streamfile(chan, "digits/oclock", lang);
+		if (!res)
+			res = ast_waitstream(chan, ints);
+	}
+	if (pm) {
+		if (!res)
+			res = ast_streamfile(chan, "digits/p-m", lang);
+	} else {
+		if (!res)
+			res = ast_streamfile(chan, "digits/a-m", lang);
+	}
+	if (!res)
+		res = ast_waitstream(chan, ints);
+	if (!res)
+		res = ast_say_number(chan, tm.tm_year + 1900, ints, lang, (char *) NULL);
+	return res;
+}
+
+/* Dutch syntax */
+int ast_say_datetime_nl(struct ast_channel *chan, time_t t, char *ints, char *lang)
+{
+	struct tm tm;
+	int res = 0;
+	localtime_r(&t,&tm);
+	res = ast_say_date(chan, t, ints, lang);
+	if (!res) {
+		res = ast_streamfile(chan, "digits/nl-om", lang);
+		if (!res)
+			res = ast_waitstream(chan, ints);
+	}
+	if (!res) 
+		ast_say_time(chan, t, ints, lang);
+	return res;
+}
+
+/* Portuguese syntax */
+int ast_say_datetime_pt(struct ast_channel *chan, time_t t, char *ints, char *lang)
 {
 	struct tm tm;
 	char fn[256];
@@ -1684,6 +2313,19 @@ int ast_say_datetime(struct ast_channel *chan, time_t t, char *ints, char *lang)
 }
 
 int ast_say_datetime_from_now(struct ast_channel *chan, time_t t, char *ints, char *lang)
+{
+	if (!strcasecmp(lang, "en") ) {	/* English syntax */
+		return(ast_say_datetime_from_now_en(chan, t, ints, lang));
+	} else if (!strcasecmp(lang, "pt") ) {	/* Portuguese syntax */
+		return(ast_say_datetime_from_now_pt(chan, t, ints, lang));
+	}
+
+	/* Default to English */
+	return(ast_say_datetime_from_now_en(chan, t, ints, lang));
+}
+
+/* English syntax */
+int ast_say_datetime_from_now_en(struct ast_channel *chan, time_t t, char *ints, char *lang)
 {
 	int res=0;
 	time_t nowt;
@@ -1722,3 +2364,44 @@ int ast_say_datetime_from_now(struct ast_channel *chan, time_t t, char *ints, ch
 	return res;
 }
 
+/* Portuguese syntax */
+int ast_say_datetime_from_now_pt(struct ast_channel *chan, time_t t, char *ints, char *lang)
+{
+	int res=0;
+	time_t nowt;
+	int daydiff;
+	struct tm tm;
+	struct tm now;
+	char fn[256];
+
+	time(&nowt);
+
+	localtime_r(&t,&tm);
+	localtime_r(&nowt,&now);
+	daydiff = now.tm_yday - tm.tm_yday;
+	if ((daydiff < 0) || (daydiff > 6)) {
+		/* Day of month and month */
+		if (!res)
+			res = ast_say_number(chan, tm.tm_mday, ints, lang, (char *) NULL);
+		if (!res)
+			res = wait_file(chan, ints, "digits/pt-de", lang);
+		snprintf(fn, sizeof(fn), "digits/mon-%d", tm.tm_mon);
+		if (!res)
+			res = wait_file(chan, ints, fn, lang);
+	
+	} else if (daydiff) {
+		/* Just what day of the week */
+		snprintf(fn, sizeof(fn), "digits/day-%d", tm.tm_wday);
+		if (!res)
+			res = wait_file(chan, ints, fn, lang);
+	}	/* Otherwise, it was today */
+	snprintf(fn, sizeof(fn), "digits/pt-ah");
+	if (!res)
+		res = wait_file(chan, ints, fn, lang);
+	if (tm.tm_hour != 1)
+	if (!res)
+		res = wait_file(chan, ints, "digits/pt-sss", lang);
+	if (!res)
+		res = ast_say_time(chan, t, ints, lang);
+	return res;
+}