Index: apps/Makefile
===================================================================
RCS file: /usr/cvsroot/asterisk/apps/Makefile,v
retrieving revision 1.50
diff -u -r1.50 Makefile
--- apps/Makefile	12 Jan 2004 01:56:38 -0000	1.50
+++ apps/Makefile	26 Mar 2004 14:25:34 -0000
@@ -25,7 +25,7 @@
      app_waitforring.so app_privacy.so app_db.so app_chanisavail.so \
      app_enumlookup.so app_transfer.so app_setcidnum.so app_cdr.so \
      app_hasnewvoicemail.so app_sayunixtime.so app_cut.so app_read.so \
-     app_setcdruserfield.so app_random.so
+     app_setcdruserfield.so app_random.so app_waitforring2.so
 
 ifneq (${OSARCH},Darwin)
 APPS+=app_intercom.so
Index: cdr/Makefile
===================================================================
RCS file: /usr/cvsroot/asterisk/cdr/Makefile,v
retrieving revision 1.21
diff -u -r1.21 Makefile
--- cdr/Makefile	23 Jan 2004 15:43:31 -0000	1.21
+++ cdr/Makefile	26 Mar 2004 14:25:35 -0000
@@ -26,12 +26,13 @@
 #
 # PGSQL stuff...  Autoconf anyone??
 #
-MODS+=$(shell if [ -d /usr/local/pgsql/include ] || [ -d /usr/include/pgsql ] || [ -d /usr/local/include/pgsql ] || [ -d /opt/pgsql/include ] || [ -f /usr/include/libpq-fe.h ] ; then echo "cdr_pgsql.so"; fi)
+MODS+=$(shell if [ -d /usr/local/pgsql/include ] || [ -d /usr/include/pgsql ] || [ -d /usr/local/include/pgsql ] || [ -d /opt/pgsql/include ] || [ -f /usr/include/libpq-fe.h ] || [ -d /usr/pgsql/include ]; then echo "cdr_pgsql.so"; fi)
 CFLAGS+=$(shell if [ -d /usr/local/pgsql/include ]; then echo "-I/usr/local/pgsql/include"; fi)
 CFLAGS+=$(shell if [ -d /usr/include/pgsql ]; then echo "-I/usr/include/pgsql"; fi)
 CFLAGS+=$(shell if [ -d /usr/include/postgresql ]; then echo "-I/usr/include/postgresql"; fi)
 CFLAGS+=$(shell if [ -d /usr/local/include/pgsql ]; then echo "-I/usr/local/include/pgsql"; fi)
 CFLAGS+=$(shell if [ -d /opt/pgsql/include ]; then echo "-I/opt/pgsql/include"; fi)
+CFLAGS+=$(shell if [ -d /usr/pgsql/include ]; then echo "-I/usr/pgsql/include"; fi)
 #CFLAGS+=$(shell if [ -f /usr/include/libpq-fe.h ]; then echo "-I/usr/include"; fi)
 MLFLAGS=
 MLFLAGS+=$(shell if [ -d /usr/lib/pgsql ]; then echo "-L/usr/lib/pgsql"; fi)
@@ -39,6 +40,7 @@
 MLFLAGS+=$(shell if [ -d /usr/local/lib/pgsql ]; then echo "-L/usr/local/lib/pgsql"; fi)
 MLFLAGS+=$(shell if [ -d /opt/pgsql/lib ]; then echo "-L/opt/pgsql/lib"; fi)
 MLFLAGS+=$(shell if [ -f /usr/lib/libpq.so ]; then echo "-L/usr/lib"; fi)
+MLFLAGS+=$(shell if [ -d /usr/pgsql/lib ]; then echo "-L/usr/pgsql/lib"; fi)
 
 all: depend $(MODS)
 
Index: channels/chan_vpb.c
===================================================================
RCS file: /usr/cvsroot/asterisk/channels/chan_vpb.c,v
retrieving revision 1.12
diff -u -r1.12 chan_vpb.c
--- channels/chan_vpb.c	9 Dec 2003 23:55:17 -0000	1.12
+++ channels/chan_vpb.c	26 Mar 2004 14:25:53 -0000
@@ -41,7 +41,7 @@
 #define VPB_NULL_EVENT 200
 
 #define VPB_DIALTONE_WAIT 2000
-#define VPB_RINGWAIT 2000
+#define VPB_RINGWAIT 6000
 #define VPB_WAIT_TIMEOUT 40
 
 #if defined(__cplusplus) || defined(c_plusplus)
@@ -97,9 +97,9 @@
 #define MODE_FXO	3
 
 
-static VPB_TONE Dialtone     = {440, 440, 440, 0,  0, 0, 5000, 0   };
-static VPB_TONE Busytone     = {440,   0,   0, 0,  -100, -100,   500, 500};
-static VPB_TONE Ringbacktone = {440,   0,   0, 0,  -100, -100,  100, 100};
+static VPB_TONE Dialtone     = {425, 425, 0, -12,  -12, -12, 600, 1000 };
+static VPB_TONE Busytone     = {425, 425, 0, -12,  -12, -12, 500, 500  };
+static VPB_TONE Ringbacktone = {425, 0, 0, -12,  -12, -12, 650, 0  };
 
 
 #define VPB_MAX_BRIDGES 128 
@@ -113,6 +113,17 @@
      pthread_cond_t cond;
 } bridges[VPB_MAX_BRIDGES]; /* Bridges...*/
 
+/* Filippo Dattola 20/02/04 size of buffer to store CID signal in (may need to be adjusted) */
+
+#define CIDN (8000*4)
+
+typedef struct {
+	int   h;
+        short buf[CIDN];
+} THREAD_INFO;
+
+void *rec_thread(void *pv);
+
 static ast_mutex_t bridge_lock = AST_MUTEX_INITIALIZER;
 
 static struct vpb_pvt {
@@ -375,8 +386,10 @@
           
      switch(e->type) {
      case VPB_RING:
-	  if (p->mode == MODE_FXO) /* FXO port ring, start * */
-	       vpb_new(p, AST_STATE_RING, p->context);
+	  if (p->mode == MODE_FXO) {
+		/* FXO port ring, start * */
+	        vpb_new(p, AST_STATE_RING, p->context);
+	  }
 	  break;
      case VPB_STATION_OFFHOOK:
 	  if (p->mode == MODE_IMMEDIATE) 
@@ -441,6 +454,12 @@
     
      /* Monitor thread, doesn't die until explicitly killed. */
      
+     int ringcid = 0;
+     int ret;
+     THREAD_INFO ti;
+     pthread_t   thread;
+     char cid_str[VPB_MAX_STR];
+     
      if (option_verbose > 4) 
 	  ast_verbose(VERBOSE_PREFIX_3 "Starting vpb monitor thread[%ld]\n",
 		      pthread_self());
@@ -479,12 +498,24 @@
 	       
 	       
 	       /* Two scenarios: Are you owned or not. */
-	       
-	       if (p->owner) 
-			monitor_handle_owned(p, &e);
-	       else 
-		    monitor_handle_notowned(p, &e);
-	       
+	       /* Filippo Dattola 20/02/04 - decode CID */
+	       if (p->owner) { 
+		       monitor_handle_owned(p, &e);
+	       } else if(e.type == VPB_RING && ringcid == 0) {
+		       ast_log(LOG_WARNING,"First ring: %d\n",ringcid);
+		       ringcid++;
+		       ti.h = p->handle;
+	      	       pthread_create(&thread, NULL, rec_thread, (void*)&ti);
+	       } else if(e.type == VPB_RING && ringcid == 1) {
+		       ast_log(LOG_WARNING,"Second ring: %d\n",ringcid);
+		       vpb_record_terminate(ti.h);
+		       ret = vpb_cid_decode(cid_str, ti.buf, CIDN);
+		       ast_log(LOG_WARNING,"CID decoding: '%d'-'%s'\n",ret,cid_str);
+		       strcpy(p->callerid,cid_str);
+		       monitor_handle_notowned(p, &e);
+		       ringcid = 0;
+	       } else monitor_handle_notowned(p, &e);
+		    
 	       done: (void)0;
 	  } ast_mutex_unlock(&iflock);
 	  ast_mutex_unlock(&monlock);
@@ -498,6 +529,20 @@
      return NULL;
 }
 
+// Records CID samples to a buffer
+
+void *rec_thread(void *pv) {
+   THREAD_INFO *ti = (THREAD_INFO*)pv;
+
+   // record buffer of samples between rings
+
+   vpb_record_buf_start(ti->h, VPB_LINEAR);
+   vpb_record_buf_sync(ti->h, (char*)ti->buf, sizeof(short)*CIDN);
+   vpb_record_buf_finish(ti->h);
+
+   return(NULL);
+}
+
 static int restart_monitor(void)
 {
      int error = 0;
Index: pbx/pbx_spool.c
===================================================================
RCS file: /usr/cvsroot/asterisk/pbx/pbx_spool.c,v
retrieving revision 1.5.2.2
diff -u -r1.5.2.2 pbx_spool.c
--- pbx/pbx_spool.c	20 Mar 2004 21:13:30 -0000	1.5.2.2
+++ pbx/pbx_spool.c	26 Mar 2004 14:25:56 -0000
@@ -22,6 +22,7 @@
 #include <sys/stat.h>
 #include <errno.h>
 #include <time.h>
+#include <sys/time.h>
 #include <utime.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -30,6 +31,7 @@
 #include <string.h>
 #include <stdio.h>
 #include <unistd.h>
+#include <ctype.h>
 #include "../astconf.h"
 
 /*
@@ -74,11 +76,315 @@
 	/* Account code */
 	char account[256];
 	
+	/* Date - Time validity */
+	int hastime;
+	unsigned int monthmask;
+	unsigned int daymask;
+	unsigned int dowmask;
+	unsigned int minmask[24];
+	
 	/* Maximum length of call */
 	int maxlen;
 	
 };
 
+#define FIND_NEXT \
+do { \
+	c = info; \
+	while(*c && (*c != '|')) c++; \
+	if (*c) { *c = '\0'; c++; } else c = NULL; \
+} while(0)
+
+static void get_timerange(struct outgoing *i, char *times)
+{
+	char *e;
+	int x;
+	int s1, s2;
+	int e1, e2;
+
+	//[PHM 07/01/03]
+	//start disabling all times, fill the fields with 0's, as they may contain garbage
+	memset(i->minmask, 0, sizeof(i->minmask));
+	
+	/* Star is all times */
+	if (!strlen(times) || !strcmp(times, "*")) {
+		for (x=0;x<24;x++)
+			i->minmask[x] = (1 << 30) - 1;
+		return;
+	}
+	/* Otherwise expect a range */
+	e = strchr(times, '-');
+	if (!e) {
+		ast_log(LOG_WARNING, "Time range is not valid. Assuming no time.\n");
+		return;
+	}
+	*e = '\0';
+	e++;
+	while(*e && !isdigit(*e)) e++;
+	if (!*e) {
+		ast_log(LOG_WARNING, "Invalid time range.  Assuming no time.\n");
+		return;
+	}
+	if (sscanf(times, "%d:%d", &s1, &s2) != 2) {
+		ast_log(LOG_WARNING, "%s isn't a time.  Assuming no time.\n", times);
+		return;
+	}
+	if (sscanf(e, "%d:%d", &e1, &e2) != 2) {
+		ast_log(LOG_WARNING, "%s isn't a time.  Assuming no time.\n", e);
+		return;
+	}
+	s1 = s1 * 30 + s2/2;
+	if ((s1 < 0) || (s1 >= 24*30)) {
+		ast_log(LOG_WARNING, "%s isn't a valid star time. Assuming no time.\n", times);
+		return;
+	}
+	e1 = e1 * 30 + e2/2;
+	if ((e1 < 0) || (e2 >= 24*30)) {
+		ast_log(LOG_WARNING, "%s isn't a valid start time. Assuming no time.\n", times);
+		return;
+	}
+	/* Go through the time and enable each appropriate bit */
+	for (x=s1;x != e1;x = (x + 1) % (24 * 30)) {
+		i->minmask[x/30] |= (1 << (x % 30));
+	}
+	/* Do the last one */
+	i->minmask[x/30] |= (1 << (x % 30));
+	/* All done */
+	return;
+}
+
+static char *days[] =
+{
+	"sun",
+	"mon",
+	"tue",
+	"wed",
+	"thu",
+	"fri",
+	"sat",
+};
+
+static unsigned int get_dow(char *dow)
+{
+	char *c;
+	/* The following line is coincidence, really! */
+	int s, e, x;
+	unsigned int mask;
+	/* Check for all days */
+	if (!strlen(dow) || !strcmp(dow, "*"))
+		return (1 << 7) - 1;
+	/* Get start and ending days */
+	c = strchr(dow, '-');
+	if (c) {
+		*c = '\0';
+		c++;
+	} else
+		c = NULL;
+	/* Find the start */
+	s = 0;
+	while((s < 7) && strcasecmp(dow, days[s])) s++;
+	if (s >= 7) {
+		ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", dow);
+		return 0;
+	}
+	if (c) {
+		e = 0;
+		while((e < 7) && strcasecmp(c, days[e])) e++;
+		if (e >= 7) {
+			ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
+			return 0;
+		}
+	} else
+		e = s;
+	mask = 0;
+	for (x=s;x!=e;x = (x + 1) % 7) {
+		mask |= (1 << x);
+	}
+	/* One last one */
+	mask |= (1 << x);
+	return mask;
+}
+
+static unsigned int get_day(char *day)
+{
+	char *c;
+	/* The following line is coincidence, really! */
+	int s, e, x;
+	unsigned int mask;
+	/* Check for all days */
+	if (!strlen(day) || !strcmp(day, "*")) {
+		mask = (1 << 30)  + ((1 << 30) - 1);
+		return mask;
+	}
+	/* Get start and ending days */
+	c = strchr(day, '-');
+	if (c) {
+		*c = '\0';
+		c++;
+	}
+	/* Find the start */
+	if (sscanf(day, "%d", &s) != 1) {
+		ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
+		return 0;
+	}
+	if ((s < 1) || (s > 31)) {
+		ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", day);
+		return 0;
+	}
+	s--;
+	if (c) {
+		if (sscanf(c, "%d", &e) != 1) {
+			ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
+			return 0;
+		}
+		if ((e < 1) || (e > 31)) {
+			ast_log(LOG_WARNING, "Invalid day '%s', assuming none\n", c);
+			return 0;
+		}
+		e--;
+	} else
+		e = s;
+	mask = 0;
+	for (x=s;x!=e;x = (x + 1) % 31) {
+		mask |= (1 << x);
+	}
+	mask |= (1 << x);
+	return mask;
+}
+
+static char *months[] =
+{
+	"jan",
+	"feb",
+	"mar",
+	"apr",
+	"may",
+	"jun",
+	"jul",
+	"aug",
+	"sep",
+	"oct",
+	"nov",
+	"dec",
+};
+
+static unsigned int get_month(char *mon)
+{
+	char *c;
+	/* The following line is coincidence, really! */
+	int s, e, x;
+	unsigned int mask;
+	/* Check for all days */
+	if (!strlen(mon) || !strcmp(mon, "*")) 
+		return (1 << 12) - 1;
+	/* Get start and ending days */
+	c = strchr(mon, '-');
+	if (c) {
+		*c = '\0';
+		c++;
+	}
+	/* Find the start */
+	s = 0;
+	while((s < 12) && strcasecmp(mon, months[s])) s++;
+	if (s >= 12) {
+		ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", mon);
+		return 0;
+	}
+	if (c) {
+		e = 0;
+		while((e < 12) && strcasecmp(mon, months[e])) e++;
+		if (e >= 12) {
+			ast_log(LOG_WARNING, "Invalid month '%s', assuming none\n", c);
+			return 0;
+		}
+	} else
+		e = s;
+	mask = 0;
+	for (x=s;x!=e;x = (x + 1) % 12) {
+		mask |= (1 << x);
+	}
+	/* One last one */
+	mask |= (1 << x);
+	return mask;
+}
+
+/* check datetime with current time */
+
+static int date_check(struct outgoing *i)
+{
+	struct tm tm;
+	time_t t;
+	if (!i->hastime)
+		return 1;
+	time(&t);
+	localtime_r(&t,&tm);
+
+	/* If it's not the right month, return */
+	if (!(i->monthmask & (1 << tm.tm_mon))) {
+		return 0;
+	}
+
+	/* If it's not that time of the month.... */
+	/* Warning, tm_mday has range 1..31! */
+	if (!(i->daymask & (1 << (tm.tm_mday-1))))
+		return 0;
+
+	/* If it's not the right day of the week */
+	if (!(i->dowmask & (1 << tm.tm_wday)))
+	        return 0;
+
+	/* Sanity check the hour just to be safe */
+	if ((tm.tm_hour < 0) || (tm.tm_hour > 23)) {
+		ast_log(LOG_WARNING, "Insane time...\n");
+		return 0;
+	}
+
+	/* Now the tough part, we calculate if it fits
+	 *            in the right time based on min/hour */
+	if (!(i->minmask[tm.tm_hour] & (1 << (tm.tm_min / 2))))
+	        return 0;
+
+	/* If we got this far, then we're good */
+	return 1;
+}
+
+/* load the value of data in the struct outgoing */
+
+static void build_time(struct outgoing *i, char *info)
+{
+	char *c;
+	/* Check for empty just in case */
+	if (!strlen(info))
+		return;
+	i->hastime = 1;
+	/* Assume everything except time */
+	i->monthmask = (1 << 12) - 1;
+	i->daymask = (1 << 30) - 1 + (1 << 30);
+	i->dowmask = (1 << 7) - 1;
+	/* Avoid using str tok */
+	FIND_NEXT;
+	/* Info has the time range, start with that */
+	get_timerange(i, info);
+	info = c;
+	if (!info)
+		return;
+	FIND_NEXT;
+	/* Now check for day of week */
+	i->dowmask = get_dow(info);
+	info = c;
+	if (!info)
+		return;
+	FIND_NEXT;
+	/* Now check for the day of the month */
+	i->daymask = get_day(info);
+	info = c;
+	if (!info)
+		return;
+	FIND_NEXT;
+	/* And finally go for the month */
+	i->monthmask = get_month(info);
+}
+
 static void init_outgoing(struct outgoing *o)
 {
 	memset(o, 0, sizeof(struct outgoing));
@@ -165,14 +471,19 @@
 							o->callingpid = 0;
 						}
 					} else if (!strcasecmp(buf, "endretry") || !strcasecmp(buf, "abortretry")) {
+						/* if reason is channel not available, don't increase retry */
 						o->callingpid = 0;
-						o->retries++;
+						if (*c != '0') o->retries++;
 					} else if (!strcasecmp(buf, "setvar")) { /* JDG variable support */
 						strncat(o->variable, c, sizeof(o->variable) - strlen(o->variable) - 1);
 						strncat(o->variable, "|", sizeof(o->variable) - strlen(o->variable) - 1);
  
 					} else if (!strcasecmp(buf, "account")) {
 						strncpy(o->account, c, sizeof(o->account) - 1);
+					} else if (!strcasecmp(buf, "datetime")) {
+						c2 = strchr(c, '|');
+						*c2 = '\0';
+						build_time(o, c);
 					} else {
 						ast_log(LOG_WARNING, "Unknown keyword '%s' at line %d of %s\n", buf, lineno, fn);
 					}
@@ -211,6 +522,7 @@
 {
 	struct outgoing *o = data;
 	int res, reason;
+	char *endretry;
 	if (strlen(o->app)) {
 		if (option_verbose > 2)
 			ast_verbose(VERBOSE_PREFIX_3 "Attempting call on %s/%s for application %s(%s) (Retry %d)\n", o->tech, o->dest, o->app, o->data, o->retries);
@@ -228,7 +540,9 @@
 			unlink(o->fn);
 		} else {
 			/* Notate that the call is still active */
-			safe_append(o, time(NULL), "EndRetry");
+			/* Attach reason of failure to EndRetry */
+			sprintf(endretry,"EndRetry: %d",reason);
+			safe_append(o, time(NULL), endretry);
 		}
 	} else {
 		ast_log(LOG_NOTICE, "Call completed to %s/%s\n", o->tech, o->dest);
@@ -275,12 +589,20 @@
 						   so abort their retry and continue as we were... */
 						if (o->callingpid)
 							safe_append(o, time(NULL), "AbortRetry");
-							
-						/* Add a retry line at the end */
-						fseek(f, 0L, SEEK_END);
-						fprintf(f, "StartRetry: %d %d (%ld)\n", ast_mainpid, o->retries, (long) now);
-						fclose(f);
-						launch_service(o);
+						
+					 	/* if the datetime is not ok, don't increase the retry and don't try to call */
+						
+						if(!date_check(o)) {
+							ast_log(LOG_NOTICE, "Don't CALL in this Date/Time! (Retry %d)\n",o->retries);
+							fclose(f);
+							safe_append(o, time(NULL), "EndRetry: 0");
+						} else {
+							/* Add a retry line at the end */
+							fseek(f, 0L, SEEK_END);
+							fprintf(f, "StartRetry: %d %d (%ld)\n", ast_mainpid, o->retries, (long) now);
+							fclose(f);
+							launch_service(o);
+						}
 					}
 					/* Update the file time */
 					tbuf.actime = atime;
