]> git.proxmox.com Git - libgit2.git/blame - src/signature.c
signature: Shut up MSVC, you silly goose
[libgit2.git] / src / signature.c
CommitLineData
58519018 1/*
359fc2d2 2 * Copyright (C) the libgit2 contributors. All rights reserved.
58519018 3 *
bb742ede
VM
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.
58519018
VM
6 */
7
8#include "common.h"
638c2ca4 9#include "signature.h"
58519018 10#include "repository.h"
44908fe7 11#include "git2/common.h"
58519018 12
638c2ca4 13void git_signature_free(git_signature *sig)
58519018 14{
638c2ca4 15 if (sig == NULL)
58519018
VM
16 return;
17
3286c408 18 git__free(sig->name);
97769280 19 sig->name = NULL;
3286c408 20 git__free(sig->email);
97769280 21 sig->email = NULL;
3286c408 22 git__free(sig);
58519018
VM
23}
24
4aa7de15
RB
25static int signature_error(const char *msg)
26{
c51880ee 27 giterr_set(GITERR_INVALID, "Failed to parse signature - %s", msg);
4aa7de15
RB
28 return -1;
29}
30
c51880ee 31static bool contains_angle_brackets(const char *input)
a01acc47 32{
c51880ee 33 return strchr(input, '<') != NULL || strchr(input, '>') != NULL;
a01acc47 34}
35
c51880ee 36static char *extract_trimmed(const char *ptr, size_t len)
8aedf1d5 37{
c51880ee
VM
38 while (len && ptr[0] == ' ') {
39 ptr++; len--;
40 }
8aedf1d5 41
c51880ee
VM
42 while (len && ptr[len - 1] == ' ') {
43 len--;
44 }
45
46 return git__substrdup(ptr, len);
8aedf1d5 47}
48
63396a39 49int git_signature_new(git_signature **sig_out, const char *name, const char *email, git_time_t time, int offset)
58519018 50{
638c2ca4 51 git_signature *p = NULL;
58519018 52
a01acc47 53 assert(name && email);
54
63396a39
MS
55 *sig_out = NULL;
56
c51880ee
VM
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.");
61 }
62
4aa7de15
RB
63 p = git__calloc(1, sizeof(git_signature));
64 GITERR_CHECK_ALLOC(p);
a01acc47 65
c51880ee
VM
66 p->name = extract_trimmed(name, strlen(name));
67 p->email = extract_trimmed(email, strlen(email));
68
69 if (p->name == NULL || p->email == NULL ||
70 p->name[0] == '\0' || p->email[0] == '\0') {
8aedf1d5 71 git_signature_free(p);
72 return -1;
73 }
74
a01acc47 75 p->when.time = time;
76 p->when.offset = offset;
58519018 77
63396a39 78 *sig_out = p;
4aa7de15 79 return 0;
58519018
VM
80}
81
638c2ca4 82git_signature *git_signature_dup(const git_signature *sig)
58519018 83{
63396a39 84 git_signature *new;
4aa7de15 85 if (git_signature_new(&new, sig->name, sig->email, sig->when.time, sig->when.offset) < 0)
63396a39
MS
86 return NULL;
87 return new;
58519018
VM
88}
89
63396a39 90int git_signature_now(git_signature **sig_out, const char *name, const char *email)
9e9e6ae1
CMN
91{
92 time_t now;
53b7560b 93 time_t offset;
d03d309b 94 struct tm *utc_tm;
63396a39 95 git_signature *sig;
d03d309b 96 struct tm _utc;
9e9e6ae1 97
63396a39
MS
98 *sig_out = NULL;
99
d03d309b
CMN
100 /*
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.
107 */
14eb94ee 108 time(&now);
9ecf860d 109 utc_tm = p_gmtime_r(&now, &_utc);
d03d309b 110 utc_tm->tm_isdst = -1;
b97c169e 111 offset = (time_t)difftime(now, mktime(utc_tm));
9e9e6ae1 112 offset /= 60;
14eb94ee 113
4aa7de15
RB
114 if (git_signature_new(&sig, name, email, now, (int)offset) < 0)
115 return -1;
63396a39
MS
116
117 *sig_out = sig;
118
4aa7de15
RB
119 return 0;
120}
121
720d5472 122int git_signature__parse(git_signature *sig, const char **buffer_out,
7757be33 123 const char *buffer_end, const char *header, char ender)
58519018 124{
720d5472 125 const char *buffer = *buffer_out;
c51880ee 126 const char *email_start, *email_end;
58519018 127
de70aea6 128 memset(sig, 0, sizeof(git_signature));
58519018 129
c51880ee 130 if ((buffer_end = memchr(buffer, ender, buffer_end - buffer)) == NULL)
4aa7de15 131 return signature_error("no newline given");
58519018 132
8b2c913a
MS
133 if (header) {
134 const size_t header_len = strlen(header);
58519018 135
41051e3f 136 if (buffer + header_len >= buffer_end || memcmp(buffer, header, header_len) != 0)
4aa7de15 137 return signature_error("expected prefix doesn't match actual");
58519018 138
8b2c913a
MS
139 buffer += header_len;
140 }
58519018 141
41051e3f
VM
142 email_start = git__memrchr(buffer, '<', buffer_end - buffer);
143 email_end = git__memrchr(buffer, '>', buffer_end - buffer);
fbfc7580 144
c51880ee 145 if (!email_start || !email_end || email_end <= email_start)
4aa7de15 146 return signature_error("malformed e-mail");
076141a1 147
c51880ee 148 sig->name = extract_trimmed(buffer, email_start - buffer);
58519018 149
c51880ee
VM
150 email_start += 1;
151 sig->email = extract_trimmed(email_start, email_end - email_start);
58519018 152
c51880ee
VM
153 /* Do we even have a time at the end of the signature? */
154 if (email_end + 2 < buffer_end) {
155 const char *time_start = email_end + 2;
156 const char *time_end;
58519018 157
c51880ee
VM
158 if (git__strtol64(&sig->when.time, time_start, &time_end, 10) < 0)
159 return signature_error("invalid Unix timestamp");
c6e65aca 160
c51880ee
VM
161 /* no timezone at all */
162 if (time_end + 1 < buffer_end) {
163 int offset, hours, mins;
164 const char *tz_start, *tz_end;
165
166 tz_start = time_end + 1;
167
168 if ((tz_start[0] != '-' && tz_start[0] != '+') ||
169 git__strtol32(&offset, tz_start + 1, &tz_end, 10) < 0)
170 return signature_error("malformed timezone");
171
172 hours = offset / 100;
173 mins = offset % 100;
932d1baf 174
c51880ee
VM
175 /*
176 * only store timezone if it's not overflowing;
177 * see http://www.worldtimezone.com/faq.html
178 */
179 if (hours < 14 && mins < 59) {
180 sig->when.offset = (hours * 60) + mins;
181 if (tz_start[0] == '-')
182 sig->when.offset = -sig->when.offset;
183 }
184 }
42a1b5e1 185 }
13710f1e 186
c51880ee 187 *buffer_out = buffer_end + 1;
4aa7de15 188 return 0;
58519018
VM
189}
190
afeecf4f
VM
191void git_signature__writebuf(git_buf *buf, const char *header, const git_signature *sig)
192{
193 int offset, hours, mins;
194 char sign;
195
196 offset = sig->when.offset;
197 sign = (sig->when.offset < 0) ? '-' : '+';
198
199 if (offset < 0)
200 offset = -offset;
201
202 hours = offset / 60;
203 mins = offset % 60;
204
205 git_buf_printf(buf, "%s%s <%s> %u %c%02d%02d\n",
206 header ? header : "", sig->name, sig->email,
207 (unsigned)sig->when.time, sign, hours, mins);
208}
58519018 209