2
0
Эх сурвалжийг харах

modules/tmrec: Ported Perl's Time::Period module.

- Make Time::Period (http://search.cpan.org/~pryan/Period-1.20/Period.pm)
  available as native C implementation.

Author: Richard Fuchs <[email protected]>
Andreas Granig 13 жил өмнө
parent
commit
1810746263

+ 71 - 1
modules/tmrec/README

@@ -37,12 +37,14 @@ Alex Balashov
 
 
               4.1. tmrec_match(timerec [, timestamp])
               4.1. tmrec_match(timerec [, timestamp])
               4.2. is_leap_year([year])
               4.2. is_leap_year([year])
+              4.3. time_period_match(period [, timestamp])
 
 
    List of Examples
    List of Examples
 
 
    1.1. Set separator parameter
    1.1. Set separator parameter
    1.2. tmrec_match usage
    1.2. tmrec_match usage
    1.3. is_leap_year usage
    1.3. is_leap_year usage
+   1.4. time_period_match usage
 
 
 Chapter 1. Admin Guide
 Chapter 1. Admin Guide
 
 
@@ -62,12 +64,14 @@ Chapter 1. Admin Guide
 
 
         4.1. tmrec_match(timerec [, timestamp])
         4.1. tmrec_match(timerec [, timestamp])
         4.2. is_leap_year([year])
         4.2. is_leap_year([year])
+        4.3. time_period_match(period [, timestamp])
 
 
 1. Overview
 1. Overview
 
 
    This module provides time recurrence matching functions. The format of
    This module provides time recurrence matching functions. The format of
    recurrence definitions is based on Internet Calendaring and Scheduling
    recurrence definitions is based on Internet Calendaring and Scheduling
-   Core Object Specification (Calendar COS - RFC 2445).
+   Core Object Specification (Calendar COS - RFC 2445). It also provides a
+   port of the Perl Time::Period module for generic time period matching.
 
 
 2. Dependencies
 2. Dependencies
 
 
@@ -105,6 +109,7 @@ modparam("tmrec", "separator", ";")
 
 
    4.1. tmrec_match(timerec [, timestamp])
    4.1. tmrec_match(timerec [, timestamp])
    4.2. is_leap_year([year])
    4.2. is_leap_year([year])
+   4.3. time_period_match(period [, timestamp])
 
 
 4.1.  tmrec_match(timerec [, timestamp])
 4.1.  tmrec_match(timerec [, timestamp])
 
 
@@ -236,3 +241,68 @@ modparam("tmrec", "separator", ";")
 ...
 ...
 if(is_leap_year("2010"))
 if(is_leap_year("2010"))
 ...
 ...
+
+4.3.  time_period_match(period [, timestamp])
+
+   Matches the point in time specified by the timestamp parameter, or the
+   current time if the parameter is missing, against the given period
+   specification. Returns 1 if it matches, -1 if it doesn't, and a value
+   <= -2 if there was an error.
+
+   The time period specification follows the Perl Time::Period module. It
+   is a string and consists of zero or more sub-period specifications,
+   separated by commas. The period matches if at least one of the
+   sub-periods matches, or if no sub-periods were given at all (an empty
+   string).
+
+   Each sub-period is a list of one or more scale definitions, optionally
+   separated by space characters. The sub-period matches if all of the
+   given scales within that sub-period match. For each scale given, a
+   single value or a range of values (which is two values separated by a
+   hyphen) can be specified. Multiple values or multiple ranges (or a
+   combination thereof) within a single scale is also possible. If a
+   certain scale is specified more than once, the previous values or
+   ranges for that scale are extended by the newly given ones. If a
+   particular scale is not mentioned at all within a sub-period, then no
+   matching is performed for that scale.
+
+   The following scales are supported and understood. Each scale also has
+   a respective short code, either one can be used. A single scale
+   definition consists of the scale name, followed by an opening brace,
+   followed by the list of values, followed by a closing brace.
+     * year or yr - Either given as a full 4-digit number >= 1970, or as a
+       2-digit number, in which case it will be understood to be within
+       the current century.
+     * month or mo - Month of the year, either a number between 1 and 12,
+       or at least the first 3 letters of a spelled out month name, e.g.
+       “jan”, “janua” or “january” will all work.
+     * week or wk - Week of the month, a number between 1 and 6. The first
+       day of the week is Sunday.
+     * yday or yd - Day of the year, a number between 1 and 366.
+     * mday or md - Day of the month, a number between 1 and 31.
+     * wday or wd - Day of the week, either a number between 1 and 7, or
+       at least the first 2 letters of a spelled out weekday name
+       (analogous to the “month” scale). Sunday is the first day of the
+       week.
+     * hour or hr - A number between 0 and 23. Unlike the Perl
+       Time::Period module, “am” or “pm” specifications are not supported.
+     * minute or min - A number between 0 and 59.
+     * second or sec - A number between 0 and 60 (to allow for leap
+       seconds).
+
+   The parameters can include pseudo-variables. Whitespace (more
+   precisely, the space character only) can occur anywhere, but is
+   optional. Ranges in all scales (with the exception of the “year” scale)
+   are allowed to wrap-around, e.g. a weekday scale of “{fri-tue}” is
+   equivalent to “{fri-sat,sun-tue}”.
+
+   Example 1.4. time_period_match usage
+...
+if(time_period_match("wd{1-5} hr{8-16}, wd{1-5} hr{17} min{0-29}"))
+        xdbg("Monday to Friday, 8:00 to 17:30\n");
+
+if(time_period_match("weekday { sat sun }, weekday {mo-fr} hr {17-8},wd{mo-wed}h
+r{15 16 9}"))
+        xdbg("We're closed - open only Monday to Wednesday 10:00-15:00, Thursday
+ and Friday 9:00-17:00");
+...

+ 108 - 0
modules/tmrec/doc/tmrec_admin.xml

@@ -19,6 +19,8 @@
 		This module provides time recurrence matching functions. The format
 		This module provides time recurrence matching functions. The format
 		of recurrence definitions is based on Internet Calendaring and 
 		of recurrence definitions is based on Internet Calendaring and 
 		Scheduling Core Object Specification (Calendar COS - RFC 2445).
 		Scheduling Core Object Specification (Calendar COS - RFC 2445).
+		It also provides a port of the Perl Time::Period module for generic
+		time period matching.
 	</para>
 	</para>
 	</section>
 	</section>
 
 
@@ -301,6 +303,112 @@ modparam("tmrec", "separator", ";")
 ...
 ...
 if(is_leap_year("2010"))
 if(is_leap_year("2010"))
 ...
 ...
+</programlisting>
+	    </example>
+	</section>
+
+	<section>
+	    <title>
+		<function moreinfo="none">time_period_match(period [, timestamp])</function>
+	    </title>
+	    <para>
+			Matches the point in time specified by the timestamp parameter, or
+			the current time if the parameter is missing, against the given
+			period specification. Returns 1 if it matches, -1 if it doesn't,
+			and a value &lt;= -2 if there was an error.
+		</para>
+		<para>
+			The time period specification follows the Perl Time::Period module.
+			It is a string and consists of zero or more sub-period specifications,
+			separated by commas. The period matches if at least one of the
+			sub-periods matches, or if no sub-periods were given at all (an
+			empty string).
+		</para>
+		<para>
+			Each sub-period is a list of one or more scale definitions,
+			optionally separated by space characters. The sub-period matches if
+			all of the given scales within that sub-period match. For each scale
+			given, a single value or a range of values (which is two values
+			separated by a hyphen) can be specified. Multiple
+			values or multiple ranges (or a combination thereof) within a single
+			scale is also possible. If a certain scale is specified more than once,
+			the previous values or ranges for that scale are extended by the newly
+			given ones. If a particular scale is not mentioned at all within a
+			sub-period, then no matching is performed for that scale.
+		</para>
+		<para>
+			The following scales are supported and understood. Each scale also has
+			a respective short code, either one can be used. A single scale
+			definition consists of the scale name, followed by an opening brace,
+			followed by the list of values, followed by a closing brace.
+			<itemizedlist>
+				<listitem><para>
+					<emphasis>year</emphasis> or <emphasis>yr</emphasis>
+					- Either given as a full 4-digit number &gt;= 1970, or
+					as a 2-digit number, in which case it will be understood
+					to be within the current century.
+				</para></listitem>
+				<listitem><para>
+					<emphasis>month</emphasis> or <emphasis>mo</emphasis>
+					- Month of the year, either a number between 1 and 12,
+					or at least the first 3 letters of a spelled out month
+					name, e.g. <quote>jan</quote>, <quote>janua</quote>
+					or <quote>january</quote> will all work.
+				</para></listitem>
+				<listitem><para>
+					<emphasis>week</emphasis> or <emphasis>wk</emphasis>
+					- Week of the month, a number between 1 and 6. The
+					first day of the week is Sunday.
+				</para></listitem>
+				<listitem><para>
+					<emphasis>yday</emphasis> or <emphasis>yd</emphasis>
+					- Day of the year, a number between 1 and 366.
+				</para></listitem>
+				<listitem><para>
+					<emphasis>mday</emphasis> or <emphasis>md</emphasis>
+					- Day of the month, a number between 1 and 31.
+				</para></listitem>
+				<listitem><para>
+					<emphasis>wday</emphasis> or <emphasis>wd</emphasis>
+					- Day of the week, either a number between 1 and 7, or
+					at least the first 2 letters of a spelled out weekday
+					name (analogous to the <quote>month</quote> scale).
+					Sunday is the first day of the week.
+				</para></listitem>
+				<listitem><para>
+					<emphasis>hour</emphasis> or <emphasis>hr</emphasis>
+					- A number between 0 and 23. Unlike the Perl Time::Period
+					module, <quote>am</quote> or <quote>pm</quote>
+					specifications are not supported.
+				</para></listitem>
+				<listitem><para>
+					<emphasis>minute</emphasis> or <emphasis>min</emphasis>
+					- A number between 0 and 59.
+				</para></listitem>
+				<listitem><para>
+					<emphasis>second</emphasis> or <emphasis>sec</emphasis>
+					- A number between 0 and 60 (to allow for leap seconds).
+				</para></listitem>
+			</itemizedlist>
+		</para>
+		<para>
+			The parameters can include pseudo-variables. Whitespace (more
+			precisely, the space character only) can occur anywhere, but is
+			optional. Ranges in all scales (with the exception of the
+			<quote>year</quote> scale) are allowed to wrap-around, e.g. a weekday
+			scale of <quote>{fri-tue}</quote> is equivalent to
+			<quote>{fri-sat,sun-tue}</quote>.
+		</para>
+		<example>
+		<title><function>time_period_match</function> usage</title>
+		<programlisting format="linespecific">
+...
+if(time_period_match("wd{1-5} hr{8-16}, wd{1-5} hr{17} min{0-29}"))
+	xdbg("Monday to Friday, 8:00 to 17:30\n");
+
+if(time_period_match("weekday { sat sun }, weekday {mo-fr} hr {17-8},wd{mo-wed}hr{15 16 9}"))
+	xdbg("We're closed - open only Monday to Wednesday 10:00-15:00, Thursday and Friday 9:00-17:00");
+...
 </programlisting>
 </programlisting>
 	    </example>
 	    </example>
 	</section>
 	</section>

+ 369 - 0
modules/tmrec/period.c

@@ -0,0 +1,369 @@
+#include <stdio.h>
+#include <string.h>
+#include <time.h>
+#include <sys/time.h>
+#include <stdlib.h>
+
+enum scales {
+	SCALE_YEAR = 0,
+	SCALE_MONTH,
+	SCALE_WEEK,
+	SCALE_MDAY,
+	SCALE_WDAY,
+	SCALE_YDAY,
+	SCALE_HOUR,
+	SCALE_MINUTE,
+	SCALE_SECOND,
+
+	SCALE_MAX
+};
+
+#define MAX_CODES 2
+#define MAX_VALUE_LEN 16 /* for spelled out month names, longest is "September" */
+
+typedef int (*scale_match_func)(const int time_var, const char *from, const char *to);
+
+struct scale_definition {
+	scale_match_func	func;
+	const char		*codes[MAX_CODES];
+	int			flags;
+};
+
+#define FLAG_INTEGER_ARGS		0x1
+
+static int year_fn(const int time_var, const char *from, const char *to);
+static int month_fn(const int time_var, const char *from, const char *to);
+static int week_fn(const int time_var, const char *from, const char *to);
+static int mday_fn(const int time_var, const char *from, const char *to);
+static int wday_fn(const int time_var, const char *from, const char *to);
+static int yday_fn(const int time_var, const char *from, const char *to);
+static int hour_fn(const int time_var, const char *from, const char *to);
+static int minute_fn(const int time_var, const char *from, const char *to);
+static int second_fn(const int time_var, const char *from, const char *to);
+
+static const struct scale_definition defs[SCALE_MAX + 1] = {
+	[SCALE_YEAR  ] = { year_fn,   { "year",   "yr"  }, FLAG_INTEGER_ARGS },
+	[SCALE_MONTH ] = { month_fn,  { "month",  "mo"  }, 0                 },
+	[SCALE_WEEK  ] = { week_fn,   { "week",   "wk"  }, FLAG_INTEGER_ARGS },	/* week of the month */
+	[SCALE_MDAY  ] = { mday_fn,   { "mday",   "md"  }, FLAG_INTEGER_ARGS },	/* day of the month */
+	[SCALE_WDAY  ] = { wday_fn,   { "wday",   "wd"  }, 0                 },	/* day of the week */
+	[SCALE_YDAY  ] = { yday_fn,   { "yday",   "yd"  }, FLAG_INTEGER_ARGS },	/* day of the year */
+	[SCALE_HOUR  ] = { hour_fn,   { "hour",   "hr"  }, FLAG_INTEGER_ARGS },
+	[SCALE_MINUTE] = { minute_fn, { "minute", "min" }, FLAG_INTEGER_ARGS },
+	[SCALE_SECOND] = { second_fn, { "second", "sec" }, FLAG_INTEGER_ARGS },
+	/* XXX week of the year? */
+
+	[SCALE_MAX   ] = { NULL, { NULL, } },
+};
+
+static const char *months[12] = { "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug",
+	"sep", "oct", "nov", "dec" };
+static const char *weekdays[7] = { "su", "mo", "tu", "we", "th", "fr", "sa" };
+
+static void get_time_vars(int time_vars[SCALE_MAX], time_t t) {
+	struct tm tm;
+
+	localtime_r(&t, &tm);
+
+	time_vars[SCALE_YEAR]   = tm.tm_year + 1900;
+	time_vars[SCALE_MONTH]  = tm.tm_mon + 1;
+	time_vars[SCALE_WEEK]   = (tm.tm_mday - 1 + (tm.tm_wday - tm.tm_mday + 1) % 7) / 7 + 1;
+	time_vars[SCALE_MDAY]   = tm.tm_mday;
+	time_vars[SCALE_WDAY]   = tm.tm_wday;
+	time_vars[SCALE_YDAY]   = tm.tm_yday + 1;
+	time_vars[SCALE_HOUR]   = tm.tm_hour;
+	time_vars[SCALE_MINUTE] = tm.tm_min;
+	time_vars[SCALE_SECOND] = tm.tm_sec;
+}
+
+#define WS_SKIP() while (*p == ' ') p++;
+
+int in_period(time_t t, const char *p) {
+	int time_vars[SCALE_MAX];
+	int scale_results[SCALE_MAX];
+	int scale, j, len, res;
+	const char *c, *a1, *a2;
+	char from[MAX_VALUE_LEN], to[MAX_VALUE_LEN], *str;
+
+	/* If no period is given or string is empty, the time always matches */
+	if (!p)
+		return 1;
+	WS_SKIP();
+	if (!*p)
+		return 1;
+
+	/* If "none" or "never" is given, time never matches */
+	if (!strcasecmp(p, "none") || !strcasecmp(p, "never"))
+		return 0;
+
+	get_time_vars(time_vars, t);
+
+	/* Loop through all sub-periods, separated by commas.
+	   string :=  PERIOD [, PERIOD ... ] */
+	while (1) {
+		memset(scale_results, -1, sizeof(scale_results));
+
+		/* Each sub-period consists of one or more scales, separated by spaces.
+		   PERIOD := SCALE { VALUES } [ SCALE { VALUES } ... ] */
+		while (1) {
+			/* XXX could do some hashing here */
+			for (scale = 0; scale < SCALE_MAX; scale++) {
+				for (j = 0; j < MAX_CODES; j++) {
+					c = defs[scale].codes[j];
+					len = strlen(c);
+					if (strncasecmp(p, c, len))
+						continue;
+					if (p[len] == ' ' || p[len] == '{')
+						goto found_scale;
+				}
+			}
+
+			/* No valid scale definition found, syntax error */
+			return -1;
+
+found_scale:
+			/* Skip over scale name, whitespace and brace */
+			p += len;
+			WS_SKIP();
+			if (*p != '{')
+				return -1; /* Syntax error */
+			p++;
+			WS_SKIP();
+
+			/* Keep track of what we've found */
+			if (scale_results[scale] == -1)
+				scale_results[scale] = 0;
+			else if (scale_results[scale] == 1) {
+				/* We already have a valid match for this scale. Skip
+				   over all this nonsense then. */
+				while (*p && *p != '}')
+					p++;
+				if (!*p)
+					return -1; /* Syntax error */
+				goto close_brace;
+			}
+
+			/* We're inside the braces now. Values are separated
+			   by spaces, possibly given as ranges.
+			   VALUES := ( VALUE | RANGE ) [ ( VALUE | RANGE ) ... ]
+			   RANGE := VALUE - VALUE */
+
+			while (1) {
+				str = from;
+				len = sizeof(from) - 1;
+				*from = *to = '\0';
+				while (1) {
+					switch (*p) {
+						case '\0':
+							return -1; /* Syntax error */
+
+						case ' ':
+							WS_SKIP();
+							/* Here, it's either a hyphen or end of value/range */
+							if (*p == '-')
+								goto hyphen;
+							break;
+
+						case '-':
+hyphen:
+							if (!*from)
+								return -1; /* Range given as "-foo", syntax error */
+							if (*to)
+								return -1; /* Range given as "foo-bar-baz", syntax error */
+							/* Terminate "from" string and init for "to" */
+							*str = '\0';
+							str = to;
+							len = sizeof(to) - 1;
+							p++;
+							WS_SKIP();
+							continue;
+
+						case '}':
+							break;
+
+						default:
+							/* everything else gets copied and lowercased */
+							if (len <= 0)
+								return -1; /* String too long, syntax error */
+							*str++ = *p++ | 0x20;	/* works for letters and digits */
+							len--;
+							continue;
+					}
+					break;
+				}
+
+				*str = '\0';
+
+				/* Finished parsing out value or range. An empty result
+				   is valid, e.g. at the end of the list for the scale */
+				if (!*from) {
+					if (*p == '}')
+						break;
+					continue;
+				}
+				a1 = from;
+				a2 = *to ? to : NULL;
+				if ((defs[scale].flags & FLAG_INTEGER_ARGS)) {
+					a1 = (void *) atol(a1);
+					a2 = (void *) (a2 ? atol(a2) : -1);
+				}
+				res = defs[scale].func(time_vars[scale], a1, a2);
+				printf("result: %i\n", res);
+
+				if (res == -1)
+					return -1; /* Syntax error */
+				else if (res == 1)
+					scale_results[scale] = 1;
+			}
+
+close_brace:
+			p++;
+
+			/* Finished with one scale, braces closed. See if there's any more */
+			WS_SKIP();
+			if (!*p || *p == ',') {
+				/* Nope! Evaluate our result */
+				for (scale = 0; scale < SCALE_MAX; scale++) {
+					if (scale_results[scale] == 0)
+						goto no_match;
+				}
+
+				/* All scales that were given matched! We're done! */
+				return 1;
+
+no_match:
+				/* No luck, try next one if there are any more */
+				if (*p == ',') {
+					p++;
+					WS_SKIP();
+					break;
+				}
+
+				return 0;
+			}
+
+			continue;
+		}
+	}
+}
+
+static int generic_fn(const int time_var, const long f, long t, const long min, const long max) {
+	if (t == -1)
+		t = f;
+
+	if (f < min || f > max)
+		return -1;
+	if (t < min || t > max)
+		return -1;
+
+	if (f > t) {
+		if (f <= time_var || t >= time_var)
+			return 1;
+	}
+	else if (f <= time_var && time_var <= t)
+		return 1;
+	return 0;
+}
+
+static int generic_named_fn(const int time_var, const char *from, const char *to,
+		const char **array, int arr_len, int str_len) {
+
+	int i, f = 0, t = 0;
+
+	f = atoi(from);
+	if (!f)
+		for (i = 0; i < arr_len; i++)
+			if (!strncmp(array[i], from, str_len)) {
+				f = i + 1;
+				break;
+			}
+	if (!f)
+		return -1;
+
+	if (!to)
+		t = f;
+	else {
+		t = atoi(to);
+		if (!t)
+			for (i = 0; i < arr_len; i++)
+				if (!strncmp(array[i], to, str_len)) {
+					t = i + 1;
+					break;
+				}
+		if (!t)
+			return -1;
+	}
+
+	return generic_fn(time_var, f, t, 1, arr_len);
+}
+
+static int year_fn(const int time_var, const char *from, const char *to) {
+	long f, t, c;
+	printf("%s %i %li %li\n", __FUNCTION__, time_var, (long) from, (long) to);
+
+	f = (long) from;
+	t = (long) to;
+
+	if (t == -1)
+		t = f;
+
+	c = time_var / 100;	
+
+	if (t < 0)
+		return -1;
+	else if (t <= 99)
+		t += c;
+	else if (t < 1970)
+		return -1;
+
+	if (f < 0)
+		return -1;
+	else if (f <= 99)
+		f += c;
+	else if (f < 1970)
+		return -1;
+
+	if (time_var >= f && time_var <= t)
+		return 1;
+	return 0;
+}
+
+static int month_fn(const int time_var, const char *from, const char *to) {
+	printf("%s %i '%s' '%s'\n", __FUNCTION__, time_var, from, to);
+	return generic_named_fn(time_var, from, to, months, 12, 3);
+}
+
+static int week_fn(const int time_var, const char *from, const char *to) {
+	printf("%s %i %li %li\n", __FUNCTION__, time_var, (long) from, (long) to);
+	return generic_fn(time_var, (long) from, (long) to, 1, 6);
+}
+
+static int mday_fn(const int time_var, const char *from, const char *to) {
+	printf("%s %i %li %li\n", __FUNCTION__, time_var, (long) from, (long) to);
+	return generic_fn(time_var, (long) from, (long) to, 1, 31);
+}
+
+static int wday_fn(const int time_var, const char *from, const char *to) {
+	printf("%s %i '%s' '%s'\n", __FUNCTION__, time_var, from, to);
+	return generic_named_fn(time_var, from, to, weekdays, 7, 2);
+}
+
+static int yday_fn(const int time_var, const char *from, const char *to) {
+	printf("%s %i %li %li\n", __FUNCTION__, time_var, (long) from, (long) to);
+	return generic_fn(time_var, (long) from, (long) to, 1, 366);
+}
+
+static int hour_fn(const int time_var, const char *from, const char *to) {
+	printf("%s %i %li %li\n", __FUNCTION__, time_var, (long) from, (long) to);
+	return generic_fn(time_var, (long) from, (long) to, 0, 23);
+}
+
+static int minute_fn(const int time_var, const char *from, const char *to) {
+	printf("%s %i %li %li\n", __FUNCTION__, time_var, (long) from, (long) to);
+	return generic_fn(time_var, (long) from, (long) to, 0, 59);
+}
+
+static int second_fn(const int time_var, const char *from, const char *to) {
+	printf("%s %i %li %li\n", __FUNCTION__, time_var, (long) from, (long) to);
+	return generic_fn(time_var, (long) from, (long) to, 0, 60); /* allow for leap seconds */
+}

+ 6 - 0
modules/tmrec/period.h

@@ -0,0 +1,6 @@
+#ifndef _PERIOD_H_
+#define _PERIOH_H_
+
+int in_period(time_t t, const char *p);
+
+#endif

+ 53 - 0
modules/tmrec/tmrec_mod.c

@@ -33,6 +33,7 @@
 #include "../../pvar.h"
 #include "../../pvar.h"
 #include "../../mod_fix.h"
 #include "../../mod_fix.h"
 #include "../../lib/srutils/tmrec.h"
 #include "../../lib/srutils/tmrec.h"
+#include "period.h"
 
 
 
 
 MODULE_VERSION
 MODULE_VERSION
@@ -45,6 +46,8 @@ static int w_tmrec_match(struct sip_msg* msg, char* rec, char* t);
 static int fixup_tmrec_match(void** param, int param_no);
 static int fixup_tmrec_match(void** param, int param_no);
 static int w_is_leap_year(struct sip_msg* msg, char* t, char* p2);
 static int w_is_leap_year(struct sip_msg* msg, char* t, char* p2);
 static int fixup_is_leap_year(void** param, int param_no);
 static int fixup_is_leap_year(void** param, int param_no);
+static int fixup_time_period_match(void** param, int param_no);
+static int w_time_period_match(struct sip_msg* msg, char* period, char* t);
 
 
 int tmrec_wday = 0;
 int tmrec_wday = 0;
 char tmrec_separator = '|';
 char tmrec_separator = '|';
@@ -59,6 +62,10 @@ static cmd_export_t cmds[]={
 		0, ANY_ROUTE},
 		0, ANY_ROUTE},
 	{"is_leap_year", (cmd_function)w_is_leap_year, 1, fixup_is_leap_year,
 	{"is_leap_year", (cmd_function)w_is_leap_year, 1, fixup_is_leap_year,
 		0, ANY_ROUTE},
 		0, ANY_ROUTE},
+	{"time_period_match", (cmd_function)w_time_period_match, 1, fixup_time_period_match,
+		0, ANY_ROUTE},
+	{"time_period_match", (cmd_function)w_time_period_match, 2, fixup_time_period_match,
+		0, ANY_ROUTE},
 	{0, 0, 0, 0, 0, 0}
 	{0, 0, 0, 0, 0, 0}
 };
 };
 
 
@@ -220,3 +227,49 @@ static int fixup_tmrec_match(void** param, int param_no)
 	}
 	}
 	return 0;
 	return 0;
 }
 }
+
+static int fixup_time_period_match(void** param, int param_no)
+{
+	if(param_no==1)
+	{
+		if(fixup_spve_null(param, 1)<0)
+			return -1;
+		return 0;
+	} else if(param_no==2) {
+		if(fixup_igp_null(param, 1)<0)
+			return -1;
+	}
+	return 0;
+}
+
+static int w_time_period_match(struct sip_msg* msg, char* period, char* t)
+{
+	str rv;
+	time_t tv;
+	int ti;
+
+	if(msg==NULL)
+		return -2;
+
+	if(fixup_get_svalue(msg, (gparam_t*)period, &rv)!=0)
+	{
+		LM_ERR("invalid period parameter value\n");
+		return -3;
+	}
+
+	if(t!=NULL)
+	{
+		if(fixup_get_ivalue(msg, (gparam_t*)t, &ti)!=0)
+		{
+			LM_ERR("invalid time stamp parameter value\n");
+			return -4;
+		}
+		tv = (time_t)ti;
+	} else {
+		tv = time(NULL);
+	}
+
+	if (in_period(tv, rv.s))
+		return 1;
+	return -1;
+}