1 /*
2  * ggit-remote-callbacks.c
3  * This file is part of libgit2-glib
4  *
5  * Copyright (C) 2013 - Ignacio Casal Quinteiro
6  *
7  * libgit2-glib is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * libgit2-glib is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public License
18  * along with libgit2-glib. If not, see <http://www.gnu.org/licenses/>.
19  */
20 
21 #include "ggit-remote-callbacks.h"
22 #include "ggit-cred.h"
23 #include "ggit-transfer-progress.h"
24 #include "ggit-oid.h"
25 #include "ggit-enum-types.h"
26 
27 /**
28  * GgitRemoteCallbacks:
29  *
30  * Represents a git remote callbacks.
31  */
32 
33 typedef struct _GgitRemoteCallbacksPrivate
34 {
35 	git_remote_callbacks native;
36 } GgitRemoteCallbacksPrivate;
37 
38 enum
39 {
40 	PROGRESS,
41 	TRANSFER_PROGRESS,
42 	UPDATE_TIPS,
43 	COMPLETION,
44 	NUM_SIGNALS
45 };
46 
47 static guint signals[NUM_SIGNALS] = {0,};
48 
49 /**
50  * GgitRemoteCallbacksClass::credentials:
51  * @callbacks: a #GgitRemoteCallbacks.
52  * @url: the url.
53  * @username_from_url: (allow-none): the username extracted from the url.
54  * @allowed_types: the allowed credential types.
55  * @error: a #GError for error reporting.
56  *
57  * Returns: (transfer full) (nullable): a #GgitCred or %NULL in case of an error.
58  */
59 
G_DEFINE_TYPE_WITH_PRIVATE(GgitRemoteCallbacks,ggit_remote_callbacks,G_TYPE_OBJECT)60 G_DEFINE_TYPE_WITH_PRIVATE (GgitRemoteCallbacks, ggit_remote_callbacks, G_TYPE_OBJECT)
61 
62 static void
63 ggit_remote_callbacks_finalize (GObject *object)
64 {
65 	GgitRemoteCallbacks *callbacks = GGIT_REMOTE_CALLBACKS (object);
66 	GgitRemoteCallbacksPrivate *priv;
67 
68 	priv = ggit_remote_callbacks_get_instance_private (callbacks);
69 
70 	priv->native.payload = NULL;
71 
72 	G_OBJECT_CLASS (ggit_remote_callbacks_parent_class)->finalize (object);
73 }
74 
75 static void
ggit_remote_callbacks_class_init(GgitRemoteCallbacksClass * klass)76 ggit_remote_callbacks_class_init (GgitRemoteCallbacksClass *klass)
77 {
78 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
79 
80 	object_class->finalize = ggit_remote_callbacks_finalize;
81 
82 	signals[UPDATE_TIPS] =
83 		g_signal_new ("update-tips",
84 		              G_TYPE_FROM_CLASS (object_class),
85 		              G_SIGNAL_RUN_LAST,
86 		              G_STRUCT_OFFSET (GgitRemoteCallbacksClass, update_tips),
87 		              NULL, NULL,
88 		              NULL,
89 		              G_TYPE_NONE,
90 		              3,
91 		              G_TYPE_STRING,
92 		              GGIT_TYPE_OID,
93 		              GGIT_TYPE_OID);
94 
95 	signals[PROGRESS] =
96 		g_signal_new ("progress",
97 		              G_TYPE_FROM_CLASS (object_class),
98 		              G_SIGNAL_RUN_LAST,
99 		              G_STRUCT_OFFSET (GgitRemoteCallbacksClass, progress),
100 		              NULL, NULL,
101 		              NULL,
102 		              G_TYPE_NONE,
103 		              1,
104 		              G_TYPE_STRING);
105 
106 	signals[TRANSFER_PROGRESS] =
107 		g_signal_new ("transfer-progress",
108 		              G_TYPE_FROM_CLASS (object_class),
109 		              G_SIGNAL_RUN_LAST,
110 		              G_STRUCT_OFFSET (GgitRemoteCallbacksClass, transfer_progress),
111 		              NULL, NULL,
112 		              NULL,
113 		              G_TYPE_NONE,
114 		              1,
115 		              GGIT_TYPE_TRANSFER_PROGRESS);
116 
117 	signals[COMPLETION] =
118 		g_signal_new ("completion",
119 		              G_TYPE_FROM_CLASS (object_class),
120 		              G_SIGNAL_RUN_LAST,
121 		              G_STRUCT_OFFSET (GgitRemoteCallbacksClass, completion),
122 		              NULL, NULL,
123 		              NULL,
124 		              G_TYPE_NONE,
125 		              1,
126 		              GGIT_TYPE_REMOTE_COMPLETION_TYPE);
127 }
128 
129 static int
credentials_wrap(git_cred ** cred,const char * url,const char * username_from_url,unsigned int allowed_types,void * data)130 credentials_wrap (git_cred     **cred,
131                   const char    *url,
132                   const char    *username_from_url,
133                   unsigned int   allowed_types,
134                   void          *data)
135 {
136 	GgitRemoteCallbacks *callbacks = GGIT_REMOTE_CALLBACKS (data);
137 	GgitRemoteCallbacksClass *cls = GGIT_REMOTE_CALLBACKS_GET_CLASS (callbacks);
138 
139 	*cred = NULL;
140 
141 	if (cls->credentials != NULL)
142 	{
143 		GgitCred *mcred = NULL;
144 		GError *error = NULL;
145 
146 		mcred = cls->credentials (callbacks,
147 		                          url,
148 		                          username_from_url,
149 		                          allowed_types,
150 		                          &error);
151 
152 		if (mcred != NULL)
153 		{
154 			*cred = _ggit_native_release (mcred);
155 			g_object_unref (mcred);
156 
157 			return GIT_OK;
158 		}
159 		else
160 		{
161 			if (error)
162 			{
163 #if LIBGIT2_VER_MAJOR > 0 || (LIBGIT2_VER_MAJOR == 0 && LIBGIT2_VER_MINOR >= 28)
164 				git_error_set_str (GIT_ERROR, error->message);
165 #else
166 				giterr_set_str (GIT_ERROR, error->message);
167 #endif
168 				g_error_free (error);
169 
170 				return GIT_ERROR;
171 			}
172 			else
173 			{
174 				return GIT_PASSTHROUGH;
175 			}
176 		}
177 	}
178 	else
179 	{
180 		return GIT_OK;
181 	}
182 }
183 
184 
185 static int
progress_wrap(const char * str,int len,void * data)186 progress_wrap (const char *str,
187                int         len,
188                void       *data)
189 {
190 	GgitRemoteCallbacks *callbacks = GGIT_REMOTE_CALLBACKS (data);
191 	gchar *message;
192 
193 	message = g_strndup (str, len);
194 
195 	g_signal_emit (callbacks, signals[PROGRESS], 0, message);
196 
197 	g_free (message);
198 	return GIT_OK;
199 }
200 
201 static int
transfer_progress_wrap(const git_transfer_progress * stats,void * data)202 transfer_progress_wrap (const git_transfer_progress *stats,
203                         void                        *data)
204 {
205 	GgitRemoteCallbacks *callbacks = GGIT_REMOTE_CALLBACKS (data);
206 	GgitTransferProgress *p;
207 
208 	p = _ggit_transfer_progress_wrap (stats);
209 
210 	g_signal_emit (callbacks, signals[TRANSFER_PROGRESS], 0, p);
211 	ggit_transfer_progress_free (p);
212 
213 	return GIT_OK;
214 }
215 
216 static int
update_tips_wrap(const char * refname,const git_oid * a,const git_oid * b,void * data)217 update_tips_wrap (const char    *refname,
218                   const git_oid *a,
219                   const git_oid *b,
220                   void          *data)
221 {
222 	GgitRemoteCallbacks *callbacks = GGIT_REMOTE_CALLBACKS (data);
223 	GgitOId *na;
224 	GgitOId *nb;
225 
226 	na = _ggit_oid_wrap (a);
227 	nb = _ggit_oid_wrap (b);
228 
229 	g_signal_emit (callbacks, signals[UPDATE_TIPS], 0, refname, na, nb);
230 
231 	ggit_oid_free (na);
232 	ggit_oid_free (nb);
233 
234 	return GIT_OK;
235 }
236 
237 static int
completion_wrap(git_remote_completion_type type,void * data)238 completion_wrap (git_remote_completion_type  type,
239                  void                       *data)
240 {
241 	GgitRemoteCallbacks *callbacks = GGIT_REMOTE_CALLBACKS (data);
242 	GgitRemoteCompletionType rt = (GgitRemoteCompletionType)type;
243 
244 	g_signal_emit (callbacks, signals[COMPLETION], 0, rt);
245 
246 	return GIT_OK;
247 }
248 
249 static void
ggit_remote_callbacks_init(GgitRemoteCallbacks * callbacks)250 ggit_remote_callbacks_init (GgitRemoteCallbacks *callbacks)
251 {
252 	GgitRemoteCallbacksPrivate *priv;
253 
254 	git_remote_callbacks gcallbacks = GIT_REMOTE_CALLBACKS_INIT;
255 
256 	priv = ggit_remote_callbacks_get_instance_private (callbacks);
257 
258 	priv->native = gcallbacks;
259 
260 	priv->native.sideband_progress = progress_wrap;
261 	priv->native.transfer_progress = transfer_progress_wrap;
262 	priv->native.update_tips = update_tips_wrap;
263 	priv->native.completion = completion_wrap;
264 
265 	priv->native.credentials = credentials_wrap;
266 
267 	priv->native.payload = callbacks;
268 }
269 
270 git_remote_callbacks *
_ggit_remote_callbacks_get_native(GgitRemoteCallbacks * callbacks)271 _ggit_remote_callbacks_get_native (GgitRemoteCallbacks *callbacks)
272 {
273 	GgitRemoteCallbacksPrivate *priv;
274 
275 	priv = ggit_remote_callbacks_get_instance_private (callbacks);
276 
277 	return &priv->native;
278 }
279 
280 /* ex:set ts=8 noet: */
281