1 /*
2 * Empire - A multi-player, client/server Internet based war game.
3 * Copyright (C) 1986-2021, Dave Pare, Jeff Bailey, Thomas Ruschak,
4 * Ken Stevens, Steve McClure, Markus Armbruster
5 *
6 * Empire is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 * ---
20 *
21 * See files README, COPYING and CREDITS in the root of the source
22 * tree for related information and legal notices. It is expected
23 * that future projects/authors will amend these files as needed.
24 *
25 * ---
26 *
27 * hours.c: Game hours determination; is it legal to play now?
28 *
29 * Known contributors to this file:
30 * Dave Pare, 1989
31 * Doug Hay, 1998
32 * Steve McClure, 1998
33 * Markus Armbruster, 2004-2010
34 */
35
36 #include <config.h>
37
38 #include <ctype.h>
39 #include <time.h>
40 #include "misc.h"
41 #include "optlist.h"
42 #include "prototypes.h"
43
44 static char *weekday(char *str, int *wday);
45 static char *daytime_range(char *str, int *from_min, int *to_min);
46
47 /*
48 * Is week day @wday (Sunday is 0) allowed by restriction @days?
49 * If @days is not empty, it lists the allowed week day names. See
50 * weekday() for syntax.
51 */
52 int
is_wday_allowed(int wday,char * days)53 is_wday_allowed(int wday, char *days)
54 {
55 int wd;
56
57 if (!days || !*days)
58 return 1;
59
60 while (NULL != (days = weekday(days, &wd)))
61 if (wd == wday)
62 return 1;
63
64 return 0;
65 }
66
67 /*
68 * Is day time @dtime allowed by restriction @times?
69 * @dtime is in minutes since midnight.
70 * If @times is not empty, it lists the allowed day time ranges. See
71 * daytime_range() for syntax.
72 */
73 int
is_daytime_allowed(int dtime,char * times)74 is_daytime_allowed(int dtime, char *times)
75 {
76 int from, to;
77
78 if (!times || !*times)
79 return 1;
80
81 while (NULL != (times = daytime_range(times, &from, &to)))
82 if (from <= dtime && dtime < to)
83 return 1;
84
85 return 0;
86 }
87
88 /*
89 * Can the game played at time @t?
90 */
91 int
gamehours(time_t t)92 gamehours(time_t t)
93 {
94 struct tm *tm;
95
96 tm = localtime(&t);
97 if (!is_wday_allowed(tm->tm_wday, game_days))
98 return 0;
99 return is_daytime_allowed(60 * tm->tm_hour + tm->tm_min, game_hours);
100 }
101
102 /*
103 * Parse weekday name in @str.
104 * On success assign day number (Sunday is 0) to *@wday and return
105 * pointer to first character not parsed.
106 * Else return NULL.
107 * Abbreviated names are recognized, but not single characters.
108 * Initial whitespace is ignored.
109 */
110 static char *
weekday(char * str,int * wday)111 weekday(char *str, int *wday)
112 {
113 /*
114 * strptime() format " %a" would do fine, but it's XPG and Windows
115 * doesn't have it. Besides, Empire accepts more abbreviations.
116 */
117 static char *day_name[7] = {
118 "sunday", "monday", "tuesday", "wednesday",
119 "thursday", "friday", "saturday"
120 };
121 int i, j;
122
123 for (; isspace(*str); ++str) ;
124
125 for (i = 0; i < 7; ++i) {
126 j = 0;
127 while (str[j] && tolower(str[j]) == day_name[i][j])
128 ++j;
129 if (j > 1) {
130 *wday = i;
131 return str + j;
132 }
133 }
134
135 return NULL;
136 }
137
138 /*
139 * Parse day time in @str.
140 * On success store minutes since midnight in *@min and return pointer
141 * to first character not parsed.
142 * Else return NULL.
143 * Time format is HOUR:MINUTE. Initial whitespace is ignored.
144 */
145 static char *
daytime(char * str,int * min)146 daytime(char *str, int *min)
147 {
148 /*
149 * strptime() format " %H:%M" would do fine, but it's XPG and
150 * Windows doesn't have it.
151 */
152 char *end;
153 unsigned long h, m;
154
155 h = strtoul(str, &end, 10);
156 if (end == str || h > 24)
157 return NULL;
158
159 if (*end++ != ':')
160 return NULL;
161
162 str = end;
163 m = strtoul(str, &end, 10);
164 if (end == str || m > 59)
165 return NULL;
166 else if (h == 24 && m != 0)
167 return NULL;
168
169 *min = 60 * h + m;
170 return end;
171 }
172
173 /*
174 * Parse a day time range in @str.
175 * On success, store minutes since midnight in *@from_min, *@to_min,
176 * and return pointer to first character not parsed.
177 * Else return NULL.
178 * Format is HOUR:MINUTE-HOUR:MINUTE. Initial whitespace is ignored.
179 */
180 static char *
daytime_range(char * str,int * from_min,int * to_min)181 daytime_range(char *str, int *from_min, int *to_min)
182 {
183 char *end;
184
185 end = daytime(str, from_min);
186 if (!end)
187 return NULL;
188 while (isspace(*end)) ++end;
189 if (*end++ != '-')
190 return NULL;
191 return daytime(end, to_min);
192 }
193