1 /* vi: set sw=4 ts=4:
2  *
3  * Copyright (C) 2001 - 2012 Christian Hohnstaedt.
4  *
5  * All rights reserved.
6  */
7 
8 #include <time.h>
9 
10 #include "base.h"
11 #include "func.h"
12 #include "exception.h"
13 #include "widgets/XcaApplication.h"
14 #include "asn1time.h"
15 #include <openssl/x509.h>
16 #include <openssl/err.h>
17 #include <openssl/opensslv.h>
18 
19 #include <QObject>
20 
21 /* As defined in rfc-5280  4.1.2.5 */
22 #define UNDEFINED_DATE "99991231235959Z"
23 
24 #define UTC_FORMAT     "yyMMddHHmmss'Z'"
25 #define GEN_FORMAT     "yy" UTC_FORMAT
26 
isUndefined() const27 bool a1time::isUndefined() const
28 {
29 	return toTime_t() == 0;
30 }
31 
setUndefined()32 a1time &a1time::setUndefined()
33 {
34 	/* This way we handle "Jan 01, 1970 00:00:00"
35 	 * like RFC-5280 undefined date. I dare it */
36 	setTimeSpec(Qt::UTC);
37 	setTime_t(0);
38 	return *this;
39 }
40 
from_asn1(const ASN1_TIME * a)41 int a1time::from_asn1(const ASN1_TIME *a)
42 {
43 	ASN1_GENERALIZEDTIME *gt;
44 	QString t;
45 
46 	*this = QDateTime();
47 	if (!a)
48 		return -1;
49 	gt = ASN1_TIME_to_generalizedtime((ASN1_TIME*)a, NULL);
50 	if (!gt)
51 		return -1;
52 	t = QString::fromLatin1((char*)gt->data, gt->length);
53 	ASN1_GENERALIZEDTIME_free(gt);
54 	return fromPlain(t);
55 }
56 
fromPlain(const QString & plain)57 int a1time::fromPlain(const QString &plain)
58 {
59 	setTimeSpec(Qt::LocalTime);
60 	if (plain == UNDEFINED_DATE)
61 		setUndefined();
62 	else
63 		*this = fromString(plain, GEN_FORMAT);
64 	setTimeSpec(Qt::UTC);
65 	return isValid() ? 0 : -1;
66 }
67 
set_asn1(const QString & str,int type)68 int a1time::set_asn1(const QString &str, int type)
69 {
70 	if (!atime)
71 		atime = ASN1_TIME_new();
72 	if (!atime)
73 		return -1;
74 	atime->type = type;
75 	if (ASN1_STRING_set(atime, str.toLatin1(), str.length()))
76 		return -1;
77 	return 0;
78 }
79 
a1time(const QDateTime & a)80 a1time::a1time(const QDateTime &a)
81 	: QDateTime(a)
82 {
83 	atime = NULL;
84 }
85 
a1time(const a1time & a)86 a1time::a1time(const a1time &a)
87 	: QDateTime(a)
88 {
89 	atime = NULL;
90 }
91 
operator =(const a1time & a)92 a1time &a1time::operator = (const a1time &a)
93 {
94 	if (atime)
95 		ASN1_TIME_free(atime);
96 	atime = NULL;
97 	QDateTime::operator=(a);
98 	return *this;
99 }
100 
a1time()101 a1time::a1time()
102 {
103 	atime = NULL;
104 	*this = now();
105 }
106 
a1time(const ASN1_TIME * a)107 a1time::a1time(const ASN1_TIME *a)
108 {
109 	atime = NULL;
110 	from_asn1(a);
111 }
112 
a1time(const QString & plain)113 a1time::a1time(const QString &plain)
114 {
115 	atime = NULL;
116 	fromPlain(plain);
117 }
118 
~a1time()119 a1time::~a1time()
120 {
121 	if (atime)
122 		ASN1_TIME_free(atime);
123 }
124 
get_utc()125 ASN1_TIME *a1time::get_utc()
126 {
127 	int year = date().year();
128 
129 	if (!isValid() || isUndefined() || year > 2049 || year < 1950)
130 		return get();
131 
132 	set_asn1(toUTC().toString(UTC_FORMAT), V_ASN1_UTCTIME);
133 	return atime;
134 }
135 
get()136 ASN1_TIME *a1time::get()
137 {
138 	if (isUndefined())
139 		set_asn1(UNDEFINED_DATE, V_ASN1_GENERALIZEDTIME);
140 	else if (!isValid())
141 		throw errorEx("Invalid Time");
142 	else
143 		set_asn1(toUTC().toString(GEN_FORMAT),
144 			V_ASN1_GENERALIZEDTIME);
145 	return atime;
146 }
147 
set(const ASN1_TIME * a)148 a1time &a1time::set(const ASN1_TIME *a)
149 {
150 	from_asn1(a);
151 	return *this;
152 }
153 
toString(QString fmt,Qt::TimeSpec spec) const154 QString a1time::toString(QString fmt, Qt::TimeSpec spec) const
155 {
156 	if (isUndefined())
157 		return QObject::tr("Undefined");
158 	if (!isValid())
159 		return QObject::tr("Broken / Invalid");
160 	return XcaApplication::language().toString(
161 		spec == Qt::UTC ? toUTC() : toLocalTime(), fmt);
162 }
163 
toPretty() const164 QString a1time::toPretty() const
165 {
166 	QString fmt = XcaApplication::language().dateTimeFormat();
167 	return toString(fmt, Qt::LocalTime);
168 }
169 
toPrettyGMT() const170 QString a1time::toPrettyGMT() const
171 {
172 	return toString("yyyy-MM-dd'T'HH:mm:ss' GMT'");
173 }
174 
toSortable() const175 QString a1time::toSortable() const
176 {
177 	return toString("yyyy-MM-dd");
178 }
179 
toPlain(const QString & fmt) const180 QString a1time::toPlain(const QString &fmt) const
181 {
182 	if (isUndefined())
183 		return QString(UNDEFINED_DATE);
184 	if (!isValid())
185 		return QString("Broken-InvalidZ");
186 	return toString(fmt.isEmpty() ? GEN_FORMAT : fmt);
187 }
188 
age() const189 qint64 a1time::age() const
190 {
191 	return secsTo(now());
192 }
193 
toFancy() const194 QString a1time::toFancy() const
195 {
196 	QString fmt("Dunno");
197 	qint64 diff = age();
198 	int dtn = toLocalTime().daysTo(now().toLocalTime());
199 	bool future = false;
200 	if (diff < 0) {
201 		future = true;
202 		diff *= -1;
203 	}
204 	if (diff < 2 * SECS_PER_MINUTE) {
205 		fmt = future ? QObject::tr("in %1 seconds") :
206 				QObject::tr("%1 seconds ago");
207 	} else if (diff < 2 *SECS_PER_HOUR) {
208 		diff /= SECS_PER_MINUTE;
209 		fmt = future ? QObject::tr("in %1 minutes") :
210 				QObject::tr("%1 minutes ago");
211 	} else if (dtn == 1) {
212 		return QObject::tr("Yesterday");
213 	} else if (dtn == -1) {
214 		return QObject::tr("Tomorrow");
215 	} else if (diff < SECS_PER_DAY) {
216 		diff /= SECS_PER_HOUR;
217 		fmt = future ? QObject::tr("in %1 hours") :
218 				QObject::tr("%1 hours ago");
219 	} else {
220 		return XcaApplication::language().toString(date(),
221 			QLocale::ShortFormat);
222 	}
223 	return fmt.arg(diff);
224 }
225 
toPlainUTC() const226 QString a1time::toPlainUTC() const
227 {
228 	return toPlain(UTC_FORMAT);
229 }
230 
now(int delta)231 QDateTime a1time::now(int delta)
232 {
233 	return QDateTime::currentDateTime().toUTC().addSecs(delta);
234 }
235 
d2i(QByteArray & ba)236 void a1time::d2i(QByteArray &ba)
237 {
238 	ASN1_TIME *n = (ASN1_TIME*)d2i_bytearray( D2I_VOID(d2i_ASN1_TIME), ba);
239 	openssl_error();
240 	if (n) {
241 		from_asn1(n);
242 		ASN1_TIME_free(n);
243 	}
244 }
245 
i2d()246 QByteArray a1time::i2d()
247 {
248 	get();
249 	return i2d_bytearray(I2D_VOID(i2d_ASN1_TIME), atime);
250 }
251