]>
git.proxmox.com Git - libgit2.git/blob - src/libgit2/signature.c
2 * Copyright (C) the libgit2 contributors. All rights reserved.
4 * This file is part of libgit2, distributed under the GNU GPL v2 with
5 * a Linking Exception. For full terms see the included COPYING file.
10 #include "repository.h"
11 #include "git2/common.h"
14 void git_signature_free(git_signature
*sig
)
21 git__free(sig
->email
);
26 static int signature_parse_error(const char *msg
)
28 git_error_set(GIT_ERROR_INVALID
, "failed to parse signature - %s", msg
);
32 static int signature_error(const char *msg
)
34 git_error_set(GIT_ERROR_INVALID
, "failed to parse signature - %s", msg
);
38 static bool contains_angle_brackets(const char *input
)
40 return strchr(input
, '<') != NULL
|| strchr(input
, '>') != NULL
;
43 static bool is_crud(unsigned char c
)
57 static char *extract_trimmed(const char *ptr
, size_t len
)
59 while (len
&& is_crud((unsigned char)ptr
[0])) {
63 while (len
&& is_crud((unsigned char)ptr
[len
- 1])) {
67 return git__substrdup(ptr
, len
);
70 int git_signature_new(git_signature
**sig_out
, const char *name
, const char *email
, git_time_t time
, int offset
)
72 git_signature
*p
= NULL
;
75 GIT_ASSERT_ARG(email
);
79 if (contains_angle_brackets(name
) ||
80 contains_angle_brackets(email
)) {
81 return signature_error(
82 "Neither `name` nor `email` should contain angle brackets chars.");
85 p
= git__calloc(1, sizeof(git_signature
));
86 GIT_ERROR_CHECK_ALLOC(p
);
88 p
->name
= extract_trimmed(name
, strlen(name
));
89 GIT_ERROR_CHECK_ALLOC(p
->name
);
90 p
->email
= extract_trimmed(email
, strlen(email
));
91 GIT_ERROR_CHECK_ALLOC(p
->email
);
93 if (p
->name
[0] == '\0' || p
->email
[0] == '\0') {
94 git_signature_free(p
);
95 return signature_error("Signature cannot have an empty name or email");
99 p
->when
.offset
= offset
;
100 p
->when
.sign
= (offset
< 0) ? '-' : '+';
106 int git_signature_dup(git_signature
**dest
, const git_signature
*source
)
108 git_signature
*signature
;
113 signature
= git__calloc(1, sizeof(git_signature
));
114 GIT_ERROR_CHECK_ALLOC(signature
);
116 signature
->name
= git__strdup(source
->name
);
117 GIT_ERROR_CHECK_ALLOC(signature
->name
);
119 signature
->email
= git__strdup(source
->email
);
120 GIT_ERROR_CHECK_ALLOC(signature
->email
);
122 signature
->when
.time
= source
->when
.time
;
123 signature
->when
.offset
= source
->when
.offset
;
124 signature
->when
.sign
= source
->when
.sign
;
131 int git_signature__pdup(git_signature
**dest
, const git_signature
*source
, git_pool
*pool
)
133 git_signature
*signature
;
138 signature
= git_pool_mallocz(pool
, sizeof(git_signature
));
139 GIT_ERROR_CHECK_ALLOC(signature
);
141 signature
->name
= git_pool_strdup(pool
, source
->name
);
142 GIT_ERROR_CHECK_ALLOC(signature
->name
);
144 signature
->email
= git_pool_strdup(pool
, source
->email
);
145 GIT_ERROR_CHECK_ALLOC(signature
->email
);
147 signature
->when
.time
= source
->when
.time
;
148 signature
->when
.offset
= source
->when
.offset
;
149 signature
->when
.sign
= source
->when
.sign
;
156 int git_signature_now(git_signature
**sig_out
, const char *name
, const char *email
)
167 * Get the current time as seconds since the epoch and
168 * transform that into a tm struct containing the time at
169 * UTC. Give that to mktime which considers it a local time
170 * (tm_isdst = -1 asks it to take DST into account) and gives
171 * us that time as seconds since the epoch. The difference
172 * between its return value and 'now' is our offset to UTC.
175 utc_tm
= p_gmtime_r(&now
, &_utc
);
176 utc_tm
->tm_isdst
= -1;
177 offset
= (time_t)difftime(now
, mktime(utc_tm
));
180 if (git_signature_new(&sig
, name
, email
, now
, (int)offset
) < 0)
188 int git_signature_default(git_signature
**out
, git_repository
*repo
)
192 const char *user_name
, *user_email
;
194 if ((error
= git_repository_config_snapshot(&cfg
, repo
)) < 0)
197 if (!(error
= git_config_get_string(&user_name
, cfg
, "user.name")) &&
198 !(error
= git_config_get_string(&user_email
, cfg
, "user.email")))
199 error
= git_signature_now(out
, user_name
, user_email
);
201 git_config_free(cfg
);
205 int git_signature__parse(git_signature
*sig
, const char **buffer_out
,
206 const char *buffer_end
, const char *header
, char ender
)
208 const char *buffer
= *buffer_out
;
209 const char *email_start
, *email_end
;
211 memset(sig
, 0, sizeof(git_signature
));
214 (buffer_end
= memchr(buffer
, ender
, buffer_end
- buffer
)) == NULL
)
215 return signature_parse_error("no newline given");
218 const size_t header_len
= strlen(header
);
220 if (buffer
+ header_len
>= buffer_end
|| memcmp(buffer
, header
, header_len
) != 0)
221 return signature_parse_error("expected prefix doesn't match actual");
223 buffer
+= header_len
;
226 email_start
= git__memrchr(buffer
, '<', buffer_end
- buffer
);
227 email_end
= git__memrchr(buffer
, '>', buffer_end
- buffer
);
229 if (!email_start
|| !email_end
|| email_end
<= email_start
)
230 return signature_parse_error("malformed e-mail");
233 sig
->name
= extract_trimmed(buffer
, email_start
- buffer
- 1);
234 sig
->email
= extract_trimmed(email_start
, email_end
- email_start
);
236 /* Do we even have a time at the end of the signature? */
237 if (email_end
+ 2 < buffer_end
) {
238 const char *time_start
= email_end
+ 2;
239 const char *time_end
;
241 if (git__strntol64(&sig
->when
.time
, time_start
,
242 buffer_end
- time_start
, &time_end
, 10) < 0) {
243 git__free(sig
->name
);
244 git__free(sig
->email
);
245 sig
->name
= sig
->email
= NULL
;
246 return signature_parse_error("invalid Unix timestamp");
249 /* do we have a timezone? */
250 if (time_end
+ 1 < buffer_end
) {
251 int offset
, hours
, mins
;
252 const char *tz_start
, *tz_end
;
254 tz_start
= time_end
+ 1;
256 if ((tz_start
[0] != '-' && tz_start
[0] != '+') ||
257 git__strntol32(&offset
, tz_start
+ 1,
258 buffer_end
- tz_start
- 1, &tz_end
, 10) < 0) {
259 /* malformed timezone, just assume it's zero */
263 hours
= offset
/ 100;
267 * only store timezone if it's not overflowing;
268 * see http://www.worldtimezone.com/faq.html
270 if (hours
<= 14 && mins
<= 59) {
271 sig
->when
.offset
= (hours
* 60) + mins
;
272 sig
->when
.sign
= tz_start
[0];
273 if (tz_start
[0] == '-')
274 sig
->when
.offset
= -sig
->when
.offset
;
279 *buffer_out
= buffer_end
+ 1;
283 int git_signature_from_buffer(git_signature
**out
, const char *buf
)
294 sig
= git__calloc(1, sizeof(git_signature
));
295 GIT_ERROR_CHECK_ALLOC(sig
);
297 buf_end
= buf
+ strlen(buf
);
298 error
= git_signature__parse(sig
, &buf
, buf_end
, NULL
, '\0');
308 void git_signature__writebuf(git_str
*buf
, const char *header
, const git_signature
*sig
)
310 int offset
, hours
, mins
;
313 offset
= sig
->when
.offset
;
314 sign
= (sig
->when
.offset
< 0 || sig
->when
.sign
== '-') ? '-' : '+';
322 git_str_printf(buf
, "%s%s <%s> %u %c%02d%02d\n",
323 header
? header
: "", sig
->name
, sig
->email
,
324 (unsigned)sig
->when
.time
, sign
, hours
, mins
);
327 bool git_signature__equal(const git_signature
*one
, const git_signature
*two
)
333 git__strcmp(one
->name
, two
->name
) == 0 &&
334 git__strcmp(one
->email
, two
->email
) == 0 &&
335 one
->when
.time
== two
->when
.time
&&
336 one
->when
.offset
== two
->when
.offset
&&
337 one
->when
.sign
== two
->when
.sign
;