]>
git.proxmox.com Git - libgit2.git/blob - src/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"
13 void git_signature_free(git_signature
*sig
)
20 git__free(sig
->email
);
25 static int signature_error(const char *msg
)
27 giterr_set(GITERR_INVALID
, "Failed to parse signature - %s", msg
);
31 static bool contains_angle_brackets(const char *input
)
33 return strchr(input
, '<') != NULL
|| strchr(input
, '>') != NULL
;
36 static char *extract_trimmed(const char *ptr
, size_t len
)
38 while (len
&& ptr
[0] == ' ') {
42 while (len
&& ptr
[len
- 1] == ' ') {
46 return git__substrdup(ptr
, len
);
49 int git_signature_new(git_signature
**sig_out
, const char *name
, const char *email
, git_time_t time
, int offset
)
51 git_signature
*p
= NULL
;
53 assert(name
&& email
);
57 if (contains_angle_brackets(name
) ||
58 contains_angle_brackets(email
)) {
59 return signature_error(
60 "Neither `name` nor `email` should contain angle brackets chars.");
63 p
= git__calloc(1, sizeof(git_signature
));
64 GITERR_CHECK_ALLOC(p
);
66 p
->name
= extract_trimmed(name
, strlen(name
));
67 p
->email
= extract_trimmed(email
, strlen(email
));
69 if (p
->name
== NULL
|| p
->email
== NULL
||
70 p
->name
[0] == '\0' || p
->email
[0] == '\0') {
71 git_signature_free(p
);
72 return signature_error("Empty name or email");
76 p
->when
.offset
= offset
;
82 git_signature
*git_signature_dup(const git_signature
*sig
)
85 if (git_signature_new(&new, sig
->name
, sig
->email
, sig
->when
.time
, sig
->when
.offset
) < 0)
90 int git_signature_now(git_signature
**sig_out
, const char *name
, const char *email
)
101 * Get the current time as seconds since the epoch and
102 * transform that into a tm struct containing the time at
103 * UTC. Give that to mktime which considers it a local time
104 * (tm_isdst = -1 asks it to take DST into account) and gives
105 * us that time as seconds since the epoch. The difference
106 * between its return value and 'now' is our offset to UTC.
109 utc_tm
= p_gmtime_r(&now
, &_utc
);
110 utc_tm
->tm_isdst
= -1;
111 offset
= (time_t)difftime(now
, mktime(utc_tm
));
114 if (git_signature_new(&sig
, name
, email
, now
, (int)offset
) < 0)
122 int git_signature__parse(git_signature
*sig
, const char **buffer_out
,
123 const char *buffer_end
, const char *header
, char ender
)
125 const char *buffer
= *buffer_out
;
126 const char *email_start
, *email_end
;
128 memset(sig
, 0, sizeof(git_signature
));
130 if ((buffer_end
= memchr(buffer
, ender
, buffer_end
- buffer
)) == NULL
)
131 return signature_error("no newline given");
134 const size_t header_len
= strlen(header
);
136 if (buffer
+ header_len
>= buffer_end
|| memcmp(buffer
, header
, header_len
) != 0)
137 return signature_error("expected prefix doesn't match actual");
139 buffer
+= header_len
;
142 email_start
= git__memrchr(buffer
, '<', buffer_end
- buffer
);
143 email_end
= git__memrchr(buffer
, '>', buffer_end
- buffer
);
145 if (!email_start
|| !email_end
|| email_end
<= email_start
)
146 return signature_error("malformed e-mail");
149 sig
->name
= extract_trimmed(buffer
, email_start
- buffer
- 1);
150 sig
->email
= extract_trimmed(email_start
, email_end
- email_start
);
152 /* Do we even have a time at the end of the signature? */
153 if (email_end
+ 2 < buffer_end
) {
154 const char *time_start
= email_end
+ 2;
155 const char *time_end
;
157 if (git__strtol64(&sig
->when
.time
, time_start
, &time_end
, 10) < 0)
158 return signature_error("invalid Unix timestamp");
160 /* do we have a timezone? */
161 if (time_end
+ 1 < buffer_end
) {
162 int offset
, hours
, mins
;
163 const char *tz_start
, *tz_end
;
165 tz_start
= time_end
+ 1;
167 if ((tz_start
[0] != '-' && tz_start
[0] != '+') ||
168 git__strtol32(&offset
, tz_start
+ 1, &tz_end
, 10) < 0)
169 return signature_error("malformed timezone");
171 hours
= offset
/ 100;
175 * only store timezone if it's not overflowing;
176 * see http://www.worldtimezone.com/faq.html
178 if (hours
< 14 && mins
< 59) {
179 sig
->when
.offset
= (hours
* 60) + mins
;
180 if (tz_start
[0] == '-')
181 sig
->when
.offset
= -sig
->when
.offset
;
186 *buffer_out
= buffer_end
+ 1;
190 void git_signature__writebuf(git_buf
*buf
, const char *header
, const git_signature
*sig
)
192 int offset
, hours
, mins
;
195 offset
= sig
->when
.offset
;
196 sign
= (sig
->when
.offset
< 0) ? '-' : '+';
204 git_buf_printf(buf
, "%s%s <%s> %u %c%02d%02d\n",
205 header
? header
: "", sig
->name
, sig
->email
,
206 (unsigned)sig
->when
.time
, sign
, hours
, mins
);