File: fmt_date.c

package info (click to toggle)
webcit 8.24-dfsg-1
  • links: PTS, VCS
  • area: main
  • in suites: jessie, jessie-kfreebsd
  • size: 10,888 kB
  • ctags: 4,214
  • sloc: ansic: 33,336; sh: 4,468; makefile: 340; xml: 90; sed: 9
file content (309 lines) | stat: -rw-r--r-- 6,932 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
/*
 * Copyright (c) 1996-2012 by the citadel.org team
 *
 * This program is open source software.  You can redistribute it and/or
 * modify it under the terms of the GNU General Public License, version 3.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include "webcit.h"
#include "webserver.h"

#ifdef HAVE_USELOCALE
extern locale_t *wc_locales;
#endif

typedef unsigned char byte;

#define FALSE 0 /**< no. */
#define TRUE 1 /**< yes. */

/*
 * Wrapper around strftime() or strftime_l()
 * depending upon how our build is configured.
 *
 * s		String target buffer
 * max		Maximum size of string target buffer
 * format	strftime() format
 * tm		Input date/time
 */
size_t wc_strftime(char *s, size_t max, const char *format, const struct tm *tm)
{

#ifdef ENABLE_NLS
#ifdef HAVE_USELOCALE
	if (wc_locales[WC->selected_language] == NULL) {
		return strftime(s, max, format, tm);
	}
	else {
		return strftime_l(s, max, format, tm, wc_locales[WC->selected_language]);
	}
#else
	return strftime(s, max, format, tm);
#endif
#else
	return strftime(s, max, format, tm);
#endif
}



/*
 * Format a date/time stamp for output 
 */
long webcit_fmt_date(char *buf, size_t siz, time_t thetime, int Format)
{
	long retlen = 0;
	struct tm tm;
	struct tm today_tm;
	time_t today_timet;
	int time_format;

	time_format = get_time_format_cached ();
	today_timet = time(NULL);
	localtime_r(&today_timet, &today_tm);

	localtime_r(&thetime, &tm);

	/*
	 * DATEFMT_FULL:      full display 
	 * DATEFMT_BRIEF:     if date == today, show only the time
	 *		      otherwise, for messages up to 6 months old, 
	 *                 show the month and day, and the time
	 *		      older than 6 months, show only the date
	 * DATEFMT_RAWDATE:   show full date, regardless of age 
	 * DATEFMT_LOCALEDATE:   show full date as prefered for the locale
	 */

	switch (Format) {
		case DATEFMT_BRIEF:
			if ((tm.tm_year == today_tm.tm_year)
			  &&(tm.tm_mon == today_tm.tm_mon)
			  &&(tm.tm_mday == today_tm.tm_mday)) {
				if (time_format == WC_TIMEFORMAT_24) 
					retlen = wc_strftime(buf, siz, "%k:%M", &tm);
				else
					retlen = wc_strftime(buf, siz, "%l:%M%p", &tm);
			}
			else if (today_timet - thetime < 15552000) {
				if (time_format == WC_TIMEFORMAT_24) 
					retlen = wc_strftime(buf, siz, "%b %d %k:%M", &tm);
				else
					retlen = wc_strftime(buf, siz, "%b %d %l:%M%p", &tm);
			}
			else {
				retlen = wc_strftime(buf, siz, "%b %d %Y", &tm);
			}
			break;
		case DATEFMT_FULL:
			if (time_format == WC_TIMEFORMAT_24)
				retlen = wc_strftime(buf, siz, "%a %b %d %Y %T %Z", &tm);
			else
				retlen = wc_strftime(buf, siz, "%a %b %d %Y %r %Z", &tm);
			break;
		case DATEFMT_RAWDATE:
			retlen = wc_strftime(buf, siz, "%a %b %d %Y", &tm);
			break;
		case DATEFMT_LOCALEDATE:
			retlen = wc_strftime(buf, siz, "%x", &tm);
			break;
	}
	return retlen;
}


/* 
 * Try to guess whether the user will prefer 12 hour or 24 hour time based on the locale.
 */
long guess_calhourformat(void) {
	char buf[64];
	struct tm tm;
	memset(&tm, 0, sizeof tm);
	wc_strftime(buf, 64, "%X", &tm);
	if (buf[strlen(buf)-1] == 'M') {
		return 12;
	}
	return 24;
}


/*
 * learn the users timeformat preference.
 */
int get_time_format_cached (void)
{
	long calhourformat;
	int *time_format_cache;
	time_format_cache = &(WC->time_format_cache);
	if (*time_format_cache == WC_TIMEFORMAT_NONE)
	{
		get_pref_long("calhourformat", &calhourformat, 99);

		/* If we don't know the user's time format preference yet,
		 * make a guess based on the locale.
		 */
		if (calhourformat == 99) {
			calhourformat = guess_calhourformat();
		}

		/* Now set the preference */
		if (calhourformat == 24) 
			*time_format_cache = WC_TIMEFORMAT_24;
		else
			*time_format_cache = WC_TIMEFORMAT_AMPM;
	}
	return *time_format_cache;
}

/*
 * Format TIME ONLY for output 
 * buf		the output buffer
 * thetime	time to format into buf
 */
void fmt_time(char *buf, size_t siz, time_t thetime)
{
	struct tm *tm;
	int hour;
	int time_format;
	
	time_format = get_time_format_cached ();
	buf[0] = 0;
	tm = localtime(&thetime);
	hour = tm->tm_hour;
	if (hour == 0)
		hour = 12;
	else if (hour > 12)
		hour = hour - 12;

	if (time_format == WC_TIMEFORMAT_24) {
		snprintf(buf, siz, "%d:%02d",
			tm->tm_hour, tm->tm_min
		);
	}
	else {
		snprintf(buf, siz, "%d:%02d%s",
			hour, tm->tm_min, ((tm->tm_hour > 12) ? "pm" : "am")
		);
	}
}




/*
 * Break down the timestamp used in HTTP headers
 * Should read rfc1123 and rfc850 dates OK
 * FIXME won't read asctime
 * Doesn't understand timezone, but we only should be using GMT/UTC anyway
 */
time_t httpdate_to_timestamp(StrBuf *buf)
{
	time_t t = 0;
	struct tm tt;
	const char *c;

	/** Skip day of week, to number */
	for (c = ChrPtr(buf); *c != ' '; c++)
		;
	c++;
	
	memset(&tt, 0, sizeof(tt));

	/* Get day of month */
	tt.tm_mday = atoi(c);
	for (; *c != ' ' && *c != '-'; c++);
	c++;

	/* Get month */
	switch (*c) {
	case 'A':	/* April, August */
		tt.tm_mon = (c[1] == 'p') ? 3 : 7;
		break;
	case 'D':	/* December */
		tt.tm_mon = 11;
		break;
	case 'F':	/* February */
		tt.tm_mon = 1;
		break;
	case 'M':	/* March, May */
		tt.tm_mon = (c[2] == 'r') ? 2 : 4;
		break;
	case 'J':	/* January, June, July */
		tt.tm_mon = (c[2] == 'n') ? ((c[1] == 'a') ? 0 : 5) : 6;
		break;
	case 'N':	/* November */
		tt.tm_mon = 10;
		break;
	case 'O':	/* October */
		tt.tm_mon = 9;
		break;
	case 'S':	/* September */
		tt.tm_mon = 8;
		break;
	default:
		return 42;
		break;	/* NOTREACHED */
	}
	c += 4;

	tt.tm_year = 0;
	/* Get year */
	tt.tm_year = atoi(c);
	for (; *c != ' '; c++);
	c++;
	if (tt.tm_year >= 1900)
		tt.tm_year -= 1900;

	/* Get hour */
	tt.tm_hour = atoi(c);
	for (; *c != ':'; c++);
	c++;

	/* Get minute */
	tt.tm_min = atoi(c);
	for (; *c != ':'; c++);
	c++;

	/* Get second */
	tt.tm_sec = atoi(c);
	for (; *c && *c != ' '; c++);

	/* Got everything; let's go.  The global 'timezone' variable contains the
	 * local timezone's offset from UTC, in seconds, so we apply that to tm_sec.
	 * This produces an illegal value for tm_sec, but mktime() will normalize
	 * it for us.  This eliminates the need to temporarily switch the environment
	 * variable TZ to UTC, which is good because it fails to switch back on
	 * some systems.
	 */
	tzset();
	tt.tm_sec = tt.tm_sec - (int)timezone;
	t = mktime(&tt);
	return t;
}


void LoadTimeformatSettingsCache(StrBuf *Preference, long lvalue)
{
	int *time_format_cache;
	
	 time_format_cache = &(WC->time_format_cache);
	 if (lvalue == 24) 
		 *time_format_cache = WC_TIMEFORMAT_24;
	 else
		 *time_format_cache = WC_TIMEFORMAT_AMPM;
}



void 
InitModule_DATETIME
(void)
{
	RegisterPreference("calhourformat", _("Time format"), PRF_INT, LoadTimeformatSettingsCache);


}