1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
2 /*
3  * anjuta
4  * Copyright (C) James Liggett 2007 <jrliggett@cox.net>
5  *
6  * anjuta is free software.
7  *
8  * You may redistribute it and/or modify it under the terms of the
9  * GNU General Public License, as published by the Free Software
10  * Foundation; either version 2 of the License, or (at your option)
11  * any later version.
12  *
13  * anjuta is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16  * See the GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with anjuta.  If not, write to:
20  * 	The Free Software Foundation, Inc.,
21  * 	51 Franklin Street, Fifth Floor
22  * 	Boston, MA  02110-1301, USA.
23  */
24 
25 #include "svn-command.h"
26 
27 struct _SvnCommandPriv
28 {
29 	svn_client_ctx_t *client_context;
30 	apr_pool_t *pool;
31 	GQueue *info_messages;
32 	GCond *dialog_finished_condition;
33 	GMutex *dialog_finished_lock;
34 	gboolean dialog_finished;
35 	gboolean cancelled;
36 };
37 
38 G_DEFINE_TYPE (SvnCommand, svn_command, ANJUTA_TYPE_ASYNC_COMMAND);
39 
40 
41 /* Auth functions */
42 /* In order to prevent deadlocking when Subversion prompts for something, we
43  * have to make sure that no GTK calls are made from the command threads by way
44  * of the authentication baton. To do this, the dialog code will be called from
45  * idle sources. */
46 
47 /* svn_auth_simple_prompt_func_cb argumements */
48 typedef struct
49 {
50 	svn_auth_cred_simple_t **cred;
51 	void *baton;
52 	gchar *realm;
53 	gchar *username;
54 	svn_boolean_t may_save;
55 	apr_pool_t *pool;
56 	svn_error_t *error;
57 } SimplePromptArgs;
58 
59 /* svn_auth_ssl_server_trust_prompt_func_cb arguements */
60 typedef struct
61 {
62 	svn_auth_cred_ssl_server_trust_t **cred;
63 	void *baton;
64 	gchar *realm;
65 	apr_uint32_t failures;
66 	svn_auth_ssl_server_cert_info_t *cert_info;
67 	svn_boolean_t may_save;
68 	apr_pool_t *pool;
69 	svn_error_t *error;
70 } SSLServerTrustArgs;
71 
72 
73 /* Idle destroy functions. The command threads should wait for the dialogs to
74  * finish before continuing. These functions signals the condition structure,
75  * allowing them to continue. These functions are executed on the main thread */
76 
77 static void
on_simple_prompt_finished(SimplePromptArgs * args)78 on_simple_prompt_finished (SimplePromptArgs *args)
79 {
80 	SvnCommand *self;
81 
82 	self = SVN_COMMAND (args->baton);
83 
84 	g_mutex_lock (self->priv->dialog_finished_lock);
85 
86 	self->priv->dialog_finished = TRUE;
87 	g_cond_signal (self->priv->dialog_finished_condition);
88 
89 	g_mutex_unlock (self->priv->dialog_finished_lock);
90 }
91 
92 static void
on_ssl_server_trust_prompt_finished(SSLServerTrustArgs * args)93 on_ssl_server_trust_prompt_finished (SSLServerTrustArgs *args)
94 {
95 	SvnCommand *self;
96 
97 	self = SVN_COMMAND (args->baton);
98 
99 	g_mutex_lock (self->priv->dialog_finished_lock);
100 
101 	self->priv->dialog_finished = TRUE;
102 	g_cond_signal (self->priv->dialog_finished_condition);
103 
104 	g_mutex_unlock (self->priv->dialog_finished_lock);
105 }
106 
107 static gboolean
simple_prompt(SimplePromptArgs * args)108 simple_prompt (SimplePromptArgs *args)
109 {
110 	GtkBuilder* bxml = gtk_builder_new ();
111 	GtkWidget* svn_user_auth;
112 	GtkWidget* auth_realm;
113 	GtkWidget* username_entry;
114 	GtkWidget* password_entry;
115 	GtkWidget* remember_pwd;
116 	svn_error_t *err = NULL;
117 	SvnCommand *svn_command;
118 	GError* error = NULL;
119 
120 	if (!gtk_builder_add_from_file (bxml, GLADE_FILE, &error))
121 	{
122 		g_warning ("Couldn't load builder file: %s", error->message);
123 		g_error_free (error);
124 	}
125 
126 	svn_user_auth = GTK_WIDGET (gtk_builder_get_object (bxml, "svn_user_auth"));
127 	auth_realm = GTK_WIDGET (gtk_builder_get_object (bxml, "auth_realm"));
128 	username_entry = GTK_WIDGET (gtk_builder_get_object (bxml, "username_entry"));
129 	password_entry = GTK_WIDGET (gtk_builder_get_object (bxml, "password_entry"));
130 	remember_pwd = GTK_WIDGET (gtk_builder_get_object (bxml, "remember_pwd"));
131 
132 	gtk_dialog_set_default_response (GTK_DIALOG (svn_user_auth), GTK_RESPONSE_OK);
133 
134 	if (args->realm)
135 		gtk_label_set_text (GTK_LABEL (auth_realm), args->realm);
136 	if (args->username)
137 	{
138 		gtk_entry_set_text (GTK_ENTRY (username_entry), args->username);
139 		gtk_widget_grab_focus (password_entry);
140 	}
141 	if (!args->may_save)
142 		gtk_widget_set_sensitive(remember_pwd, FALSE);
143 
144 	/* Then the dialog is prompted to user and when user clicks ok, the
145 	 * values entered, i.e username, password and remember password (true
146 	 * by default) should be used to initialized the memebers below. If the
147 	 * user cancels the dialog, I think we return an error struct
148 	 * appropriately initialized. -- naba
149 	 */
150 
151  	switch (gtk_dialog_run(GTK_DIALOG(svn_user_auth)))
152 	{
153 		case GTK_RESPONSE_OK:
154 		{
155 			*args->cred = apr_pcalloc (args->pool, sizeof(svn_auth_cred_simple_t));
156 			(*(args->cred))->may_save = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
157 															       (remember_pwd));
158 			(*(args->cred))->username = apr_pstrdup (args->pool,
159 								 	  gtk_entry_get_text(GTK_ENTRY(username_entry)));
160 			(*(args->cred))->password = apr_pstrdup (args->pool,
161 								 	  gtk_entry_get_text(GTK_ENTRY(password_entry)));
162 
163 			err = SVN_NO_ERROR;
164 			break;
165 		}
166 		default:
167 			err = svn_error_create (SVN_ERR_AUTHN_CREDS_UNAVAILABLE, NULL,
168 									_("Authentication canceled"));
169 
170 			break;
171 	}
172 	gtk_widget_destroy (svn_user_auth);
173 	args->error = err;
174 
175 	return FALSE;
176 }
177 
178 static gboolean
ssl_server_trust_prompt(SSLServerTrustArgs * args)179 ssl_server_trust_prompt (SSLServerTrustArgs *args)
180 {
181 	GtkBuilder* bxml = gtk_builder_new ();
182 	GtkWidget* svn_server_trust;
183 	GtkWidget* auth_realm;
184 	GtkWidget* server_info;
185 	GtkWidget* remember_check;
186 	svn_error_t *err = NULL;
187 	gchar* info;
188 	SvnCommand *svn_command;
189 	GError* error = NULL;
190 
191 	if (!gtk_builder_add_from_file (bxml, GLADE_FILE, &error))
192 	{
193 		g_warning ("Couldn't load builder file: %s", error->message);
194 		g_error_free (error);
195 	}
196 	svn_server_trust = GTK_WIDGET (gtk_builder_get_object (bxml, "svn_server_trust"));
197 	auth_realm = GTK_WIDGET (gtk_builder_get_object (bxml, "realm_label"));
198 	server_info = GTK_WIDGET (gtk_builder_get_object (bxml, "server_info_label"));
199 	remember_check = GTK_WIDGET (gtk_builder_get_object (bxml, "remember_check"));
200 
201 	if (args->realm)
202 		gtk_label_set_text (GTK_LABEL (auth_realm), args->realm);
203 
204 	info = g_strconcat(_("Hostname:"), args->cert_info->hostname, "\n",
205 					   _("Fingerprint:"), args->cert_info->fingerprint, "\n",
206 					   _("Valid from:"), args->cert_info->valid_from, "\n",
207 					   _("Valid until:"), args->cert_info->valid_until, "\n",
208 					   _("Issuer DN:"), args->cert_info->issuer_dname, "\n",
209 					   _("DER certificate:"), args->cert_info->ascii_cert, "\n",
210 					   NULL);
211 	gtk_label_set_text (GTK_LABEL (server_info), info);
212 
213 	if (!args->may_save)
214 		gtk_widget_set_sensitive(remember_check, FALSE);
215 
216 	gtk_dialog_set_default_response (GTK_DIALOG (svn_server_trust), GTK_RESPONSE_YES);
217 
218 
219 	switch (gtk_dialog_run(GTK_DIALOG(svn_server_trust)))
220 	{
221 		case GTK_RESPONSE_YES:
222 			*args->cred = apr_pcalloc (args->pool,
223 									   sizeof(*(args->cred)));
224 			(*(args->cred))->may_save = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON
225 															 	   (remember_check));
226 			err = SVN_NO_ERROR;
227 		/* TODO: Set bitmask for accepted_failures */
228 			break;
229 		default:
230 			err = svn_error_create (SVN_ERR_AUTHN_CREDS_UNAVAILABLE, NULL,
231 									_("Authentication canceled"));
232 			break;
233 	}
234 	gtk_widget_destroy (svn_server_trust);
235 	args->error = err;
236 
237 	return FALSE;
238 }
239 
240 /* User authentication prompts handlers */
241 static svn_error_t*
svn_auth_simple_prompt_func_cb(svn_auth_cred_simple_t ** cred,void * baton,const char * realm,const char * username,svn_boolean_t may_save,apr_pool_t * pool)242 svn_auth_simple_prompt_func_cb (svn_auth_cred_simple_t **cred, void *baton,
243 								const char *realm, const char *username,
244 								svn_boolean_t may_save, apr_pool_t *pool)
245 {
246 	SimplePromptArgs *args;
247 	SvnCommand *svn_command;
248 	svn_error_t *error;
249 
250 	args = g_new0 (SimplePromptArgs, 1);
251 	args->cred = cred;
252 	args->baton = baton;
253 	args->realm = g_strdup (realm);
254 	args->username = g_strdup (username);
255 	args->may_save = may_save;
256 	args->pool = pool;
257 
258 	svn_command = SVN_COMMAND (baton);
259 
260 	/* Wait for the dialog to finish */
261 	g_mutex_lock (svn_command->priv->dialog_finished_lock);
262 
263 	svn_command->priv->dialog_finished = FALSE;
264 
265 	g_idle_add_full (G_PRIORITY_HIGH_IDLE,
266 					 (GSourceFunc) simple_prompt, args,
267 	                 (GDestroyNotify) on_simple_prompt_finished);
268 
269 	while (!svn_command->priv->dialog_finished)
270 	{
271 		g_cond_wait (svn_command->priv->dialog_finished_condition,
272 		             svn_command->priv->dialog_finished_lock);
273 	}
274 
275 	error = args->error;
276 	g_free (args->realm);
277 	g_free (args->username);
278 	g_free (args);
279 
280 	g_mutex_unlock (svn_command->priv->dialog_finished_lock);
281 
282 	return error;
283 
284 }
285 
286 static svn_error_t*
svn_auth_ssl_server_trust_prompt_func_cb(svn_auth_cred_ssl_server_trust_t ** cred,void * baton,const char * realm,apr_uint32_t failures,const svn_auth_ssl_server_cert_info_t * cert_info,svn_boolean_t may_save,apr_pool_t * pool)287 svn_auth_ssl_server_trust_prompt_func_cb (svn_auth_cred_ssl_server_trust_t **cred,
288 										  void *baton, const char *realm,
289 										  apr_uint32_t failures,
290 										  const svn_auth_ssl_server_cert_info_t *cert_info,
291 										  svn_boolean_t may_save,
292 										  apr_pool_t *pool)
293 {
294 	SSLServerTrustArgs *args;
295 	SvnCommand *svn_command;
296 	svn_error_t *error;
297 
298 	args = g_new0 (SSLServerTrustArgs, 1);
299 	args->cred = cred;
300 	args->baton = baton;
301 	args->realm = g_strdup (realm);
302 	args->failures = failures;
303 	args->cert_info = g_memdup (cert_info,
304 								sizeof (svn_auth_ssl_server_cert_info_t));
305 	args->may_save = may_save;
306 	args->pool = pool;
307 
308 	svn_command = SVN_COMMAND (baton);
309 
310 	/* Wait for the dialog to finish */
311 	g_mutex_lock (svn_command->priv->dialog_finished_lock);
312 
313 	svn_command->priv->dialog_finished = FALSE;
314 
315 	g_idle_add_full (G_PRIORITY_HIGH_IDLE,
316 					 (GSourceFunc) ssl_server_trust_prompt, args,
317 	                 (GDestroyNotify) on_ssl_server_trust_prompt_finished);
318 
319 	while (!svn_command->priv->dialog_finished)
320 	{
321 		g_cond_wait (svn_command->priv->dialog_finished_condition,
322 		             svn_command->priv->dialog_finished_lock);
323 	}
324 
325 	error = args->error;
326 	g_free (args->realm);
327 	g_free (args->cert_info);
328 	g_free (args);
329 
330 	g_mutex_unlock (svn_command->priv->dialog_finished_lock);
331 
332 	return error;
333 }
334 
335 static svn_error_t*
svn_auth_ssl_client_cert_prompt_func_cb(svn_auth_cred_ssl_client_cert_t ** cred,void * baton,const char * realm,svn_boolean_t may_save,apr_pool_t * pool)336 svn_auth_ssl_client_cert_prompt_func_cb (svn_auth_cred_ssl_client_cert_t **cred,
337 										 void *baton, const char *realm,
338 										 svn_boolean_t may_save,
339 										 apr_pool_t *pool)
340 {
341 
342 	/* Ask for the file where client certificate of authenticity is.
343 	 * I think it is some sort of private key. */
344 	return SVN_NO_ERROR;
345 }
346 
347 static svn_error_t*
svn_auth_ssl_client_cert_pw_prompt_func_cb(svn_auth_cred_ssl_client_cert_pw_t ** cred,void * baton,const char * realm,svn_boolean_t may_save,apr_pool_t * pool)348 svn_auth_ssl_client_cert_pw_prompt_func_cb (svn_auth_cred_ssl_client_cert_pw_t **cred,
349 											void *baton, const char *realm,
350 											svn_boolean_t may_save,
351 											apr_pool_t *pool)
352 {
353 
354 	/* Prompt for password only. I think it is pass-phrase of the above key. */
355 	return SVN_NO_ERROR;;
356 }
357 
358 /* Notification callback to handle notifications from Subversion itself */
359 static void
on_svn_notify(gpointer baton,const svn_wc_notify_t * notify,apr_pool_t * pool)360 on_svn_notify (gpointer baton,
361 			   const svn_wc_notify_t *notify,
362 			   apr_pool_t *pool)
363 {
364 	SvnCommand *self;
365 	gchar *action_message;
366 	gchar *state_message;
367 
368 	self = SVN_COMMAND (baton);
369 	action_message = NULL;
370 	state_message = NULL;
371 
372 	switch (notify->action)
373 	{
374 		case svn_wc_notify_delete:
375 			action_message = g_strdup_printf (_("Deleted: %s"), notify->path);
376 			break;
377 		case svn_wc_notify_add:
378 			action_message = g_strdup_printf (_("Added: %s"), notify->path);
379 			break;
380 		case svn_wc_notify_revert:
381 			action_message = g_strdup_printf ("Reverted: %s", notify->path);
382 			break;
383 		case svn_wc_notify_failed_revert:
384 			action_message = g_strdup_printf ("Revert failed: %s",
385 											  notify->path);
386 			break;
387 		case svn_wc_notify_resolved:
388 			action_message = g_strdup_printf (_("Resolved: %s"), notify->path);
389 			break;
390 		case svn_wc_notify_update_delete:
391 			action_message = g_strdup_printf (_("Deleted: %s"), notify->path);
392 			break;
393 		case svn_wc_notify_update_update:
394 			action_message = g_strdup_printf (_("Updated: %s"), notify->path);
395 			break;
396 		case svn_wc_notify_update_add:
397 			action_message = g_strdup_printf (_("Added: %s"), notify->path);
398 			break;
399 		case svn_wc_notify_update_external:
400 			action_message = g_strdup_printf (_("Externally Updated: %s"),
401 									   notify->path);
402 			break;
403 		case svn_wc_notify_commit_modified:
404 			action_message = g_strdup_printf ("Commit Modified: %s",
405 											  notify->path);
406 			break;
407 		case svn_wc_notify_commit_added:
408 			action_message = g_strdup_printf ("Commit Added: %s", notify->path);
409 			break;
410 		case svn_wc_notify_commit_deleted:
411 			action_message = g_strdup_printf ("Commit Deleted: %s",
412 											  notify->path);
413 			break;
414 		case svn_wc_notify_commit_replaced:
415 			action_message = g_strdup_printf ("Commit Replaced: %s",
416 											  notify->path);
417 			break;
418 		case svn_wc_notify_copy:
419 			action_message = g_strdup_printf ("Created File: %s", notify->path);
420 			break;
421 		default:
422 			break;
423 	}
424 
425 	if (action_message)
426 	{
427 		svn_command_push_info (self, action_message);
428 		g_free (action_message);
429 	}
430 
431 	switch (notify->content_state)
432 	{
433 		case svn_wc_notify_state_changed:
434 			state_message = g_strdup_printf (_("Modified: %s"), notify->path);
435 			break;
436 		case svn_wc_notify_state_merged:
437 			state_message = g_strdup_printf (_("Merged: %s"), notify->path);
438 			break;
439 		case svn_wc_notify_state_conflicted:
440 			state_message = g_strdup_printf (_("Conflicted: %s"),
441 											 notify->path);
442 			break;
443 		case svn_wc_notify_state_missing:
444 			state_message = g_strdup_printf (_("Missing: %s"), notify->path);
445 			break;
446 		case svn_wc_notify_state_obstructed:
447 			state_message = g_strdup_printf (_("Obstructed: %s"), notify->path);
448 			break;
449 		default:
450 			break;
451 	}
452 
453 	if (state_message)
454 	{
455 		svn_command_push_info (self, state_message);
456 		g_free (state_message);
457 	}
458 }
459 
460 /* Operation cancelling callback */
461 static svn_error_t *
on_svn_cancel(gpointer cancel_baton)462 on_svn_cancel (gpointer cancel_baton)
463 {
464 	SvnCommand *self;
465 
466 	self = SVN_COMMAND (cancel_baton);
467 
468 	if (self->priv->cancelled)
469 		return svn_error_create (SVN_ERR_CANCELLED, NULL, NULL);
470 	else
471 		return SVN_NO_ERROR;
472 }
473 
474 static void
svn_command_init(SvnCommand * self)475 svn_command_init (SvnCommand *self)
476 {
477 	svn_auth_baton_t *auth_baton;
478 	apr_array_header_t *providers;
479 	svn_auth_provider_object_t *provider;
480 
481 	self->priv = g_new0 (SvnCommandPriv, 1);
482 
483 	self->priv->pool = svn_pool_create (NULL);
484 	svn_client_create_context (&self->priv->client_context, self->priv->pool);
485 	self->priv->client_context->notify_func2 = on_svn_notify;
486 	self->priv->client_context->notify_baton2 = self;
487 	self->priv->client_context->cancel_func = on_svn_cancel;
488 	self->priv->client_context->cancel_baton = self;
489 
490 	svn_config_get_config (&(self->priv->client_context)->config,
491 						   NULL, /* default dir */
492 						   self->priv->pool);
493 
494 	self->priv->info_messages = g_queue_new ();
495 	self->priv->dialog_finished_lock = g_mutex_new ();
496 	self->priv->dialog_finished_condition = g_cond_new ();
497 
498 	/* Fill in the auth baton callbacks */
499 	providers = apr_array_make (self->priv->pool, 1,
500 								sizeof (svn_auth_provider_object_t *));
501 
502 	/* Provider that authenticates username/password from ~/.subversion */
503 	provider = apr_pcalloc (self->priv->pool, sizeof(*provider));
504 	svn_client_get_simple_provider (&provider, self->priv->pool);
505 	*(svn_auth_provider_object_t **)apr_array_push (providers) = provider;
506 
507 	/* Provider that authenticates server trust from ~/.subversion */
508 	provider = apr_pcalloc (self->priv->pool, sizeof(*provider));
509 	svn_client_get_ssl_server_trust_file_provider (&provider, self->priv->pool);
510 	*(svn_auth_provider_object_t **)apr_array_push (providers) = provider;
511 
512 	/* Provider that authenticates client cert from ~/.subversion */
513 	provider = apr_pcalloc (self->priv->pool, sizeof(*provider));
514 	svn_client_get_ssl_client_cert_file_provider (&provider, self->priv->pool);
515 	*(svn_auth_provider_object_t **)apr_array_push (providers) = provider;
516 
517 	/* Provider that authenticates client cert password from ~/.subversion */
518 	provider = apr_pcalloc (self->priv->pool, sizeof(*provider));
519 	svn_client_get_ssl_client_cert_pw_file_provider (&provider,
520 													 self->priv->pool);
521 	*(svn_auth_provider_object_t **)apr_array_push (providers) = provider;
522 
523 	/* Provider that prompts for username/password */
524 	provider = apr_pcalloc (self->priv->pool, sizeof(*provider));
525 	svn_client_get_simple_prompt_provider(&provider,
526 										  svn_auth_simple_prompt_func_cb,
527 										  self, 3, self->priv->pool);
528 	*(svn_auth_provider_object_t **)apr_array_push (providers) = provider;
529 
530 	/* Provider that prompts for server trust */
531 	provider = apr_pcalloc (self->priv->pool, sizeof(*provider));
532 	svn_client_get_ssl_server_trust_prompt_provider (&provider,
533 													 svn_auth_ssl_server_trust_prompt_func_cb,
534 													 self,
535 													 self->priv->pool);
536 	*(svn_auth_provider_object_t **)apr_array_push (providers) = provider;
537 
538 	/* Provider that prompts for client certificate file */
539 	provider = apr_pcalloc (self->priv->pool, sizeof(*provider));
540 	svn_client_get_ssl_client_cert_prompt_provider (&provider,
541 													svn_auth_ssl_client_cert_prompt_func_cb,
542 													NULL, 3, self->priv->pool);
543 	*(svn_auth_provider_object_t **)apr_array_push (providers) = provider;
544 
545 	/* Provider that prompts for client certificate file password */
546 	provider = apr_pcalloc (self->priv->pool, sizeof(*provider));
547 	svn_client_get_ssl_client_cert_pw_prompt_provider (&provider,
548 													   svn_auth_ssl_client_cert_pw_prompt_func_cb,
549 													   NULL, 3,
550 													   self->priv->pool);
551 	*(svn_auth_provider_object_t **)apr_array_push (providers) = provider;
552 
553 	svn_auth_open (&auth_baton, providers, self->priv->pool);
554 	self->priv->client_context->auth_baton = auth_baton;
555 
556 }
557 
558 static void
svn_command_finalize(GObject * object)559 svn_command_finalize (GObject *object)
560 {
561 	SvnCommand *self;
562 	GList *current_message_line;
563 
564 	self = SVN_COMMAND (object);
565 
566 	svn_pool_clear (self->priv->pool);
567 	svn_pool_destroy (self->priv->pool);
568 
569 	current_message_line = self->priv->info_messages->head;
570 
571 	while (current_message_line)
572 	{
573 		g_free (current_message_line->data);
574 		current_message_line = g_list_next (current_message_line);
575 	}
576 
577 	g_mutex_free (self->priv->dialog_finished_lock);
578 	g_cond_free (self->priv->dialog_finished_condition);
579 
580 	g_queue_free (self->priv->info_messages);
581 	g_free (self->priv);
582 
583 	G_OBJECT_CLASS (svn_command_parent_class)->finalize (object);
584 }
585 
586 static void
svn_command_cancel(AnjutaCommand * command)587 svn_command_cancel (AnjutaCommand *command)
588 {
589 	SvnCommand *self;
590 
591 	self = SVN_COMMAND (command);
592 
593 	self->priv->cancelled = TRUE;
594 }
595 
596 static void
svn_command_class_init(SvnCommandClass * klass)597 svn_command_class_init (SvnCommandClass *klass)
598 {
599 	GObjectClass* object_class = G_OBJECT_CLASS (klass);
600 	AnjutaCommandClass *command_class = ANJUTA_COMMAND_CLASS (klass);
601 
602 	object_class->finalize = svn_command_finalize;
603 	command_class->cancel = svn_command_cancel;
604 }
605 
606 
607 void
svn_command_push_info(SvnCommand * self,const gchar * message)608 svn_command_push_info (SvnCommand *self, const gchar *message)
609 {
610 	anjuta_async_command_lock (ANJUTA_ASYNC_COMMAND (self));
611 	g_queue_push_tail (self->priv->info_messages, g_strdup (message));
612 	anjuta_async_command_unlock (ANJUTA_ASYNC_COMMAND (self));
613 
614 	anjuta_command_notify_data_arrived (ANJUTA_COMMAND (self));
615 }
616 
617 GQueue *
svn_command_get_info_queue(SvnCommand * self)618 svn_command_get_info_queue (SvnCommand *self)
619 {
620 	return self->priv->info_messages;
621 }
622 
623 void
svn_command_set_error(SvnCommand * self,svn_error_t * error)624 svn_command_set_error (SvnCommand *self, svn_error_t *error)
625 {
626 	GString *error_string;
627 	svn_error_t *current_error;
628 	gchar *error_c_string;
629 
630 	error_string = g_string_new ("");
631 	current_error = error;
632 
633 	while (current_error)
634 	{
635 		g_string_append (error_string, current_error->message);
636 
637 		if (current_error->child)
638 			g_string_append_c (error_string, '\n');
639 
640 		current_error = current_error->child;
641 	}
642 
643 	error_c_string = g_string_free (error_string, FALSE);
644 	anjuta_async_command_set_error_message (ANJUTA_COMMAND (self),
645 											error_c_string);
646 
647 	g_free (error_c_string);
648 }
649 
650 svn_client_ctx_t *
svn_command_get_client_context(SvnCommand * self)651 svn_command_get_client_context (SvnCommand *self)
652 {
653 	return self->priv->client_context;
654 }
655 
656 apr_pool_t *
svn_command_get_pool(SvnCommand * self)657 svn_command_get_pool (SvnCommand *self)
658 {
659 	return self->priv->pool;
660 }
661 
662 gchar *
svn_command_make_canonical_path(SvnCommand * self,const gchar * path)663 svn_command_make_canonical_path (SvnCommand *self, const gchar *path)
664 {
665 	const gchar *canonical_path;
666 
667 	canonical_path = NULL;
668 
669 	if (path)
670 		canonical_path = svn_path_canonicalize (path, self->priv->pool);
671 
672 	return g_strdup (canonical_path);
673 }
674 
675 svn_opt_revision_t *
svn_command_get_revision(const gchar * revision)676 svn_command_get_revision (const gchar *revision)
677 {
678 	svn_opt_revision_t* svn_revision;
679 
680 	svn_revision = g_new0 (svn_opt_revision_t, 1);
681 
682 	/* FIXME: Parse the revision string */
683 	svn_revision->kind = svn_opt_revision_head;
684 
685 	return svn_revision;
686 }
687 
688 GList *
svn_command_copy_path_list(GList * list)689 svn_command_copy_path_list (GList *list)
690 {
691 	GList *current_path;
692 	GList *new_list;
693 
694 	new_list = NULL;
695 	current_path = list;
696 
697 	while (current_path)
698 	{
699 		new_list = g_list_append (new_list, g_strdup (current_path->data));
700 		current_path = g_list_next (current_path);
701 	}
702 
703 	return new_list;
704 }
705 
706 void
svn_command_free_path_list(GList * list)707 svn_command_free_path_list (GList *list)
708 {
709 	GList *current_path;
710 
711 	current_path = list;
712 
713 	while (current_path)
714 	{
715 		g_free (current_path->data);
716 		current_path = g_list_next (current_path);
717 	}
718 
719 	g_list_free (list);
720 }
721